Re-implement router-act with browser-based fetch instrumentation#90959
Re-implement router-act with browser-based fetch instrumentation#90959acdlite wants to merge 1 commit into
Conversation
Failing test suitesCommit: cf731d8 | About building and testing Next.js
Expand output● instant-nav-panel › should show loading skeleton during SPA navigation after clicking Start
Expand output● app-dir - server-action-period-hash › should have same manifest between continuous two builds ● app-dir - server-action-period-hash › should have different manifest between two builds with period hash
Expand output● Image Component Default Tests › production mode › should load the images ● Image Component Default Tests › production mode › should preload priority images ● Image Component Default Tests › production mode › should work with preload prop ● Image Component Default Tests › production mode › should not pass through user-provided srcset (causing a flash) ● Image Component Default Tests › production mode › should update the image on src change ● Image Component Default Tests › production mode › should callback onLoadingComplete when image is fully loaded ● Image Component Default Tests › production mode › should callback native onLoad with sythetic event ● Image Component Default Tests › production mode › should callback native onError when error occurred while loading image ● Image Component Default Tests › production mode › should callback native onError even when error before hydration ● Image Component Default Tests › production mode › should work with image with blob src ● Image Component Default Tests › production mode › should work when using flexbox ● Image Component Default Tests › production mode › should work when using overrideSrc prop ● Image Component Default Tests › production mode › should work with sizes and automatically use responsive srcset ● Image Component Default Tests › production mode › should render no wrappers or sizers ● Image Component Default Tests › production mode › should lazy load with placeholder=blur ● Image Component Default Tests › production mode › should handle the styles prop appropriately ● Image Component Default Tests › production mode › should warn when legacy prop layout=fill ● Image Component Default Tests › production mode › should warn when legacy prop layout=responsive ● Image Component Default Tests › production mode › should render picture via getImageProps ● Image Component Default Tests › production mode › should not create an image folder in server/chunks ● Image Component Default Tests › production mode › should render as unoptimized with missing src prop ● Image Component Default Tests › production mode › should render as unoptimized with empty string src prop ● Image Component Default Tests › production mode › should correctly ignore prose styles ● Image Component Default Tests › production mode › should apply style inheritance for img elements but not wrapper elements ● Image Component Default Tests › production mode › should apply filter style after image loads ● Image Component Default Tests › production mode › should emit image for next/dynamic with non ssr case ● Image Component Default Tests › production mode › Fill-mode tests › should include a data-attribute on fill images ● Image Component Default Tests › production mode › Fill-mode tests › should include a data-attribute on fill images ● Image Component Default Tests › production mode › Fill-mode tests › should add position:absolute to fill images ● Image Component Default Tests › production mode › Fill-mode tests › should add position:absolute to fill images ● Image Component Default Tests › production mode › Fill-mode tests › should add 100% width and height to fill images ● Image Component Default Tests › production mode › Fill-mode tests › should add 100% width and height to fill images ● Image Component Default Tests › production mode › Fill-mode tests › should add position styles to fill images ● Image Component Default Tests › production mode › Fill-mode tests › should add position styles to fill images ● Image Component Default Tests › production mode › should correctly rotate image ● Image Component Default Tests › production mode › should have data url placeholder when enabled ● Image Component Default Tests › production mode › should remove data url placeholder after image loads ● Image Component Default Tests › production mode › should render correct objectFit when data url placeholder and fill ● Image Component Default Tests › production mode › should have blurry placeholder when enabled ● Image Component Default Tests › production mode › should remove blurry placeholder after image loads ● Image Component Default Tests › production mode › should render correct objectFit when blurDataURL and fill ● Image Component Default Tests › production mode › should be valid HTML ● Image Component Default Tests › production mode › should call callback ref cleanups when unmounting ● Image Component Default Tests › production mode › should build correct images-manifest.json |
485f506 to
789c0b2
Compare
7668fe9 to
514b57c
Compare
This comment was marked as spam.
This comment was marked as spam.
52d8fc6 to
90a4017
Compare
7889ced to
6cf2064
Compare
77af5e1 to
fb33082
Compare
The existing `router-act` test utility intercepts Next.js Router network requests using Playwright's `page.route()` API. This approach is flaky — Playwright's network interception has issues with streaming responses (`transfer-encoding: chunked`), redirect handling (307/308), and execution context destruction. The implementation requires many workarounds and retry loops. This commit introduces `@next/router-act`, a private workspace package that re-implements the same API using a browser-side fetch monkey-patch. The patch is installed via a `<RouterAct />` client component rendered in test fixture layouts. Using a React component (rather than `page.addInitScript` or similar) ensures the monkey-patch is installed after hydration, avoiding interference with the hydration process itself. This is viable because router-act is only used in test fixtures that we control — it's not designed for testing arbitrary Next.js apps. The browser runtime handles all scheduling internally — idle callbacks, waiting for in-flight requests, response matching, and resolve/block decisions run in a single `drainQueue()` call. The Playwright orchestrator communicates with the browser via `page.evaluate()` and is only responsible for config parsing, error formatting with stack traces, and final sequence assertions using jest utilities. All existing test files that use `router-act` have been migrated to the new implementation. The old Playwright-based implementation is preserved at `test/lib/deprecated-router-act.ts` because a handful of tests trigger hard navigations that destroy the browser JS context mid-act. Those tests will be reworked in a follow-up PR, after which the old implementation can be deleted.
fb33082 to
cf731d8
Compare
Summary
Re-implements the
router-acttest utility to use a browser-side fetch monkey-patch instead of Playwright'spage.route()API. The old approach was flaky due to issues with streaming responses, redirect handling, and execution context destruction.The new implementation (
@next/router-act) is a private workspace package with three files:setup.ts— browser-side runtime that intercepts fetch calls and runs the drain loopindex.ts— thin Playwright orchestrator for config parsing, error formatting, and assertionscomponent.tsx—<RouterAct />client component rendered in test fixture layoutsThe
<RouterAct />component installs the fetch patch viauseEffectso it doesn't interfere with hydration. This works because router-act is only used in test fixtures we control.All 30 test files have been migrated. The old implementation is preserved at
test/lib/deprecated-router-act.tsfor a handful of tests that trigger hard navigations destroying the browser context mid-act — those will be reworked in a follow-up PR.Test plan
NEXT_SKIP_ISOLATE=1 NEXT_TEST_MODE=start