From ca0362f53edda92a35c80f8eebb7b854a24b4608 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 8 Nov 2025 01:59:21 +0000 Subject: [PATCH] Error Handling & Edge Cases Test Suite cgen-9d6eda8f5a484a5d824f9c7b7baa98b9 --- tests/error-handling.test.ts | 446 +++++++++++++++++++++++++++++++++++ 1 file changed, 446 insertions(+) create mode 100644 tests/error-handling.test.ts diff --git a/tests/error-handling.test.ts b/tests/error-handling.test.ts new file mode 100644 index 00000000..3f2f1092 --- /dev/null +++ b/tests/error-handling.test.ts @@ -0,0 +1,446 @@ +/** + * Error Handling & Edge Cases Test Suite + * Phase 3: Testing & Validation + */ + +interface TestResult { + name: string; + passed: boolean; + expectedStatus: number; + actualStatus: number; + message: string; +} + +const results: TestResult[] = []; +const BASE_URL = "http://localhost:5173"; + +const test = ( + name: string, + passed: boolean, + expectedStatus: number, + actualStatus: number, + message: string +) => { + results.push({ name, passed, expectedStatus, actualStatus, message }); + const symbol = passed ? "āœ“" : "āœ—"; + console.log( + `${symbol} ${name.padEnd(50)} | Expected: ${expectedStatus}, Got: ${actualStatus}` + ); +}; + +async function runErrorTests() { + console.log("šŸ›”ļø Error Handling & Edge Cases Test Suite\n"); + + // ERROR CATEGORY 1: Validation Errors + console.log("\nšŸ”“ Category 1: Input Validation Errors"); + console.log("=".repeat(70)); + + // Test missing required fields + let res = await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ username: "testuser" }), // Missing user_id + }); + test( + "Create creator - missing user_id", + res.status === 400, + 400, + res.status, + "Should require user_id" + ); + + res = await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ user_id: "user123" }), // Missing username + }); + test( + "Create creator - missing username", + res.status === 400, + 400, + res.status, + "Should require username" + ); + + res = await fetch(`${BASE_URL}/api/opportunities`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ user_id: "user123" }), // Missing title + }); + test( + "Create opportunity - missing title", + res.status === 400, + 400, + res.status, + "Should require title" + ); + + res = await fetch(`${BASE_URL}/api/applications`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ user_id: "user123" }), // Missing opportunity_id + }); + test( + "Submit application - missing opportunity_id", + res.status === 400, + 400, + res.status, + "Should require opportunity_id" + ); + + // ERROR CATEGORY 2: Not Found Errors + console.log("\nšŸ”“ Category 2: Resource Not Found Errors"); + console.log("=".repeat(70)); + + res = await fetch(`${BASE_URL}/api/creators/nonexistent_user_12345`); + test( + "Get creator - non-existent username", + res.status === 404, + 404, + res.status, + "Should return 404 for non-existent creator" + ); + + res = await fetch(`${BASE_URL}/api/opportunities/fake-opp-id-99999`); + test( + "Get opportunity - non-existent ID", + res.status === 404, + 404, + res.status, + "Should return 404 for non-existent opportunity" + ); + + res = await fetch(`${BASE_URL}/api/applications?user_id=nonexistent-user`); + test( + "Get applications - non-existent creator", + res.status === 404, + 404, + res.status, + "Should return 404 when creator doesn't exist" + ); + + // ERROR CATEGORY 3: Authorization/Ownership Errors + console.log("\nšŸ”“ Category 3: Authorization & Ownership Errors"); + console.log("=".repeat(70)); + + // Create a fake creator for testing + const testCreator = { + id: `error-test-${Date.now()}`, + username: `error_test_${Date.now()}`, + }; + + let creatorRes = await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: testCreator.id, + username: testCreator.username, + bio: "Test creator", + experience_level: "junior", + }), + }); + + if (creatorRes.ok) { + // Try to update someone else's profile + res = await fetch(`${BASE_URL}/api/creators/fake-id`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + bio: "Hacked bio", + }), + }); + test( + "Update creator - invalid creator ID", + res.status === 500 || res.status === 404, + 404, + res.status, + "Should reject invalid creator ID" + ); + } + + // ERROR CATEGORY 4: Duplicate/Conflict Errors + console.log("\nšŸ”“ Category 4: Duplicate & Conflict Errors"); + console.log("=".repeat(70)); + + // Create duplicate creator + const dupUsername = `dup_test_${Date.now()}`; + await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: `dup-user-1`, + username: dupUsername, + experience_level: "junior", + }), + }); + + res = await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: `dup-user-2`, + username: dupUsername, // Same username + experience_level: "junior", + }), + }); + test( + "Create creator - duplicate username", + res.status === 400, + 400, + res.status, + "Should prevent duplicate usernames" + ); + + // Test duplicate application (create opportunity first) + const oppCreatorId = `opp-creator-${Date.now()}`; + const oppCreatorUsername = `opp_creator_${Date.now()}`; + const appCreatorId = `app-creator-${Date.now()}`; + const appCreatorUsername = `app_creator_${Date.now()}`; + + let oppRes = await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: oppCreatorId, + username: oppCreatorUsername, + experience_level: "senior", + }), + }); + + let appCreatorRes = await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: appCreatorId, + username: appCreatorUsername, + experience_level: "junior", + }), + }); + + if (oppRes.ok && appCreatorRes.ok) { + // Create opportunity + let createOppRes = await fetch(`${BASE_URL}/api/opportunities`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: oppCreatorId, + title: "Test Opportunity", + description: "Test", + job_type: "full-time", + }), + }); + + if (createOppRes.ok) { + const oppData = await createOppRes.json(); + const oppId = oppData.id; + + // First application + await fetch(`${BASE_URL}/api/applications`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: appCreatorId, + opportunity_id: oppId, + cover_letter: "First application", + }), + }); + + // Duplicate application + res = await fetch(`${BASE_URL}/api/applications`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: appCreatorId, + opportunity_id: oppId, + cover_letter: "Duplicate application", + }), + }); + test( + "Apply to opportunity - duplicate application", + res.status === 400, + 400, + res.status, + "Should prevent duplicate applications" + ); + } + } + + // ERROR CATEGORY 5: Missing Required Relationships + console.log("\nšŸ”“ Category 5: Missing Required Relationships"); + console.log("=".repeat(70)); + + res = await fetch(`${BASE_URL}/api/opportunities`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: `nonexistent-creator-user`, + title: "Opportunity", + description: "Test", + }), + }); + test( + "Create opportunity - creator doesn't exist", + res.status === 404, + 404, + res.status, + "Should require existing creator profile" + ); + + res = await fetch(`${BASE_URL}/api/applications`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: `nonexistent-app-creator`, + opportunity_id: "fake-opp-id", + }), + }); + test( + "Submit application - creator doesn't exist", + res.status === 404, + 404, + res.status, + "Should require existing creator profile" + ); + + // ERROR CATEGORY 6: Invalid Query Parameters + console.log("\nšŸ”“ Category 6: Invalid Query Parameters"); + console.log("=".repeat(70)); + + res = await fetch(`${BASE_URL}/api/creators?page=invalid&limit=20`); + const pageData = await res.json(); + test( + "Get creators - invalid page parameter", + res.ok, // Should still work with default pagination + 200, + res.status, + "Should handle invalid page gracefully" + ); + + res = await fetch(`${BASE_URL}/api/opportunities?limit=999999`); + test( + "Get opportunities - limit too large", + res.ok, // Should cap the limit + 200, + res.status, + "Should cap maximum limit" + ); + + res = await fetch(`${BASE_URL}/api/creators?arm=invalid_arm`); + const armData = await res.json(); + test( + "Get creators - invalid arm filter", + res.ok && Array.isArray(armData.data), + 200, + res.status, + "Should return empty results or handle gracefully" + ); + + // ERROR CATEGORY 7: Empty/Null Values + console.log("\nšŸ”“ Category 7: Empty & Null Values"); + console.log("=".repeat(70)); + + res = await fetch(`${BASE_URL}/api/creators`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: "", + username: "", + }), + }); + test( + "Create creator - empty user_id", + res.status === 400, + 400, + res.status, + "Should reject empty user_id" + ); + + res = await fetch(`${BASE_URL}/api/creators?search=`); + test( + "Search creators - empty search string", + res.ok, + 200, + res.status, + "Should handle empty search gracefully" + ); + + // ERROR CATEGORY 8: Missing DevConnect Parameters + console.log("\nšŸ”“ Category 8: DevConnect Linking Errors"); + console.log("=".repeat(70)); + + res = await fetch(`${BASE_URL}/api/devconnect/link`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ devconnect_username: "user" }), // Missing user_id + }); + test( + "Link DevConnect - missing user_id", + res.status === 400, + 400, + res.status, + "Should require user_id" + ); + + res = await fetch(`${BASE_URL}/api/devconnect/link`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ user_id: "user123" }), // Missing devconnect_username + }); + test( + "Link DevConnect - missing devconnect_username", + res.status === 400, + 400, + res.status, + "Should require devconnect_username" + ); + + res = await fetch(`${BASE_URL}/api/devconnect/link`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + user_id: "nonexistent-user", + devconnect_username: "dev_user", + }), + }); + test( + "Link DevConnect - creator doesn't exist", + res.status === 404, + 404, + res.status, + "Should require existing creator profile" + ); + + // Summary + console.log("\n" + "=".repeat(70)); + const passed = results.filter((r) => r.passed).length; + const failed = results.filter((r) => !r.passed).length; + + console.log(`\nšŸ“Š Error Handling Test Summary:`); + console.log(` āœ“ Passed: ${passed}`); + console.log(` āœ— Failed: ${failed}`); + console.log(` Total: ${results.length}`); + + if (failed > 0) { + console.log("\nāŒ Failed Tests:"); + results + .filter((r) => !r.passed) + .forEach((r) => { + console.log(` - ${r.name}`); + console.log(` Expected ${r.expectedStatus}, got ${r.actualStatus}: ${r.message}`); + }); + } else { + console.log("\nāœ… All error handling tests passed!"); + } + + console.log("\n" + "=".repeat(70)); + return { passed, failed, total: results.length }; +} + +runErrorTests() + .then((summary) => { + process.exit(summary.failed > 0 ? 1 : 0); + }) + .catch((error) => { + console.error("Test suite failed:", error); + process.exit(1); + });