Skip to content

Commit ecbbbb0

Browse files
bloveclaude
andauthored
fix(website): keep the post-promotion e2e run off the local fixture runtime (#983)
The deploy job re-runs the ordinary Website suite against production with only BASE_URL set, and #982 let that step run for the first time since the custom-target specs landed. Two failure clusters surfaced, both invisible to PR CI by construction because only the push-only deploy job runs the suite against a remote origin: - Twelve custom-runtime-target cases dial a fixture runtime on 127.0.0.1:4399 and the local example apps. Those exist only because the Playwright config starts them, and it starts nothing when BASE_URL is set, so every case failed with ECONNREFUSED after the site had already promoted. The config now ignores the fixture-driven specs whenever it starts no local server, including production-smoke mode. - The reduced-motion check held the runtime in its configuring state by refusing http://localhost:4300. Against the deployed site the frame loads from the production runtime origin, the handshake completes within half a second, and the loader is gone before the assertion. The route now matches the runtime frame by the session params Run mode stamps on every runtime URL, which holds the loader on screen locally and in production alike. Verified by running the full suite against https://threadplane.ai exactly as the deploy step does: 105 passed, 0 failed (was 104 passed, 13 failed). Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 7468f98 commit ecbbbb0

3 files changed

Lines changed: 84 additions & 21 deletions

File tree

apps/website/e2e/workspace-shell.spec.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,15 @@ test.describe('workspace shell', () => {
730730
page,
731731
}) => {
732732
await page.emulateMedia({ reducedMotion: 'reduce' });
733-
await page.route('http://localhost:4300/**', (request) => request.abort());
733+
// The loader is on screen only while the runtime is still being
734+
// configured, so refuse the runtime frame itself. Match it by the session
735+
// params Run mode stamps on every runtime URL rather than by host: against
736+
// the deployed site the frame loads from the production runtime origin,
737+
// and a `localhost:4300` route lets it reach ready before the assertion.
738+
await page.route(
739+
(url) => url.searchParams.has('cockpit_cap'),
740+
(route) => route.abort()
741+
);
734742
await page.setViewportSize({ width: 390, height: 844 });
735743
await page.goto(`${streamingDocsPath}?mode=run`);
736744
await page.getByRole('button', { name: 'Open navigation' }).click();

apps/website/playwright.config.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,43 @@ export const createWebsitePlaywrightConfig = (
2222
const reuseExistingServer =
2323
environment['PLAYWRIGHT_REUSE_EXISTING_SERVER'] === 'true';
2424

25+
// The public-copy gate crawls every sitemap route. Against a prebuilt
26+
// production server that is seconds; against `next dev` each route compiles
27+
// on demand, which is far too slow to belong in the ordinary suite. It runs
28+
// in production mode only, where its answers are the ones that matter.
29+
const modeIgnores: readonly string[] = productionSmoke
30+
? ['**/public-copy.spec.ts']
31+
: productionMode
32+
? [
33+
'**/platform-production-smoke.spec.ts',
34+
'**/custom-runtime-bfcache.spec.ts',
35+
]
36+
: bfcacheRuntimeTest
37+
? ['**/platform-production-smoke.spec.ts', '**/public-copy.spec.ts']
38+
: [
39+
'**/platform-production-smoke.spec.ts',
40+
'**/custom-runtime-bfcache.spec.ts',
41+
'**/public-copy.spec.ts',
42+
];
43+
// The custom-target specs drive the fixture runtime on 127.0.0.1:4399 and
44+
// the local example apps, which exist only because this config starts them.
45+
// A run against a deployed BASE_URL — the post-promotion verification, the
46+
// production smoke — starts nothing, so every case would dial a fixture that
47+
// is not there and fail with ECONNREFUSED after the site already promoted.
48+
const fixtureDrivenSpecs: readonly string[] = [
49+
'**/custom-runtime-targets.spec.ts',
50+
'**/custom-runtime-bfcache.spec.ts',
51+
];
52+
const testIgnore = shouldStartLocalServer
53+
? [...modeIgnores]
54+
: [...new Set([...modeIgnores, ...fixtureDrivenSpecs])];
55+
2556
return defineConfig({
2657
testDir: './e2e',
2758
testMatch: bfcacheRuntimeTest
2859
? '**/custom-runtime-bfcache.spec.ts'
2960
: undefined,
30-
// The public-copy gate crawls every sitemap route. Against a prebuilt
31-
// production server that is seconds; against `next dev` each route compiles
32-
// on demand, which is far too slow to belong in the ordinary suite. It runs
33-
// in production mode only, where its answers are the ones that matter.
34-
testIgnore: productionSmoke
35-
? '**/public-copy.spec.ts'
36-
: productionMode
37-
? [
38-
'**/platform-production-smoke.spec.ts',
39-
'**/custom-runtime-bfcache.spec.ts',
40-
]
41-
: bfcacheRuntimeTest
42-
? ['**/platform-production-smoke.spec.ts', '**/public-copy.spec.ts']
43-
: [
44-
'**/platform-production-smoke.spec.ts',
45-
'**/custom-runtime-bfcache.spec.ts',
46-
'**/public-copy.spec.ts',
47-
],
61+
testIgnore,
4862
fullyParallel: true,
4963
// Match the cockpit configs: 2 retries on CI to absorb transient Next.js
5064
// dev-server startup flake; 0 locally for fast feedback.

apps/website/src/playwright-config.spec.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,49 @@ describe('Website Playwright configuration', () => {
7575
expect(config.webServer).toBeUndefined();
7676
// The smoke job hits the deployed site, so it runs every spec except the
7777
// public-copy gate, which exists to check a locally built production
78-
// server before the code is deployed at all.
79-
expect(config.testIgnore).toBe('**/public-copy.spec.ts');
78+
// server before the code is deployed at all, and the custom-target specs,
79+
// which drive a fixture runtime this config did not start.
80+
expect(config.testIgnore).toEqual([
81+
'**/public-copy.spec.ts',
82+
'**/custom-runtime-targets.spec.ts',
83+
'**/custom-runtime-bfcache.spec.ts',
84+
]);
85+
});
86+
87+
it('skips the fixture-driven specs when BASE_URL points at a deployed site', () => {
88+
// The deploy job re-runs the ordinary suite against production with only
89+
// BASE_URL set. No local server starts in that mode, so the custom-target
90+
// specs would dial a fixture on 127.0.0.1:4399 that does not exist and fail
91+
// every case with ECONNREFUSED — after the site was already promoted.
92+
const config = createWebsitePlaywrightConfig({
93+
BASE_URL: 'https://threadplane.ai',
94+
});
95+
96+
expect(config.webServer).toBeUndefined();
97+
expect(config.use).toEqual(
98+
expect.objectContaining({ baseURL: 'https://threadplane.ai' })
99+
);
100+
expect(config.testIgnore).toEqual([
101+
'**/platform-production-smoke.spec.ts',
102+
'**/custom-runtime-bfcache.spec.ts',
103+
'**/public-copy.spec.ts',
104+
'**/custom-runtime-targets.spec.ts',
105+
]);
106+
});
107+
108+
it('holds the runtime frame by its session params rather than the local host', () => {
109+
// The reduced-motion check needs the runtime to stay in its connecting
110+
// state so the loader is on screen. Refusing `http://localhost:4300` only
111+
// does that against the local example app; against the deployed site the
112+
// frame loads from the production runtime origin, the handshake completes,
113+
// and the loader is gone before the assertion runs.
114+
const shell = readFileSync(
115+
resolve(__dirname, '../e2e/workspace-shell.spec.ts'),
116+
'utf8'
117+
);
118+
119+
expect(shell).not.toContain("page.route('http://localhost:4300/**'");
120+
expect(shell).toContain("url.searchParams.has('cockpit_cap')");
80121
});
81122

82123
it('starts Website, all migrated runtime apps under custom-runtime E2E, and the fixture', () => {

0 commit comments

Comments
 (0)