105 lines
3.7 KiB
TypeScript
105 lines
3.7 KiB
TypeScript
|
|
import { test, expect, tryLoadApp } from './utils/fixtures';
|
||
|
|
|
||
|
|
const EXPECTED_CASES = [
|
||
|
|
'baseline_modal_alone',
|
||
|
|
'baseline_fiber_alone',
|
||
|
|
'fiber_create_run_destroy_inside_modal',
|
||
|
|
'fiber_multi_swap_inside_modal',
|
||
|
|
'fiber_yield_across_modal_close',
|
||
|
|
'fiber_deep_yield_loop_inside_modal',
|
||
|
|
'modal_fiber_modal_sequence',
|
||
|
|
'nested_fibers_inside_modal',
|
||
|
|
];
|
||
|
|
|
||
|
|
function findSummary(logs: string[]) {
|
||
|
|
return logs.find((log) => log.includes('[COROUTINE_TEST] SUMMARY'));
|
||
|
|
}
|
||
|
|
|
||
|
|
test.describe('Nested Coroutine+Modal Tests', () => {
|
||
|
|
test('nested harness loads and reports its case inventory', async ({ page, testLogger }) => {
|
||
|
|
await page.goto('/standalone/coroutine-nested/nested_test.html');
|
||
|
|
const loaded = await tryLoadApp(page, 30000);
|
||
|
|
|
||
|
|
await expect
|
||
|
|
.poll(
|
||
|
|
() => testLogger.consoleLogs.filter((log) => log.includes('[COROUTINE_TEST] CASE ')).length,
|
||
|
|
{ timeout: 45000 }
|
||
|
|
)
|
||
|
|
.toBe(EXPECTED_CASES.length);
|
||
|
|
|
||
|
|
const caseLogs = testLogger.consoleLogs.filter((log) => log.includes('[COROUTINE_TEST] CASE '));
|
||
|
|
|
||
|
|
for (const caseName of EXPECTED_CASES) {
|
||
|
|
expect(
|
||
|
|
caseLogs.some((log) => log.includes(`[COROUTINE_TEST] CASE ${caseName}`)),
|
||
|
|
`case ${caseName} should appear in logs`
|
||
|
|
).toBe(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
await page.screenshot({ path: 'test-results/coroutine-nested-01-loaded.png', fullPage: true });
|
||
|
|
|
||
|
|
expect(loaded, 'Nested harness should load').toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('nested suite reports zero failures', async ({ page, testLogger }) => {
|
||
|
|
await page.goto('/standalone/coroutine-nested/nested_test.html');
|
||
|
|
const loaded = await tryLoadApp(page, 30000);
|
||
|
|
expect(loaded, 'Nested harness should load').toBe(true);
|
||
|
|
|
||
|
|
await expect
|
||
|
|
.poll(() => findSummary(testLogger.consoleLogs) ?? null, {
|
||
|
|
timeout: 45000,
|
||
|
|
message: 'Nested suite should emit a final summary line',
|
||
|
|
})
|
||
|
|
.not.toBeNull();
|
||
|
|
|
||
|
|
const summary = findSummary(testLogger.consoleLogs)!;
|
||
|
|
const match = summary.match(/total=(\d+)\s+passed=(\d+)\s+failed=(\d+)/);
|
||
|
|
expect(match, 'Nested summary should be parseable').not.toBeNull();
|
||
|
|
|
||
|
|
const total = Number(match![1]);
|
||
|
|
const passed = Number(match![2]);
|
||
|
|
const failed = Number(match![3]);
|
||
|
|
|
||
|
|
const failLogs = testLogger.consoleLogs.filter((log) => log.includes('[COROUTINE_TEST] FAIL '));
|
||
|
|
const passLogs = testLogger.consoleLogs.filter((log) => log.includes('[COROUTINE_TEST] PASS '));
|
||
|
|
|
||
|
|
expect(total).toBe(EXPECTED_CASES.length);
|
||
|
|
expect(passed).toBe(EXPECTED_CASES.length);
|
||
|
|
expect(failed).toBe(0);
|
||
|
|
expect(failLogs).toHaveLength(0);
|
||
|
|
expect(passLogs).toHaveLength(EXPECTED_CASES.length);
|
||
|
|
|
||
|
|
// Critical: catch the nested-asyncify crash
|
||
|
|
const indexOobErrors = testLogger.errors.filter((e) =>
|
||
|
|
e.toLowerCase().includes('index out of bounds')
|
||
|
|
);
|
||
|
|
expect(indexOobErrors, 'no index out of bounds errors').toHaveLength(0);
|
||
|
|
|
||
|
|
expect(
|
||
|
|
testLogger.errors.filter((error) => !error.includes('favicon')),
|
||
|
|
'no unexpected page errors'
|
||
|
|
).toHaveLength(0);
|
||
|
|
|
||
|
|
await page.screenshot({ path: 'test-results/coroutine-nested-02-summary.png', fullPage: true });
|
||
|
|
});
|
||
|
|
|
||
|
|
test('per-scenario status (diagnostic)', async ({ page, testLogger }) => {
|
||
|
|
await page.goto('/standalone/coroutine-nested/nested_test.html');
|
||
|
|
await tryLoadApp(page, 30000);
|
||
|
|
|
||
|
|
await expect
|
||
|
|
.poll(() => findSummary(testLogger.consoleLogs) ?? null, {
|
||
|
|
timeout: 45000,
|
||
|
|
})
|
||
|
|
.not.toBeNull();
|
||
|
|
|
||
|
|
// Use soft assertions so we see the full failure map instead of stopping at the first FAIL.
|
||
|
|
for (const name of EXPECTED_CASES) {
|
||
|
|
const passed = testLogger.consoleLogs.some((log) =>
|
||
|
|
log.includes(`[COROUTINE_TEST] PASS ${name}`)
|
||
|
|
);
|
||
|
|
expect.soft(passed, `scenario ${name} should PASS`).toBe(true);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|