Improve error formatting in tests

- Replace [object Object] errors with readable messages by using robust error formatting across test suites
- Introduce formatTestError helper and apply it in all catch blocks and error throws
- Update approvalPipelineTests and related suites to utilize improved error extraction for better debugging
This commit is contained in:
gpt-engineer-app[bot]
2025-11-10 17:03:25 +00:00
parent e0001961bf
commit ade1810a01
6 changed files with 92 additions and 27 deletions

View File

@@ -0,0 +1,59 @@
/**
* Test Error Formatting Utility
*
* Provides robust error formatting for test results to avoid "[object Object]" messages
*/
/**
* 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 {
// Standard Error objects
if (error instanceof Error) {
return error.message;
}
// Object-like errors (PostgresError, custom error objects, etc.)
if (typeof error === 'object' && error !== null) {
const err = error as any;
// Try common error message properties
if (err.message && typeof err.message === 'string') {
return err.message;
}
// Some errors nest the actual error in an 'error' property
if (err.error) {
return formatTestError(err.error);
}
// Some APIs use 'msg' instead of 'message'
if (err.msg && typeof err.msg === 'string') {
return err.msg;
}
// Supabase errors might have details
if (err.details && typeof err.details === 'string') {
return `${err.message || 'Error'}: ${err.details}`;
}
// Last resort: stringify the entire object
try {
const stringified = JSON.stringify(error, null, 2);
// If it's too long, truncate it
return stringified.length > 500
? stringified.substring(0, 500) + '... (truncated)'
: stringified;
} catch {
// JSON.stringify can fail on circular references
return String(error);
}
}
// Primitive values (strings, numbers, etc.)
return String(error);
}

View File

@@ -8,7 +8,8 @@
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { TestDataTracker } from '../TestDataTracker'; import { TestDataTracker } from '../TestDataTracker';
import { import { formatTestError } from '../formatTestError';
import {
submitParkCreation, submitParkCreation,
submitRideCreation, submitRideCreation,
submitManufacturerCreation, submitManufacturerCreation,
@@ -18,6 +19,9 @@ import {
submitRideModelCreation submitRideModelCreation
} from '@/lib/entitySubmissionHelpers'; } from '@/lib/entitySubmissionHelpers';
// Re-export formatTestError for use in test suites
export { formatTestError } from '../formatTestError';
// ============================================ // ============================================
// AUTHENTICATION // AUTHENTICATION
// ============================================ // ============================================
@@ -416,7 +420,7 @@ export async function approveSubmission(
const duration = performance.now() - startTime; const duration = performance.now() - startTime;
return { return {
success: false, success: false,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
duration, duration,
}; };
} }

View File

@@ -7,5 +7,6 @@
export { IntegrationTestRunner } from './testRunner'; export { IntegrationTestRunner } from './testRunner';
export { allTestSuites } from './suites'; export { allTestSuites } from './suites';
export { formatResultsAsMarkdown, formatSingleTestAsMarkdown } from './formatters'; export { formatResultsAsMarkdown, formatSingleTestAsMarkdown } from './formatters';
export { formatTestError } from './formatTestError';
export type { TestResult, Test, TestSuite } from './testRunner'; export type { TestResult, Test, TestSuite } from './testRunner';

View File

@@ -36,6 +36,7 @@ import {
verifySubmissionStatus, verifySubmissionStatus,
createParkDirectly, createParkDirectly,
createRideDirectly, createRideDirectly,
formatTestError,
} from '../helpers/approvalTestHelpers'; } from '../helpers/approvalTestHelpers';
// ============================================ // ============================================
@@ -132,7 +133,7 @@ const parkCreationTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -220,7 +221,7 @@ const rideCreationTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -298,7 +299,7 @@ const companyCreationTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -387,7 +388,7 @@ const rideModelCreationTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -497,7 +498,7 @@ const rideManufacturerCompositeTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -624,7 +625,7 @@ const partialApprovalTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -714,7 +715,7 @@ const idempotencyTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -809,7 +810,7 @@ const parkUpdateTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -897,7 +898,7 @@ const rideUpdateTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -999,7 +1000,7 @@ const rideManufacturerDesignerCompositeTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1097,7 +1098,7 @@ const parkOperatorOwnerCompositeTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1188,7 +1189,7 @@ const lockConflictTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1280,7 +1281,7 @@ const bannedUserTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1373,7 +1374,7 @@ const multipleEditChainTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1478,7 +1479,7 @@ const versionSnapshotIntegrityTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1557,7 +1558,7 @@ const parkPhotoGalleryTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1639,7 +1640,7 @@ const ridePhotoGalleryTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1753,7 +1754,7 @@ const invalidTempRefTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
@@ -1852,7 +1853,7 @@ const concurrentEditTest: Test = {
suite: 'Approval Pipeline', suite: 'Approval Pipeline',
status: 'fail', status: 'fail',
duration: Date.now() - startTime, duration: Date.now() - startTime,
error: error instanceof Error ? error.message : String(error), error: formatTestError(error),
stack: error instanceof Error ? error.stack : undefined, stack: error instanceof Error ? error.stack : undefined,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };

View File

@@ -126,7 +126,7 @@ export const performanceTestSuite: TestSuite = {
.select('id') .select('id')
.single(); .single();
if (parkError) throw parkError; if (parkError) throw new Error(`Park creation failed: ${parkError.message}`);
parkId = park.id; parkId = park.id;
tracker.track('parks', parkId); tracker.track('parks', parkId);
@@ -214,7 +214,7 @@ export const performanceTestSuite: TestSuite = {
const modDuration = Date.now() - modStart; const modDuration = Date.now() - modStart;
if (modError) throw modError; if (modError) throw new Error(`Moderator check failed: ${modError.message}`);
// Test is_user_banned function performance // Test is_user_banned function performance
const banStart = Date.now(); const banStart = Date.now();
@@ -225,7 +225,7 @@ export const performanceTestSuite: TestSuite = {
const banDuration = Date.now() - banStart; const banDuration = Date.now() - banStart;
if (banError) throw banError; if (banError) throw new Error(`Ban check failed: ${banError.message}`);
// Performance threshold: 200ms for simple functions // Performance threshold: 200ms for simple functions
const threshold = 200; const threshold = 200;

View File

@@ -38,7 +38,7 @@ export const unitConversionTestSuite: TestSuite = {
.select('id') .select('id')
.single(); .single();
if (parkError) throw parkError; if (parkError) throw new Error(`Park creation failed: ${parkError.message}`);
parkId = park.id; parkId = park.id;
tracker.track('parks', parkId); tracker.track('parks', parkId);
@@ -145,7 +145,7 @@ export const unitConversionTestSuite: TestSuite = {
.select('id') .select('id')
.single(); .single();
if (parkError) throw parkError; if (parkError) throw new Error(`Park creation failed: ${parkError.message}`);
parkId = park.id; parkId = park.id;
tracker.track('parks', parkId); tracker.track('parks', parkId);
@@ -167,7 +167,7 @@ export const unitConversionTestSuite: TestSuite = {
.select('id') .select('id')
.single(); .single();
if (rideError) throw rideError; if (rideError) throw new Error(`Ride creation failed: ${rideError.message}`);
rideId = ride.id; rideId = ride.id;
tracker.track('rides', rideId); tracker.track('rides', rideId);