mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
The idea here is that we waste a bunch of CPU setting up each test suite by spawning an entirely new Chrome process, but playwright can share the same browser across many tests. Tests are still isolated at the browser level, just not at the OS process level. Hoping to see some performance improvement in e2e tests. Compare to: https://github.com/vercel/next.js/pull/95617 Somewhat unscientific (single sample) results: ``` Comparing the head-commit build-and-test runs — PR #95589 run [28981702219 ](https://github.com/vercel/next.js/actions/runs/28981702219)vs PR #95617 run [28981686692](https://github.com/vercel/next.js/actions/runs/28981686692). Both ran 101 jobs and both succeeded. ┌─────────────────────────┬────────────────┬───────────────────────┬───────────────────┐ │ Metric │ #95617 control │ #95589 shared browser │ Delta │ ├─────────────────────────┼────────────────┼───────────────────────┼───────────────────┤ │ Raw wall-time sum │ 616.2 min │ 571.2 min │ −45.0 min (−7.3%) │ ├─────────────────────────┼────────────────┼───────────────────────┼───────────────────┤ │ Billable (ceil per job) │ 658 min │ 617 min │ −41 min (−6.2%) │ └─────────────────────────┴────────────────┴───────────────────────┴───────────────────┘ The shared-browser experiment is cheaper, and the savings land almost exactly where you'd expect — the browser-driven test suites — while non-browser jobs (rust, lint, unit, windows) are flat within noise: ┌─────────────────────────────────┬─────────┬────────┬───────┐ │ Job category │ control │ shared │ delta │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ test prod │ 130.7 │ 110.5 │ −20.2 │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ cache components dev │ 51.5 │ 42.9 │ −8.7 │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ turbopack dev │ 75.1 │ 69.5 │ −5.5 │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ turbopack production │ 86.3 │ 81.1 │ −5.2 │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ test dev │ 110.4 │ 105.5 │ −4.9 │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ cache components prod │ 48.7 │ 49.0 │ +0.3 │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ firefox and safari │ 5.3 │ 7.3 │ +2.0 │ ├─────────────────────────────────┼─────────┼────────┼───────┤ │ flake-detection jobs (combined) │ ~15 │ ~21 │ +~6 │ └─────────────────────────────────┴─────────┴────────┴───────┘ Takeaways: - Net savings of ~41 billable minutes per run (~6%), concentrated in the Chromium-driven test prod/dev, turbopack, and cache components suites — consistent with reusing one browser process instead of spawning per-suite. - The small regressions are in firefox and safari and the "new/changed tests for flakes" jobs (+~8 min combined). Worth a glance, though they may just be run-to-run variance. Caveat: this is a single run per PR, so there's real variance run-to-run. That said, the fact that the deltas track the browser-heavy jobs specifically — and not the Rust/lint/unit jobs — is a good signal the effect is genuine rather than noise. If you want a firmer number, re-running each PR 2–3× and averaging would tighten it up. ```
36 lines
1.5 KiB
TypeScript
36 lines
1.5 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
|
|
const describeHeaded = process.env.HEADLESS ? describe.skip : describe
|
|
|
|
describeHeaded('fetch-abort-on-refresh', () => {
|
|
const { next } = nextTestSetup({
|
|
files: __dirname,
|
|
})
|
|
|
|
it('should not show abort error in global error boundary when restoring from bfcache', async () => {
|
|
// This test ensures that when restoring a page from the browser bfcache that was pending RSC data,
|
|
// that the abort does not propagate to a user's error boundary.
|
|
// Requires headed mode, as bfcache is not available in headless mode
|
|
// (`describeHeaded` skips this suite when the HEADLESS env var is set).
|
|
const browser = await next.browser('/')
|
|
|
|
await browser.elementById('trigger-navigation').click()
|
|
|
|
await browser.waitForElementByCss('#root-2')
|
|
|
|
// Go back to trigger bfcache restoration
|
|
// we overwrite the typical waitUntil: 'load' option here as the event is never being triggered if we hit the bfcache
|
|
await browser.back({ waitUntil: 'commit' })
|
|
|
|
// Check that we're back on the slow page (the page that was first redirected to, before the MPA, not the error boundary)
|
|
// We use element checks instead of eval() because eval() triggers waitForLoadState which times out with bfcache
|
|
const hasSlowPage = await browser.hasElementByCss('#slow-page')
|
|
const hasGlobalError = await browser.hasElementByCss(
|
|
'h2:has-text("Something went wrong!")'
|
|
)
|
|
|
|
expect(hasSlowPage).toBe(true)
|
|
expect(hasGlobalError).toBe(false)
|
|
})
|
|
})
|