/** * Test Error Formatting Utility * * Provides robust error formatting for test results to avoid "[object Object]" messages * Includes pattern matching for common Supabase/Postgres constraint violations */ /** * Error pattern matchers for common database constraint violations */ const ERROR_PATTERNS = [ { // RLS policy violations pattern: /new row violates row-level security policy for table "(\w+)"/i, format: (match: RegExpMatchArray) => `RLS Policy Violation: Cannot insert into table "${match[1]}". Check that RLS policies allow this operation and user has proper authentication.` }, { // NOT NULL constraint violations pattern: /null value in column "(\w+)" of relation "(\w+)" violates not-null constraint/i, format: (match: RegExpMatchArray) => `NOT NULL Constraint: Column "${match[1]}" in table "${match[2]}" cannot be null. Provide a value for this required field.` }, { // UNIQUE constraint violations pattern: /duplicate key value violates unique constraint "(\w+)"/i, format: (match: RegExpMatchArray) => `UNIQUE Constraint: Duplicate value violates constraint "${match[1]}". This value already exists in the database.` }, { // Foreign key violations pattern: /insert or update on table "(\w+)" violates foreign key constraint "(\w+)"/i, format: (match: RegExpMatchArray) => `Foreign Key Violation: Table "${match[1]}" references non-existent record (constraint: "${match[2]}"). Ensure the referenced entity exists first.` }, { // Foreign key violations (alternative format) pattern: /violates foreign key constraint/i, format: () => `Foreign Key Violation: Referenced record does not exist. Create the parent entity before creating this dependent entity.` }, { // Check constraint violations pattern: /new row for relation "(\w+)" violates check constraint "(\w+)"/i, format: (match: RegExpMatchArray) => `Check Constraint: Validation failed for table "${match[1]}" (constraint: "${match[2]}"). The provided value does not meet validation requirements.` }, { // Column does not exist pattern: /column "(\w+)" of relation "(\w+)" does not exist/i, format: (match: RegExpMatchArray) => `Schema Error: Column "${match[1]}" does not exist in table "${match[2]}". Check database schema or migration status.` }, { // Could not find column in schema cache pattern: /Could not find the '(\w+)' column of '(\w+)' in the schema cache/i, format: (match: RegExpMatchArray) => `Schema Cache Error: Column "${match[1]}" not found in table "${match[2]}". The schema may have changed - try refreshing the database connection.` }, { // Table does not exist pattern: /relation "(\w+)" does not exist/i, format: (match: RegExpMatchArray) => `Schema Error: Table "${match[1]}" does not exist. Run migrations or check database schema.` }, { // Permission denied pattern: /permission denied for (?:table|relation) "?(\w+)"?/i, format: (match: RegExpMatchArray) => `Permission Denied: Insufficient permissions to access table "${match[1]}". Check RLS policies and user roles.` }, { // Rate limit errors pattern: /Rate limit exceeded\. Please wait (\d+) seconds?/i, format: (match: RegExpMatchArray) => `Rate Limited: Too many requests. Wait ${match[1]} seconds before retrying.` }, { // Rate limit errors (alternative format) pattern: /Too many submissions in a short time\. Please wait (\d+) seconds?/i, format: (match: RegExpMatchArray) => `Rate Limited: Submission throttled. Wait ${match[1]} seconds before submitting again.` } ]; /** * Format error for test result display * Handles Error objects, PostgresError objects, and plain objects * * @param error - Any error value thrown in a test * @returns Formatted, human-readable error string */ export function formatTestError(error: unknown): string { let errorMessage = ''; // Extract base error message if (error instanceof Error) { errorMessage = error.message; } else if (typeof error === 'object' && error !== null) { const err = error as any; // Try common error message properties if (err.message && typeof err.message === 'string') { errorMessage = err.message; // Include additional Supabase error details if present if (err.details && typeof err.details === 'string') { errorMessage += ` | Details: ${err.details}`; } if (err.hint && typeof err.hint === 'string') { errorMessage += ` | Hint: ${err.hint}`; } if (err.code && typeof err.code === 'string') { errorMessage += ` | Code: ${err.code}`; } } // Some errors nest the actual error in an 'error' property else if (err.error) { return formatTestError(err.error); } // Some APIs use 'msg' instead of 'message' else if (err.msg && typeof err.msg === 'string') { errorMessage = err.msg; } // Last resort: stringify the entire object else { try { const stringified = JSON.stringify(error, null, 2); errorMessage = stringified.length > 500 ? stringified.substring(0, 500) + '... (truncated)' : stringified; } catch { // JSON.stringify can fail on circular references errorMessage = String(error); } } } else { // Primitive values (strings, numbers, etc.) errorMessage = String(error); } // Apply pattern matching to format known constraint violations for (const { pattern, format } of ERROR_PATTERNS) { const match = errorMessage.match(pattern); if (match) { return format(match); } } // Return original message if no patterns matched return errorMessage; }