From 958f584b369a4a901c64478617dff7e5fccf054a Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Wed, 21 Oct 2026 00:20:01 +0000 Subject: [PATCH] test(ui): build the add-on bundles once for the whole run Each worker built the Studio and Talk bundles into the same dist directory, and the build empties that directory first. A worker that started, or restarted after a failure, removed the files another worker was serving, so a Studio spec saw "the style sheet of the add-on could not be loaded". Build once in a global setup before the workers start. A run without the setup still builds per worker. Assisted-by: Claude Code:claude-sonnet-5-5 node Signed-off-by: Ettore Di Giacinto --- core/http/react-ui/e2e/global-setup.js | 6 ++++++ core/http/react-ui/e2e/studio-addon.js | 16 +++++++++++++++- core/http/react-ui/playwright.config.js | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 core/http/react-ui/e2e/global-setup.js diff --git a/core/http/react-ui/e2e/global-setup.js b/core/http/react-ui/e2e/global-setup.js new file mode 100644 index 000000000..9139a314b --- /dev/null +++ b/core/http/react-ui/e2e/global-setup.js @@ -0,0 +1,6 @@ +import { buildStudioAddons } from './studio-addon.js' + +// Builds the Studio and Talk add-on bundles once, before the workers start. +export default async function globalSetup() { + await buildStudioAddons() +} diff --git a/core/http/react-ui/e2e/studio-addon.js b/core/http/react-ui/e2e/studio-addon.js index 449fb57fb..976b69c32 100644 --- a/core/http/react-ui/e2e/studio-addon.js +++ b/core/http/react-ui/e2e/studio-addon.js @@ -13,8 +13,22 @@ const DIGEST = 'e'.repeat(64) const TYPES = { js: 'text/javascript', css: 'text/css', png: 'image/png' } const built = new Map() -// Builds the bundle once per worker, so a spec never runs against a stale one. +// The build empties and rewrites addons//ui/dist, and every worker serves +// its files, so two builds at once leave a running spec without its style sheet +// or module. The run builds once, before any worker starts (global-setup.js), +// and says so in this variable. +const BUILT = 'E2E_ADDON_BUNDLES_BUILT' + +// Builds the bundles for the whole run. Called by the Playwright global setup. +export async function buildStudioAddons(ids = ['studio', 'talk']) { + for (const id of ids) await import(path.join(addons, id, 'ui/build.mjs')).then(m => m.build()) + process.env[BUILT] = '1' +} + +// The bundle of one add-on. A run that did not go through the global setup +// builds it here, once per worker, so a spec never runs against a stale one. function build(id) { + if (process.env[BUILT]) return Promise.resolve(path.join(addons, id, 'ui/dist')) if (!built.has(id)) built.set(id, import(path.join(addons, id, 'ui/build.mjs')).then(m => m.build())) return built.get(id) } diff --git a/core/http/react-ui/playwright.config.js b/core/http/react-ui/playwright.config.js index f18012850..87e3e1387 100644 --- a/core/http/react-ui/playwright.config.js +++ b/core/http/react-ui/playwright.config.js @@ -13,6 +13,7 @@ export default defineConfig({ '**/addons-upgrade.spec.js', '**/tables-acceptance.spec.js', '**/tables-artifacts.spec.js', '**/tables-ui.spec.js', ], + globalSetup: './e2e/global-setup.js', timeout: 30_000, retries: process.env.CI ? 2 : 0, // TEMPORARY: cap parallelism. Playwright's default (cores/2) oversubscribes