diff --git a/core/http/react-ui/e2e/addons-fixtures.js b/core/http/react-ui/e2e/addons-fixtures.js index 7ba7a20b4..87cc580fb 100644 --- a/core/http/react-ui/e2e/addons-fixtures.js +++ b/core/http/react-ui/e2e/addons-fixtures.js @@ -44,6 +44,22 @@ export function sessionFor(user, permissions = {}) { const ok = (payload) => ({ status: 200, contentType: 'application/json', body: JSON.stringify({ payload }) }) const fail = (status, type, extra = {}) => ({ status, contentType: 'application/json', body: JSON.stringify({ error: { type, message: type, ...extra } }) }) +// Specs that draw add-on pages need add-ons on. With no add-on owner running, +// the server reports add-ons off and answers 5xx on the pin routes, and the +// browser logs each failed request. These stubs answer the add-on pages with an +// empty set. They live on the context, which Playwright matches after the +// page's own routes: a spec that sets its own features, builtin or pin list +// still gets it. +export async function stubAddonRoutes(page) { + // The real flags, with add-ons on: the other switches keep what the server says. + await page.context().route('**/api/features', async route => { + const real = await (await route.fetch()).json() + return route.fulfill({ json: { ...real, addons: true } }) + }) + await page.context().route('**/api/addons/builtin', route => route.fulfill({ json: { builtin: [] } })) + await page.context().route('**/api/addons/pins', route => route.fulfill({ json: [] })) +} + // Installs the routes and returns the mutable state the spec reads and edits. export async function mockAddons(page, options = {}) { const state = { @@ -62,6 +78,7 @@ export async function mockAddons(page, options = {}) { dispatch: options.dispatch || null, } + await stubAddonRoutes(page) await page.route(/\/api\/addons\/apps\/[^/]+\/icon/, route => route.fulfill({ status: 200, contentType: 'image/png', body: PNG })) await page.route(/\/api\/addons\/apps$/, route => { state.log.appsList += 1 diff --git a/core/http/react-ui/e2e/not-found.spec.js b/core/http/react-ui/e2e/not-found.spec.js index 2ee6f85a6..59ae829b6 100644 --- a/core/http/react-ui/e2e/not-found.spec.js +++ b/core/http/react-ui/e2e/not-found.spec.js @@ -1,8 +1,10 @@ import { test, expect } from './coverage-fixtures.js' import { mockAccess } from './access-fixtures.js' +import { stubAddonRoutes } from './addons-fixtures.js' test.describe('404', () => { test('names the address, offers a way home and lists the places the viewer can go', async ({ page }) => { + await stubAddonRoutes(page) await page.goto('/app/no-such-page') const nf = page.getByTestId('not-found') await expect(nf.getByRole('heading', { level: 1 })).toHaveText('This page does not exist') diff --git a/core/http/react-ui/e2e/studio-addon.js b/core/http/react-ui/e2e/studio-addon.js index 3565355e9..4ce7e098f 100644 --- a/core/http/react-ui/e2e/studio-addon.js +++ b/core/http/react-ui/e2e/studio-addon.js @@ -6,7 +6,7 @@ import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' -import { app, mockAddons } from './addons-fixtures.js' +import { app, mockAddons, stubAddonRoutes } from './addons-fixtures.js' const addons = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../addons') const DIGEST = 'e'.repeat(64) @@ -55,6 +55,7 @@ export function packagedApp(id, over = {}) { // Returns the state of mockAddons. export async function installStudioAddons(page, { ids = ['studio', 'talk'], ...options } = {}) { const dirs = await Promise.all(ids.map(build)) + await stubAddonRoutes(page) await page.route(/\/api\/addons\/(studio|talk|voice)\/assets\//, route => { const parts = new URL(route.request().url()).pathname.split('/') const id = parts[3] diff --git a/core/http/react-ui/e2e/studio-addons.spec.js b/core/http/react-ui/e2e/studio-addons.spec.js index 46347b3e1..3e56c0424 100644 --- a/core/http/react-ui/e2e/studio-addons.spec.js +++ b/core/http/react-ui/e2e/studio-addons.spec.js @@ -1,5 +1,6 @@ import { test, expect } from './coverage-fixtures.js' import { installStudioAddons } from './studio-addon.js' +import { stubAddonRoutes } from './addons-fixtures.js' import { mockStudio } from './studio-fixtures.js' import { fakeRealtime } from './chat-fixtures.js' @@ -66,6 +67,7 @@ test.describe('Studio add-on', () => { }) test('the old Studio addresses say so plainly when the add-on is not installed', async ({ page }) => { + await stubAddonRoutes(page) for (const address of ['/app/studio', '/app/studio/tts', '/app/image', '/app/talk']) { await page.goto(address) await expect(page.getByTestId('addon-unavailable')).toBeVisible({ timeout: 15_000 })