diff --git a/docs/assets/rsc-runtime-workbench/fidelity-ledger.md b/docs/assets/rsc-runtime-workbench/fidelity-ledger.md index 0233513a8..5cbb70533 100644 --- a/docs/assets/rsc-runtime-workbench/fidelity-ledger.md +++ b/docs/assets/rsc-runtime-workbench/fidelity-ledger.md @@ -6,21 +6,23 @@ Workbench evidence. It is not a claim that every concept detail shipped. The concept image is not a 1536×1024 capture requirement. The approved, committed capture boundary is exactly 1440×900 for `desktop.png`, -`hmr-before.png`, `hmr-after.png`, `compile-error.png`, and `recovered.png`, -and exactly 390×844 for `mobile.png`. The capture contract pins those PNG -dimensions in `packages/workbench/tests/runtime-playground-capture.test.ts` and -writes per-run identity/layout JSON only beneath `/tmp`. +`hmr-before.png`, `hmr-after.png`, `compile-error.png`, and `recovered.png`. +The Workbench is a desktop-only application (see `AGENTS.md`), so the capture +interface is desktop-only; the previously committed 390×844 `mobile.png` was +retired with it. The capture contract pins those PNG dimensions in +`packages/workbench/tests/runtime-playground-capture.test.ts` and writes +per-run identity/layout JSON only beneath `/tmp`. ## Current captured authority -`packages/workbench/scripts/capture-runtime-playground.mjs` creates all six +`packages/workbench/scripts/capture-runtime-playground.mjs` creates all five captures from one disposable Runtime fixture. Its readiness authority is a selected immutable run, a visible binding-scoped Runtime preview iframe, and the opaque child heading `Runtime edit timeline`; the stale plan selector `data-app-status="ready"` is not used. The contract proves HMR/recovery -identities, no outer Workbench document reload during App refresh, opaque App -origin, and the mobile zero-scroll/bounds assertions. It restores every source -byte and keeps its per-run JSON untracked under `/tmp`. +identities, no outer Workbench document reload during App refresh, and opaque +App origin. It restores every source byte and keeps its per-run JSON untracked +under `/tmp`. `Verified` means a cited raster and/or committed test directly establishes the acceptance fact. `Intentional deviation` records a deliberate as-built change @@ -31,39 +33,39 @@ not a pass. | Region | Concept evidence | Acceptance | Render evidence | Disposition | | --- | --- | --- | --- | --- | | Header | `Agent Bundle Workbench`, separator, `Runtime Playground`, `Documentation ↗`, settings gear | Existing Workbench header remains recognizable; Runtime is a sibling route, with real landmarks and keyboard focus | `runtime-playground.e2e.test.ts` proves Runtime navigation and its heading, but all six approved crops begin below the shell header. | Not visually evidenced — shell-header composition is outside the final crops. | -| Identity strip | Twelve separately labelled runtime/provider/HMR/session/generation/state/target fields; simulated Portable MCP Apps profile | Labels and values stay separate, ordered, readable, and provider-declared; browser HMR clients are not inferred from endpoint readiness | `mobile.png` shows only the Portable profile/evidence portion; `runtime-playground.e2e.test.ts` verifies authoritative identity attributes and the distinct HMR-client count, but not the full twelve-field visual order/readability. | Not visually evidenced — the full identity-strip composition is outside the final crops. | +| Identity strip | Twelve separately labelled runtime/provider/HMR/session/generation/state/target fields; simulated Portable MCP Apps profile | Labels and values stay separate, ordered, readable, and provider-declared; browser HMR clients are not inferred from endpoint readiness | `runtime-playground.e2e.test.ts` verifies authoritative identity attributes and the distinct HMR-client count, but not the full twelve-field visual order/readability. | Not visually evidenced — the full identity-strip composition is outside the final crops. | | Provider/HMR status | Green-dot `Yes` values for `Provider active` and `HMR endpoint ready`; `Browser HMR clients: 1` is distinct | Expose phase text plus color; HMR readiness and connected-client events remain separate | The capture contract proves a generation/run advance without document reload, and `runtime-playground-hmr.e2e.test.ts` verifies HMR client count; neither captures the full phase/color presentation. | Not visually evidenced — HMR behavior is tested, but this status treatment is not directly rendered in the approved crops. | | Generation identity | Cobalt chip `gen_00012345 (current)`; source revision, artifact epoch, and `Last good: gen_00012344` | Active and last-good identities are immutable and never crossed between generations | `compile-error.png` retains the last-good generation/run and `recovered.png` shows a later recovered generation; the capture contract asserts those identities differ as required. | Verified | | Left operation groups | `Hooks (1)`, `MCP Tools (3)`, `MCP Resources (2)`, `MCP Apps (2)` | Operation groups are visible, count-bearing, keyboard accessible, and provider-surface driven | The as-built Runtime UI uses one provider-declared `Runtime surface` selector and output stage; `runtime-playground.e2e.test.ts` drives those surfaces. It has no concept-style left operation-group rail. | Intentional deviation — avoids a second provider-surface navigation model. | | Fixture selectors | `Fixtures`, `customer_lookup_success`, `Target`, `simulated-host` | Fixture and target choices are explicit; browser sends provider-declared opaque target IDs only; `simulated-host` is concept evidence, not an implementation value | `desktop.png`/`recovered.png` show Surface, Fixture, Target, and Profile selectors; `runtime-playground.e2e.test.ts` selects provider-declared fixture/target values. | Intentional deviation — concept-only `simulated-host` is replaced by the authoritative target ID. | | Input tabs | `Form` selected beside `Raw JSON`; `customer_id`, `include_orders`, `limit` fields | Form and raw draft share one validated model; tab selection has accessible selected state | `compile-error.png` shows Raw JSON and the detached draft; `runtime-playground.e2e.test.ts` switches Schema form → Raw JSON and verifies the retained draft. | Verified | -| Run controls | Full-width cobalt `Run`; neutral `Reset fixture state` | Read-only run affordance is immediate; reset/mutating actions have confirmation and at least 40px controls | `compile-error.png` retains Run and Reset while source build fails; `runtime-playground.e2e.test.ts` verifies confirmation and every visible Runtime control’s 40px mobile hit target. | Verified | +| Run controls | Full-width cobalt `Run`; neutral `Reset fixture state` | Read-only run affordance is immediate; reset/mutating actions have confirmation and at least 40px controls | `compile-error.png` retains Run and Reset while source build fails; `runtime-playground.e2e.test.ts` verifies the mutable-surface confirmation flow. The per-control 40px hit-target measurement was retired with the desktop-only pruning; the 40px minimum now rests on the committed `styles.css` control sizing. | Not visually evidenced — the confirmation flow is directly tested, but the 40px control acceptance now rests on source inspection alone. | | Run history | `Run history (2)`, `Clear`, two green-success entries with generation chips | History is newest-first, immutable, provider-session scoped, capped at 50, and never relabels old evidence | `compile-error.png` retains prior successful records; `runtime-model.test.ts` pins newest-first 50-item history and `runtime-playground-hmr.e2e.test.ts` proves failed source builds add no run. | Verified | | Durable state identity | Concept displays `State store` → `memory` and `State version` → `17` | Keep the separate label/version treatment, but render the provider's opaque durable `stateStoreId`; never imply module memory or browser-owned state | `desktop.png` displays `State store ID` and `State version`; `runtime-playground.e2e.test.ts` compares them with `/api/runtime/status`. | Intentional deviation — concept-only `memory` is replaced by the provider-owned durable identity. | | Last-good banner | Green banner: `All outputs are from the current runtime generation (gen_00012345). No stale views.` plus `View history` | Failed/stale output leaves last-good evidence visible with its exact generation and a phase diagnostic | `compile-error.png` shows the retained last-good identity with AB8206; the capture contract and `runtime-playground-hmr.e2e.test.ts` verify exact run/generation retention. | Verified | | Agent-visible output | `SUCCESS`, `Hook: pre_tool_call`, JSON policy result, `56 ms` | Hook output presents raw bounded evidence, status, operation, duration, and copy affordance | `runtime-playground-hmr.e2e.test.ts` verifies a real hook result remains in the agent-visible stage across failure/recovery. The approved captures use a timeline App run and do not show the concept’s policy/duration/copy composition. | Not visually evidenced — the full concept presentation is not captured. | | Native response | `SUCCESS`, `MCP Tool: get_customer`, expandable `JSON`, customer/orders object | Native response preserves the provider result and does not get replaced by model prose | The approved captures explicitly show `No native response was returned for this run`; no cited capture test renders the concept’s customer response. | Not visually evidenced — no customer/native-response raster proves this composition. | | Model-visible output | `For model consumption` plus four-line customer/order summary | Model-visible fallback is shown beside the App only when declared and remains distinguishable from native output | `desktop.png` shows a separate Model-visible output panel for the selected timeline run, but no cited capture/test proves the declaration-only condition. | Not visually evidenced — the conditional availability claim is not established by this evidence set. | -| MCP App sibling | `MCP App preview`, `Customer Lookup`, status, five-row orders table, open/refresh icons | App preview is a sibling stage surface; no iframe or App node is inserted into the decoded React tree | `mobile.png` shows a separate Runtime App stage and the capture contract proves an opaque child/stable outer frame; no approved crop or cited test proves the decoded-tree exclusion. | Not visually evidenced — sibling rendering is shown, but the complete tree-boundary claim is not. | -| App result copy | `Acme Corporation`, `cust_12345`, `ACTIVE`, `SHIPPED`, `PROCESSING`, order totals/dates | App fixture values are readable, stable, and sourced from the selected run; sandbox/profile evidence is visible but non-marketing | The captured App is the provider’s `Runtime edit timeline`, not Customer Lookup; `mobile.png` visibly labels its simulated profile and non-certified host parity. | Intentional deviation — the capture fixture exercises the timeline App, not the concept’s customer/orders sample. | +| MCP App sibling | `MCP App preview`, `Customer Lookup`, status, five-row orders table, open/refresh icons | App preview is a sibling stage surface; no iframe or App node is inserted into the decoded React tree | The capture contract proves an opaque child/stable outer frame; the raster showing a separate Runtime App stage was the retired mobile capture, and no approved crop or cited test proves the decoded-tree exclusion. | Not visually evidenced — sibling rendering is shown, but the complete tree-boundary claim is not. | +| App result copy | `Acme Corporation`, `cust_12345`, `ACTIVE`, `SHIPPED`, `PROCESSING`, order totals/dates | App fixture values are readable, stable, and sourced from the selected run; sandbox/profile evidence is visible but non-marketing | The captured App is the provider’s `Runtime edit timeline`, not Customer Lookup; the simulated-profile and non-certified host-parity labelling was rastered by the retired mobile capture. | Intentional deviation — the capture fixture exercises the timeline App, not the concept’s customer/orders sample. | | Inspector tabs | `Tree`, `Result`, `Flight`, `Protocol`, `State`, `Diagnostics`; `Tree` active | Six tabs are present in order, with active semantics, keyboard reachability, and bounded artifact views | `compile-error.png` visibly shows all six tabs; `runtime-playground.e2e.test.ts` asserts the six-tab set and selects State, but does not establish keyboard reachability or bounded views. | Not visually evidenced — the complete tab acceptance remains unproven. | | Decoded tree | `Decoded React tree`; `Show component props`, `Expand all`, `Collapse all`; CustomerLookupApp/OrdersTable tree | Tree is derived from decoded React output; props toggle and expansion state are explicit; no JSX/source editor appears | None of the approved final crops shows the Tree tab or the concept’s customer component tree, and the capture contract does not assert its controls. | Not visually evidenced — no final capture proves the full Tree composition. | | Protocol/state diagnostics | Tabs are visible even though Tree is selected in the concept | Result/Flight/Protocol/State/Diagnostics retain the same panel geometry and phase-labelled error surface | `compile-error.png` records `source/build error AB8206` in Diagnostics and `runtime-playground-hmr.e2e.test.ts` verifies the diagnostic while Result remains selected, but neither proves the same geometry for every tab. | Not visually evidenced — only the Diagnostics phase surface is directly shown. | | Trace table | `Trace (2 events)` with ordered hook/tool rows, generation chips, status, duration, details | Run-local spans remain ordered by sequence, bounded, generation-labelled, and exportable without becoming a second durable trace store | The approved final crops do not show a Trace table, and the capture contract does not assert its rows or export behavior. | Not visually evidenced — trace-table acceptance remains outside this evidence set. | | Trace controls | `Auto-scroll`, `Show details`, `Export trace (JSON)`, `Copy trace ID`, opaque trace ID | Controls are keyboard accessible; raw export/copy are bounded and do not leak credentials | No approved crop or cited Runtime capture/E2E test exercises the concept’s trace export/copy controls. | Not visually evidenced — no evidence establishes these controls. | | Footer disclaimer | `Simulated host environment. No external systems are contacted.` | Disclaimer is visible but subordinate; no fake certification or external-host claim is implied | `desktop.png`/`recovered.png` show `Simulated locally — not host certification`; `runtime-playground.test.ts` asserts that exact text, but no evidence measures its visual subordination. | Not visually evidenced — non-certification wording is shown, not the complete layout claim. | -| Typography | Compact sans-serif labels; monospace JSON/IDs/trace; small uppercase status tokens | Type hierarchy remains legible at native and mobile widths; code never depends on color alone | `desktop.png` and `mobile.png` visibly show labels and monospace values, but no committed contrast or color-independence audit establishes the entire acceptance statement. | Not visually evidenced — visual hierarchy is shown; formal accessibility evidence is not. | +| Typography | Compact sans-serif labels; monospace JSON/IDs/trace; small uppercase status tokens | Type hierarchy remains legible at the desktop width; code never depends on color alone | `desktop.png` visibly shows labels and monospace values, but no committed contrast or color-independence audit establishes the entire acceptance statement. | Not visually evidenced — visual hierarchy is shown; formal accessibility evidence is not. | | Palette | White canvas, near-black text, cool gray rules, cobalt active controls, green success, neutral disclaimer | Preserve contrast and restrained developer-tool palette; no gradients or marketing cards | The approved raster set visibly uses the restrained palette, but no committed contrast measurement establishes every stated accessibility property. | Not visually evidenced — visual appearance alone is insufficient for the contrast claim. | -| Container model | 1px outlined panels, 4–6px corners, dense 4px rhythm, 10–16px padding/gutters | Panels align to one grid and retain accessible hit areas without card bloat | `desktop.png` and `mobile.png` show outlined panels, and `runtime-playground.e2e.test.ts` verifies 40px control targets, but no cited evidence establishes the complete grid/padding/no-bloat claim. | Not visually evidenced — only portions of the container acceptance are observed. | +| Container model | 1px outlined panels, 4–6px corners, dense 4px rhythm, 10–16px padding/gutters | Panels align to one grid and retain accessible hit areas without card bloat | `desktop.png` shows outlined panels and the committed `styles.css` sizes Runtime controls at a 40px minimum, but no cited evidence establishes the complete grid/padding/no-bloat claim. | Not visually evidenced — only portions of the container acceptance are observed. | | Focus/selected states | Cobalt outline/tab underline/current chip; selected Form, Tree, history, generation | Focus is visible, selected semantics are announced, and pointer-only state is not used | Keyboard focus restoration and selected states are exercised by `runtime-playground.e2e.test.ts` and `runtime-playground.browser.test.tsx`, but neither captures computed focus appearance or proves color-independent presentation. | Not visually evidenced — implementation behavior exists, but visual focus treatment is not verified. | | Success/error states | Green dots/checks and `SUCCESS`; no error shown in the raster | Implement success and phase-labelled pale-red diagnostics; absence of an error in the concept is not evidence that error UI may be omitted | `compile-error.png` visibly records the phase-labelled AB8206 diagnostic and `recovered.png` shows its cleared text; `runtime-playground-hmr.e2e.test.ts` verifies the failure/recovery behavior. Neither cited raster nor test observes computed pale-red diagnostic styling. | Not visually evidenced — diagnostic phase/text behavior is directly observed, but the compound color-treatment acceptance is not. | | Stale/last-good states | Explicit no-stale message plus prior-generation `Last good` identity | Preserve last-good output through compile/run/App failure and distinguish stale from current | `compile-error.png` and `recovered.png`, backed by the capture contract and `runtime-playground-hmr.e2e.test.ts`, prove retention then recovery. | Verified | | 1100px continuation | Concept is native desktop only; approved continuation moves Inspector below stage | No unreadable third column; bounded trace scroll; identity labels remain separate | No approved 1100px raster or cited contract run covers this breakpoint. | Not visually evidenced — responsive evidence is limited to 1440×900 and 390×844. | -| 390×844 continuation | Concept is native desktop only; approved continuation stacks rail, stage, App, Inspector, trace | No horizontal document overflow; controls remain reachable at 40px minimum; reduced motion and focus retained | `mobile.png` is exactly 390×844 and the capture contract records zero scroll plus host/outer-frame/opaque-child bounds; `runtime-playground.e2e.test.ts` verifies visible controls, schema inputs, and associated radio/checkbox labels are ≥40px and horizontally contained. No cited evidence exercises reduced motion or computed focus visibility. | Not visually evidenced — the geometry is directly tested, but the complete mobile acceptance is not. | +| 390×844 continuation | Concept is native desktop only; approved continuation stacks rail, stage, App, Inspector, trace | Retired — the Workbench is desktop-only (`AGENTS.md`), so no mobile boundary is part of the acceptance set | The desktop-only capture interface produces no 390×844 raster and the capture contract asserts no mobile bounds; no cited test exercises a mobile viewport. | Retired — mobile evidence was withdrawn with the desktop-only capture interface; a mobile-only layout defect is not a release blocker. | ## Update protocol -Retain the approved 1440×900 desktop and 390×844 mobile boundaries. A new row +Retain the approved 1440×900 desktop boundary. A new row may be marked `Verified` only with a direct capture observation and/or a named committed test; source inspection alone is insufficient. Use `Intentional deviation` only for an explicitly stated as-built constraint, and leave any diff --git a/docs/assets/rsc-runtime-workbench/mobile.png b/docs/assets/rsc-runtime-workbench/mobile.png deleted file mode 100644 index a97cfc0bd..000000000 Binary files a/docs/assets/rsc-runtime-workbench/mobile.png and /dev/null differ diff --git a/package.json b/package.json index 995a435f0..1a3acfbf2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "test": "pnpm test:unit && pnpm test:integration", "test:unit": "rstest --config rstest.unit.config.ts", "test:integration": "pnpm build && pnpm test:integration:run", - "test:integration:run": "AGENT_BUNDLE_WORKBENCH_PREBUILT=1 AGENT_BUNDLE_PACKAGE_PREBUILT=1 rstest --config rstest.integration.config.ts && AGENT_BUNDLE_WORKBENCH_PREBUILT=1 AGENT_BUNDLE_PACKAGE_PREBUILT=1 rstest --config rstest.integration-serial.config.ts", + "test:integration:run": "AGENT_BUNDLE_WORKBENCH_PREBUILT=1 AGENT_BUNDLE_PACKAGE_PREBUILT=1 rstest --config rstest.integration.config.ts", "test:watch": "rstest --config rstest.config.ts --watch", "lint": "rslint .", "typecheck": "tsc --noEmit && tsc --project packages/workbench/tsconfig.json", diff --git a/packages/agent-bundle/tests/public-api.test.ts b/packages/agent-bundle/tests/public-api.test.ts index a46173e11..313f0f1eb 100644 --- a/packages/agent-bundle/tests/public-api.test.ts +++ b/packages/agent-bundle/tests/public-api.test.ts @@ -40,6 +40,10 @@ const packageRoot = join(workspaceRoot, 'packages/agent-bundle'); let buildPromise: Promise | undefined; const buildPackage = async (): Promise => { + // The integration pool runs this file on parallel workers that share the + // built dist directories, so a root rebuild here would race every reader. + // `test:integration:run` builds once up front and sets the prebuilt seam. + if (process.env['AGENT_BUNDLE_PACKAGE_PREBUILT'] === '1') return; buildPromise ??= execFile('pnpm', ['build'], { cwd: workspaceRoot, }).then(() => undefined); diff --git a/packages/workbench/tests/support/http.ts b/packages/workbench/tests/support/http.ts index 1f3c70071..20c0a9115 100644 --- a/packages/workbench/tests/support/http.ts +++ b/packages/workbench/tests/support/http.ts @@ -4,12 +4,16 @@ import type { Server } from 'node:http'; * Teardown must not wait for the browser to release its connections: Node's * `server.close()` blocks while any connection still has a request in flight, * which hangs test teardown on two-core CI runners where the page can hold a - * request open at close time. Destroying connections first keeps `close()` - * deterministic regardless of browser state. + * request open at close time. Start `close()` first so the listener stops + * accepting new connections (a reconnecting browser could otherwise slip in a + * fresh request after the sweep), then destroy the held connections while the + * close completion is pending — the order Node's HTTP docs prescribe for + * `closeAllConnections()`. */ export const closeServer = async (server: Server): Promise => { - server.closeAllConnections(); - await new Promise((resolve, reject) => { + const closed = new Promise((resolve, reject) => { server.close((error) => error === undefined ? resolve() : reject(error)); }); + server.closeAllConnections(); + await closed; }; diff --git a/rstest.integration-serial.config.ts b/rstest.integration-serial.config.ts deleted file mode 100644 index 448277c11..000000000 --- a/rstest.integration-serial.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from '@rstest/core'; - -import { serialIntegrationTestFiles } from './rstest.integration-tests.ts'; -import { withAgentBundleRslibConfig } from './rstest.rslib.ts'; - -/** - * Integration files that rewrite workspace-shared artifacts (see the - * serialIntegrationTestFiles doc in rstest.integration-tests.ts). One worker - * only: they rebuild or repack shared package dist directories that every - * other file in this group also reads. - */ -export default defineConfig({ - extends: withAgentBundleRslibConfig(), - include: [...serialIntegrationTestFiles], - pool: { maxWorkers: 1 }, -}); diff --git a/rstest.integration-tests.ts b/rstest.integration-tests.ts index 27a5a6ee3..cdcf6cb86 100644 --- a/rstest.integration-tests.ts +++ b/rstest.integration-tests.ts @@ -1,13 +1,15 @@ /** - * Test files that run real builds (Rslib/Rsbuild), pack and install the - * package, spawn child processes, or drive a browser. These share - * process-wide build caches and output paths, so they run serialized on one - * worker while every other file runs on the parallel unit pool. + * Test files that run real builds (Rslib/Rsbuild), spawn child processes, or + * drive a browser. They run through rstest.integration.config.ts: per-test + * fixtures via `mkdtemp`, servers on ephemeral ports, and only READS of the + * prebuilt shared artifacts (`packages/{agent-bundle,workbench}/dist`), so + * the pool can use multiple workers. * * A new test file belongs here the moment it runs `build()` from src/api or * src/build (directly or via tests/support/build.ts), imports - * tests/support/workbench-e2e.ts or packed-release-harness.ts, spawns a - * process, or launches a browser; otherwise it defaults to the unit pool. + * tests/support/workbench-e2e.ts, spawns a process, or launches a browser; + * otherwise it defaults to the unit pool. Files that `npm pack` the package + * or import packed-release-harness.ts belong in packedTestFiles below. */ export const integrationTestFiles: readonly string[] = [ 'packages/agent-bundle/tests/agent-api.test.ts', @@ -50,7 +52,6 @@ export const integrationTestFiles: readonly string[] = [ 'packages/workbench/tests/mcp-page-app-browser.test.ts', 'packages/workbench/tests/mcp-session-timeout.e2e.test.ts', 'packages/workbench/tests/overview.e2e.test.ts', - 'packages/workbench/tests/packed-release.e2e.test.ts', 'packages/workbench/tests/playground-real.e2e.test.ts', 'packages/workbench/tests/rsbuild-closure.test.ts', 'packages/workbench/tests/rsbuild-workbench.test.ts', @@ -62,38 +63,15 @@ export const integrationTestFiles: readonly string[] = [ 'packages/workbench/tests/workbench-dev-command.test.ts', ]; -/** - * Integration files that WRITE to workspace-shared locations and therefore - * cannot run alongside other integration files: - * - * - packed-release.e2e can run a root `pnpm build` (rewriting - * `packages/{agent-bundle,rsc-runtime,workbench}/dist`) when - * AGENT_BUNDLE_PACKAGE_PREBUILT is unset, and always runs `npm pack` - * plus a packed dev server on a pre-reserved (not ephemeral) port. - * - * They run on one worker via rstest.integration-serial.config.ts after the - * parallel pool finishes. - */ -export const serialIntegrationTestFiles: readonly string[] = [ - 'packages/workbench/tests/packed-release.e2e.test.ts', -]; - -/** - * Integration files safe on parallel workers: they create per-test fixtures - * with `mkdtemp`, bind servers on ephemeral ports (`port: 0` or rsbuild's - * silent free-port fallback), and only READ the prebuilt shared artifacts - * (`packages/workbench/dist`, `packages/agent-bundle/dist`). - */ -export const parallelIntegrationTestFiles: readonly string[] = - integrationTestFiles.filter((file) => !serialIntegrationTestFiles.includes(file)); - /** * Pack-and-install tests: each one runs `npm pack` (and usually a clean * `npm install` of the tarball), which dominates the serialized integration * pool. They run through the root `test:packed` / `test:packed:native` * scripts instead — CI's release-gates job (`check:release`) and the * native-host-smoke workflow keep them covered — and stay excluded from the - * parallel unit pool. + * parallel unit pool. packed-release.e2e lives here (not in the integration + * pool) so `pnpm test` and `check:release` don't each run the same long + * packed-browser suite; `rstest.config.ts` keeps `test:packed` on one worker. */ export const packedTestFiles: readonly string[] = [ 'packages/agent-bundle/tests/dev-workbench-packaging.test.ts', @@ -102,4 +80,5 @@ export const packedTestFiles: readonly string[] = [ 'packages/agent-bundle/tests/public-api-packed.test.ts', 'packages/agent-bundle/tests/release-audit.test.ts', 'packages/agent-bundle/tests/rsc-runtime-optional-packaging.test.ts', + 'packages/workbench/tests/packed-release.e2e.test.ts', ]; diff --git a/rstest.integration.config.ts b/rstest.integration.config.ts index 9b3728ad2..2180d36f0 100644 --- a/rstest.integration.config.ts +++ b/rstest.integration.config.ts @@ -2,7 +2,7 @@ import { availableParallelism } from 'node:os'; import { defineConfig } from '@rstest/core'; -import { parallelIntegrationTestFiles } from './rstest.integration-tests.ts'; +import { integrationTestFiles } from './rstest.integration-tests.ts'; import { withAgentBundleRslibConfig } from './rstest.rslib.ts'; /** @@ -25,14 +25,12 @@ const maxWorkers = Number.isSafeInteger(overrideWorkers) && overrideWorkers >= 1 /** * Build- and process-running tests that only read workspace-shared artifacts; - * files that WRITE shared locations run serialized afterwards through - * rstest.integration-serial.config.ts (rstest has no per-project pool or - * isolate settings, so the split lives in two configs chained by - * `test:integration:run`). + * files that WRITE shared locations (root builds, `npm pack`) run through the + * single-worker `test:packed` script instead (see rstest.integration-tests.ts). */ export default defineConfig({ extends: withAgentBundleRslibConfig(), - include: [...parallelIntegrationTestFiles], + include: [...integrationTestFiles], pool: { maxWorkers }, // Concurrent Chrome + dev-server + rsbuild pairs contend for cores, so // parallel runs double the polling budgets (see tests/support/time-scale.ts)