Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions test/contract/p4-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ const LATEST_RESULT_REQUIRED = [
'targetUrl',
'failedStepIndex',
'failureKind',
'verdict',
'executionStatus',
'summary',
] as const;
// `targetUrlSource` (D1) is OPTIONAL — present on backends that shipped the D1
Expand All @@ -109,6 +111,15 @@ const FAILURE_KINDS = new Set<unknown>([
'unknown',
null,
]);
const VERDICTS = new Set<unknown>(['passed', 'failed', 'blocked', 'cancelled', 'unknown', null]);
const EXECUTION_STATUSES = new Set<unknown>([
'queued',
'running',
'completed',
'cancelled',
'error',
'unknown',
]);

function expectKeysMatch(value: Record<string, unknown>, allowed: Set<string>, label: string) {
for (const key of Object.keys(value)) {
Expand Down Expand Up @@ -178,17 +189,6 @@ function validateTestStepList(value: unknown, label = 'TestStepList'): void {
}
}

function validateResultSummary(value: unknown, label: string): void {
expect(value, label).toBeTypeOf('object');
expect(value, label).not.toBeNull();
const obj = value as Record<string, unknown>;
expectKeysMatch(obj, new Set(['passed', 'failed', 'skipped']), label);
for (const k of ['passed', 'failed', 'skipped']) {
expect(typeof obj[k], `${label}.${k}`).toBe('number');
expect((obj[k] as number) >= 0, `${label}.${k} >= 0`).toBe(true);
}
}

function validateLatestResult(value: unknown, label = 'LatestResult'): void {
expect(value, `${label}: must be an object`).toBeTypeOf('object');
expect(value, `${label}: must not be null`).not.toBeNull();
Expand All @@ -215,7 +215,9 @@ function validateLatestResult(value: unknown, label = 'LatestResult'): void {
expect((obj.failedStepIndex as number) >= 1, `${label}.failedStepIndex >= 1`).toBe(true);
}
expect(FAILURE_KINDS.has(obj.failureKind), `${label}.failureKind`).toBe(true);
validateResultSummary(obj.summary, `${label}.summary`);
expect(VERDICTS.has(obj.verdict), `${label}.verdict`).toBe(true);
expect(EXECUTION_STATUSES.has(obj.executionStatus), `${label}.executionStatus`).toBe(true);
expect(typeof obj.summary, `${label}.summary`).toBe('string');
}

describe('P4 schema contract — fixtures match the OpenAPI shapes', () => {
Expand Down
16 changes: 12 additions & 4 deletions test/mock-backend/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ export const latestResultRunningFixture = {
targetUrl: FIXTURE_TARGET_URL,
failedStepIndex: null,
failureKind: null,
summary: { passed: 0, failed: 0, skipped: 0 },
verdict: null,
executionStatus: 'running' as const,
summary: 'Run is still in progress.',
};

export const latestResultPassedFixture = {
Expand All @@ -260,7 +262,9 @@ export const latestResultPassedFixture = {
targetUrlSource: 'run' as const,
failedStepIndex: null,
failureKind: null,
summary: { passed: 8, failed: 0, skipped: 0 },
verdict: 'passed' as const,
executionStatus: 'completed' as const,
summary: 'Passed all 8 steps.',
};

export const latestResultFailedFixture = {
Expand All @@ -277,7 +281,9 @@ export const latestResultFailedFixture = {
targetUrlSource: 'run' as const,
failedStepIndex: 5,
failureKind: 'assertion' as const,
summary: { passed: 4, failed: 1, skipped: 0 },
verdict: 'failed' as const,
executionStatus: 'completed' as const,
summary: 'Failed (assertion) on step 5: expected cart badge to show 1 item, but it was empty.',
};

export const failureContextFixture = {
Expand Down Expand Up @@ -351,7 +357,9 @@ export const failureContextNoAnalysisFixture = {
targetUrl: 'https://staging.example.com/',
failedStepIndex: 2,
failureKind: 'unknown' as const,
summary: { passed: 1, failed: 1, skipped: 0 },
verdict: 'failed' as const,
executionStatus: 'completed' as const,
summary: 'Failed with no detailed analysis available.',
},
steps: [],
code: {
Expand Down
Loading