diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c28457b1986..826fd12ef7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,6 +87,12 @@ jobs: if: ${{ inputs.run_frontend }} runs-on: ${{ matrix.os }} strategy: + # An OS-specific failure should not cancel the other two legs: with the + # default fail-fast the surviving jobs report "The operation was + # canceled" and the run no longer says whether the failure reproduces + # off that OS — exactly the evidence needed to tell a runner flake from + # a real break. Every other multi-leg matrix here already opts out. + fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] include: diff --git a/frontend/TESTING.md b/frontend/TESTING.md index 7372fc4b29d..9e4412d7e70 100644 --- a/frontend/TESTING.md +++ b/frontend/TESTING.md @@ -47,6 +47,7 @@ For repo-wide testing philosophy (TDD, characterization tests, "every test must | Coverage | `@vitest/coverage-v8` | | Test setup | `src/test-zone-setup.ts` wraps `it`/`test` in an Angular ProxyZone (Vitest does not provide one and Angular's `fakeAsync` requires it) | | Globals | `globals: true` in `vitest.config.ts`, so `describe / it / expect / vi / beforeEach` come from the runtime — no per-file imports | +| Timeouts | 30s per test and per hook, raised from the 5s/10s Vitest defaults because macOS CI runners stall for seconds at a time (#6073) | `src/main.test.ts` is intentionally a near-empty `export {}`. The `unit-test` builder uses `buildTarget`'s `main` to seed the bundle graph; if it pointed at the real `main.ts`, every component declared in `AppModule` would be type-checked for every spec, surfacing template errors for components no active spec touches. Keeping `main.test.ts` empty narrows the graph to what each spec actually imports. diff --git a/frontend/vitest.browser.config.ts b/frontend/vitest.browser.config.ts index 3fe2c410390..b67414aa392 100644 --- a/frontend/vitest.browser.config.ts +++ b/frontend/vitest.browser.config.ts @@ -64,6 +64,11 @@ export default defineConfig({ // browser-mode the runtime has neither, so we install the `buffer` npm // package as a shim). setupFiles: ["src/browser-buffer-polyfill.ts", "src/test-zone-setup.ts"], + // Same runner-stall headroom as the jsdom config (vitest.config.ts): + // driving a real Chromium through playwright is strictly slower than + // jsdom, so these specs need at least as much slack. See #6073. + testTimeout: 30_000, + hookTimeout: 30_000, browser: { enabled: true, provider: playwright(), diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts index 9cb2f82f88c..dbfc9a78295 100644 --- a/frontend/vitest.config.ts +++ b/frontend/vitest.config.ts @@ -34,6 +34,16 @@ export default defineConfig({ // which Angular's `fakeAsync` requires. Karma+Jasmine installed this // implicitly; the @angular/build:unit-test path doesn't. setupFiles: ["src/test-zone-setup.ts"], + // Vitest defaults (5s per test, 10s per hook) are too tight for the + // macOS runners, which stall for seconds at a time under load: the same + // spec file that takes 240ms on ubuntu-latest has been observed taking + // 11.7s on macos-latest in the same commit's matrix. The stall lands on + // whichever test happens to be running, so raising the ceiling is the + // only fix that isn't whack-a-mole — three different specs have gone + // red this way. A test that legitimately needs >30s is broken, and the + // job's own timeout still bounds a true hang. See apache/texera#6073. + testTimeout: 30_000, + hookTimeout: 30_000, // Per-spec exclusions live in `angular.json` (the unit-test builder // applies them at the discovery stage, before Vitest's own filter, // which is what the Vitest team recommends — see the Vite warning