This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new 90d0404f1b fix(ci, test, frontend): stop the frontend matrix
manufacturing false reds (#7623)
90d0404f1b is described below
commit 90d0404f1bbcef98edd7c62d13f35b5287663c64
Author: Xinyuan Lin <[email protected]>
AuthorDate: Sat Aug 29 06:03:26 2026 +0000
fix(ci, test, frontend): stop the frontend matrix manufacturing false reds
(#7623)
### What changes were proposed in this PR?
**Rescoped after #7717 landed.** That PR merged the jsdom half of this
one — `testTimeout: 20000` / `hookTimeout: 30000` in
`frontend/vitest.config.ts` — which is what put this branch in conflict.
This branch had 30s/30s, so the merge would have reverted a value
another author had just landed. Resolved by taking main's verbatim:
**`vitest.config.ts` now has no diff against main at all.**
What remains is the part of #6073 that #7717 does not cover, plus a
timeout the job was still missing:
| Change | File | Rationale |
| --- | --- | --- |
| `fail-fast: false` | `.github/workflows/build.yml` | one flaky OS leg
cancels the other two, destroying the evidence that says flake vs. real
break |
| `timeout-minutes: 45` | `.github/workflows/build.yml` | the job had no
cap, so a true hang ran to GitHub's implicit 6h, holding one of the 50
concurrent macOS jobs the whole `apache` org shares |
| `testTimeout` 15s → 30s | `frontend/vitest.browser.config.ts` | 15s is
now the tightest per-test ceiling in the job, on its slower runtime |
| Timeouts row, scoped per config | `frontend/TESTING.md` | documents
#7717's values and this one's, separately |
#### `fail-fast: false` — the flake destroys its own evidence
The `build / frontend` macOS leg goes red on a different unit test every
few days: always a timeout, never an assertion, always green on rerun.
It is a runner stall landing on whichever test happens to be executing —
same commit, same matrix, run
[31665399757](https://github.com/apache/texera/actions/runs/31665399757/job/94338769943):
| Measure | ubuntu-latest | macos-latest |
| --- | --- | --- |
| the spec file that failed (10 tests) | 240 ms | **11 727 ms** |
| suite wall clock | 89.85 s | 252.88 s |
| runner size | 4 cores / 16 GB | 3 cores / 7 GB |
Today the default fail-fast then cancels ubuntu and windows, so the run
no longer says whether the failure reproduces off macOS — exactly the
fact needed to classify it.
```
Before: macOS stalls -> that test fails -> ubuntu + windows cancelled
After: macOS stalls -> that leg fails alone; a real break still fails all
three
```
The opt-out set becomes `frontend`, `platform`, `platform-integration`,
`agent-service`, `infra`. `amber-integration` (2 OS legs) and `pyamber`
(3 Python versions) are multi-leg without it; left alone to keep this PR
to the frontend job.
#### `timeout-minutes: 45` — based on green legs, not typical ones
This is a correction to what this PR carried through the last review
round. The earlier `timeout-minutes: 30` was based on run `31869822969`
alone (legs at 8.6 / 10.0 / 10.7 min) and the comment called 30 "~3x the
slowest". Pulling every frontend leg from the last eight `Required
Checks` runs says otherwise:
| Leg | green legs observed | worst green |
| --- | --- | --- |
| ubuntu-latest | 8.4 – 9.6 min | 9.6 min |
| windows-latest | 7.1 – 11.4 min | 11.4 min |
| macos-latest | 10.0 – 21.1 min | **21.1 min** |
The 21.1-minute leg is run
[32219352076](https://github.com/apache/texera/actions/runs/32219352076)
— this branch's own merge push, **passing**. #7713 corroborates the
range independently at 16m52s. So 30 was 1.4x the worst observed *green*
leg, not 3x, and could have ended a run that was merely slow — the same
false red `fail-fast: false` is here to stop manufacturing. 45 is ~2x
that leg and still cuts a true hang from 6h.
The per-step breakdown also relocates the variance: on macOS it is the
Angular production build, not the tests.
| Run | macOS leg | `Prod build` | `Run frontend unit tests` |
| --- | --- | --- | --- |
| `32219432444` | 12.4 min | 4.5 min | 4.4 min |
| `32117825499` | (failed) | 7.8 min | — |
| `32219352076` | 21.1 min | **11.1 min** | 5.3 min |
#### Browser mode — 15s is now the tightest ceiling in the job
`gui:test-browser` runs on all three OSes, on the same runners. Vitest
keys its defaults off `browser.enabled` — read out of the pinned
`[email protected]`, `dist/chunks/coverage.DM_a_rWm.js:538-539`:
```js
resolved.testTimeout ??= resolved.browser.enabled ? 15e3 : 5e3;
resolved.hookTimeout ??= resolved.browser.enabled ? 3e4 : 1e4;
```
So after #7717 the per-test ceilings are jsdom 20s vs. browser 15s — the
tighter limit sitting on the *slower* runtime, since driving real
Chromium through playwright costs more than jsdom. Raised to 30s.
`hookTimeout` stays absent: `browser.enabled` already resolves it to the
30s `vitest.config.ts` sets explicitly.
**Left out:** capping `maxWorkers` on the macOS leg to cut memory
pressure — it trades wall clock for stability and can't be measured from
a non-macOS box.
### Any related issues, documentation, discussions?
Closes #6073
`#6073` lists two follow-ups: raise the Vitest timeout, and set
`fail-fast: false` on the frontend matrix. #7717 delivered the first for
jsdom; this PR delivers it for browser mode and delivers the second.
### How was this PR tested?
No production code is touched — the changes are CI config, a test-runner
config, and a doc row.
| Check | Result |
| --- | --- |
| conflict resolution | `git diff origin/main --
frontend/vitest.config.ts` is empty, so #7717's merged values stand
unmodified |
| `build.yml` parses | `yaml.safe_load` →
`jobs.frontend['timeout-minutes'] === 45`, `strategy['fail-fast'] ===
false`; the same pass over every job confirms the opt-out set is exactly
the five named above |
| runner cost | `macos-latest` is a standard runner and this repo is
public, so [GitHub's runner
policy](https://docs.github.com/en/actions/reference/runners/github-hosted-runners)
puts the usage at free and unlimited — the 10x multiplier is a
billed-minutes rate for private repos. `orgs/apache` reports the
`enterprise` plan, whose
[limit](https://docs.github.com/en/actions/reference/limits) is 500
concurrent jobs but only 50 concurrent macOS, org-wide — that is the
bound the comment names instead |
| leg durations | measured from the Actions jobs API across the last
eight `Required Checks` runs and per-step for the three macOS legs — not
read off the run summary |
| browser-mode defaults | read out of the pinned `[email protected]` in
`node_modules`, not from the docs |
| formatting | `prettier --check frontend/vitest.browser.config.ts`
clean. `TESTING.md` is outside `format:ci`'s `src/**` glob and already
fails `prettier --check` on main, so it is left as-is |
The flake itself can't be reproduced on demand — that is what a runner
stall is. What this PR asserts is verifiable: the browser leg's per-test
ceiling doubles (15s → 30s), a failing leg no longer cancels its
siblings, and a genuine hang ends at 45 minutes instead of 6 hours
without threatening a green 21-minute macOS leg.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 5)
---
.github/workflows/build.yml | 18 ++++++++++++++++++
frontend/TESTING.md | 1 +
frontend/vitest.browser.config.ts | 10 ++++++++++
3 files changed, 29 insertions(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6a2a6cff2c..35e921a3d2 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -86,7 +86,25 @@ jobs:
frontend:
if: ${{ inputs.run_frontend }}
runs-on: ${{ matrix.os }}
+ # Only the "Install dependency" step below is bounded, so a spec that
+ # truly hangs would otherwise run to GitHub's implicit 6h cap, holding one
+ # of the 50 concurrent macOS jobs the whole `apache` org shares for that
+ # window. The timeout is based on observed *green* legs rather than a
+ # typical one, because the macOS leg swings hard: 21.1 minutes at its
+ # slowest while still passing, and the variance sits in "Prod build"
+ # (4.5-11.1 min there) more than in the tests (4.4-5.3 min). 45 is ~2x
+ # that worst green leg, so it bounds a runaway without turning a merely
+ # slow macOS runner into a false red — which is the same failure this
+ # job's `fail-fast: false` is here to stop manufacturing.
+ timeout-minutes: 45
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. `platform`, `platform-integration`, `agent-service` and
+ # `infra` opt out for the same reason.
+ fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
diff --git a/frontend/TESTING.md b/frontend/TESTING.md
index 7372fc4b29..7adea47e4b 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 | Raised over Vitest's defaults because macOS CI
runners stall for seconds at a time (#6073, #7713). jsdom: 20s per test / 30s
per hook (`vitest.config.ts`, defaults 5s/10s). Browser mode: 30s per test
(`vitest.browser.config.ts`), hooks left at the 30s default that
`browser.enabled` already resolves — its per-test default is 15s |
`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 3fe2c41039..9500247000 100644
--- a/frontend/vitest.browser.config.ts
+++ b/frontend/vitest.browser.config.ts
@@ -64,6 +64,16 @@ 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"],
+ // Browser mode resolves larger defaults than jsdom off `browser.enabled`
+ // (15s per test, 30s per hook), but since #7717 raised the jsdom config to
+ // 20s per test, 15s is the tightest per-test ceiling left in the frontend
+ // job — on the slower of the two runtimes, since driving a real Chromium
+ // through playwright costs more than jsdom. Both legs run on the same
+ // macOS runners, whose stalls are what the jsdom raise was for, so this
+ // one gets at least as much headroom. `hookTimeout` is left alone — its
+ // browser-mode default is already the 30s the jsdom config sets. See
+ // apache/texera#6073.
+ testTimeout: 30_000,
browser: {
enabled: true,
provider: playwright(),