import { test, expect, tryLoadApp } from './utils/fixtures'; import { shotPath } from './utils/element-tracker'; const EXPECTED_CASES = [ 'first_entry_runs_once', 'yield_resume_preserves_state', 'deep_stack_preserved_across_yield', 'nested_coroutine_call_and_resume', 'nested_parent_yield_preserves_suspend', 'async_wait_loop_stays_suspended', 'async_nested_resume_from_child_tool', 'root_bounce_continue_after_root', 'completion_returns_control_without_exit', 'resume_after_finish_does_not_reenter', 'interleaving_multiple_coroutines', 'stress_many_round_trips', 'transfer_values_round_trip', ]; function findSummary(logs: string[]) { return logs.find((log) => log.includes('[COROUTINE_TEST] SUMMARY')); } test.describe('Coroutine Harness Tests', () => { test('coroutine harness loads and reports its case inventory', async ({ page, testLogger }) => { await page.goto('/standalone/coroutine/coroutine_test.html'); const loaded = await tryLoadApp(page, 30000); await expect.poll( () => testLogger.consoleLogs.filter((log) => log.includes('[COROUTINE_TEST] CASE ')).length, { timeout: 15000 } ).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}`))).toBe(true); } await page.screenshot({ path: shotPath(page, 'coroutine-01-loaded.png'), fullPage: true }); expect(loaded, 'Coroutine harness should load').toBe(true); }); test('coroutine stress suite reports zero failures', async ({ page, testLogger }) => { await page.goto('/standalone/coroutine/coroutine_test.html'); const loaded = await tryLoadApp(page, 30000); expect(loaded, 'Coroutine harness should load').toBe(true); await expect.poll( () => findSummary(testLogger.consoleLogs) ?? null, { timeout: 20000, message: 'Coroutine 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, 'Coroutine 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); expect(testLogger.errors.filter((error) => !error.includes('favicon'))).toHaveLength(0); await page.screenshot({ path: shotPath(page, 'coroutine-02-summary.png'), fullPage: true }); }); });