diff --git a/packages/backend/tests/helpers/uuid-validation.test.ts b/packages/backend/tests/helpers/uuid-validation.test.ts new file mode 100644 index 0000000..5f7c6e7 --- /dev/null +++ b/packages/backend/tests/helpers/uuid-validation.test.ts @@ -0,0 +1,24 @@ +/** + * UUID Validation Helper - Unit Tests + * Verifies the UUID validation helper utility exports correctly + */ + +import { describe, expect, it } from 'vitest'; +import { testInvalidUuidRejection } from './uuid-validation.js'; + +describe('UUID Validation Helper', () => { + it('should export testInvalidUuidRejection function', () => { + expect(testInvalidUuidRejection).toBeDefined(); + expect(typeof testInvalidUuidRejection).toBe('function'); + }); + + it('should have correct function signature (2 required params, 1 optional)', () => { + // Function.length returns number of required parameters + expect(testInvalidUuidRejection.length).toBe(2); + }); + + it('should be importable from helpers directory', () => { + // This test passing means the import worked correctly + expect(testInvalidUuidRejection).toBeTruthy(); + }); +}); diff --git a/packages/backend/tests/helpers/uuid-validation.ts b/packages/backend/tests/helpers/uuid-validation.ts new file mode 100644 index 0000000..e991ea5 --- /dev/null +++ b/packages/backend/tests/helpers/uuid-validation.ts @@ -0,0 +1,63 @@ +import type { FastifyInstance } from 'fastify'; +import { describe, expect, it } from 'vitest'; + +/** + * Shared test helper for UUID validation in API endpoints + * + * Creates a test suite that verifies: + * - Invalid UUID format returns 400 with VALIDATION_ERROR + * - Missing UUID returns 404 (route not found) + * - Valid UUID v4 is accepted (returns 200 or 404 if entity doesn't exist) + * + * @param app - Fastify application instance + * @param endpoint - API endpoint URL with :id placeholder (e.g., '/api/v1/projects/:id') + * @param method - HTTP method to test (default: 'GET') + * + * @example + * ```typescript + * import { testInvalidUuidRejection } from '../../helpers/uuid-validation'; + * + * describe('GET /api/v1/projects/:projectId', () => { + * testInvalidUuidRejection(app, '/api/v1/projects/:id', 'GET'); + * + * // Endpoint-specific tests continue... + * }); + * ``` + */ +export function testInvalidUuidRejection( + app: FastifyInstance, + endpoint: string, + method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET', +) { + describe('UUID validation', () => { + it('should return 400 for invalid UUID format', async () => { + const response = await app.inject({ + method, + url: endpoint.replace(':id', 'invalid-uuid'), + }); + + expect(response.statusCode).toBe(400); + expect(response.json().error.code).toBe('VALIDATION_ERROR'); + }); + + it('should return 400 for missing UUID', async () => { + const response = await app.inject({ + method, + url: endpoint.replace(':id', ''), + }); + + expect(response.statusCode).toBe(404); // Route not found + }); + + it('should accept valid UUID v4', async () => { + const validUuid = '550e8400-e29b-41d4-a716-446655440000'; + const response = await app.inject({ + method, + url: endpoint.replace(':id', validUuid), + }); + + // Should not fail on UUID validation (may 404 if entity doesn't exist) + expect([200, 404]).toContain(response.statusCode); + }); + }); +}