From d88248363e773c98a54871bb86d02fb494862f6c Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 8 Jul 2026 11:10:08 +0100 Subject: [PATCH] Align first-session, migration, and settings-shell specs with shipped UI The settings shell copy moved (General, Billing & Usage, Provider & Models and their descriptions); spec 15 now mirrors settingsHeaderMeta instead of pre-rework titles. The first-run agent handoff pre-provisions the scoped install token, so spec 11 asserts that contract rather than a Generate token button, exempts the app shell's Patrol open-work polling from the no-AI-bootstrap guard (it powers the Patrol nav badge on every route), treats navigation-aborted auth probes as benign console noise, and targets /settings/support/reporting directly now that the /operations alias is retired. Spec 12 scopes migration-notice assertions to the settings content because the global banner legitimately renders the same copy. --- .../tests/11-first-session.spec.ts | 26 ++++++++++++++----- .../tests/12-v5-commercial-migration.spec.ts | 7 +++-- .../15-settings-shell-consistency.spec.ts | 16 +++++++----- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/tests/integration/tests/11-first-session.spec.ts b/tests/integration/tests/11-first-session.spec.ts index b9c4f684b..e60547ade 100644 --- a/tests/integration/tests/11-first-session.spec.ts +++ b/tests/integration/tests/11-first-session.spec.ts @@ -91,9 +91,12 @@ test.describe.serial("First-session experience", () => { await expect( agentDialog.getByRole("heading", { name: "Install on a host" }), ).toBeVisible(); + // The first-run handoff pre-provisions the scoped install token, so no + // "Generate token" step exists in this variant of the dialog. await expect( - agentDialog.getByRole("button", { name: "Generate token" }), + agentDialog.getByText(/already prepared the first scoped install token/i), ).toBeVisible(); + await expect(agentDialog.getByText("Admin API Token")).toBeVisible(); }); test("shell shows key navigation elements", async ({ page }, testInfo) => { @@ -167,6 +170,11 @@ test.describe.serial("First-session experience", () => { ] as const; const consoleErrors: string[] = []; + // The app shell polls Patrol open work (stored findings + pending + // approvals) on every authenticated route to drive the Patrol nav badge. + // Those are cheap reads, not AI invocations, so they are exempt here. + const appShellPatrolPolling = + /\/api\/ai\/(?:patrol\/findings|approvals)(?:\?|$)/; const aiRequests = trackBrowserRequests(page, /\/api\/ai(\/|$)/); page.on("console", (msg) => { if (msg.type() === "error") { @@ -199,19 +207,25 @@ test.describe.serial("First-session experience", () => { await page.waitForTimeout(500); + const unexpectedAIRequests = aiRequests + .urls() + .filter((url) => !appShellPatrolPolling.test(url)); expect( - aiRequests.count(), - `Non-AI settings route ${route} should not bootstrap AI endpoints: ${aiRequests.urls().join(", ")}`, + unexpectedAIRequests.length, + `Non-AI settings route ${route} should not bootstrap AI endpoints: ${unexpectedAIRequests.join(", ")}`, ).toBe(0); - // Filter out benign console noise. + // Filter out benign console noise. "Auth check error ... Failed to + // fetch" is the previous route's in-flight auth probe aborted by + // page.goto, not a product error. const realErrors = consoleErrors.filter( (e) => !e.includes("Download the React DevTools") && !e.includes("Warning:") && !e.includes("favicon") && !e.includes("ERR_CONNECTION_REFUSED") && - !e.includes("net::"), + !e.includes("net::") && + !(e.includes("Auth check error") && e.includes("Failed to fetch")), ); expect( @@ -254,7 +268,7 @@ test.describe.serial("First-session experience", () => { // advanced_reporting or audit_logging. const gatedRoutes = [ { - route: "/operations/reporting", + route: "/settings/support/reporting", expectedURL: /\/settings\/support\/reporting/, feature: "advanced_reporting", }, diff --git a/tests/integration/tests/12-v5-commercial-migration.spec.ts b/tests/integration/tests/12-v5-commercial-migration.spec.ts index 9629accf5..6d68765db 100644 --- a/tests/integration/tests/12-v5-commercial-migration.spec.ts +++ b/tests/integration/tests/12-v5-commercial-migration.spec.ts @@ -205,9 +205,12 @@ async function expectMigrationNotice(page: Page, migration: MigrationFixture) { migration.reason, migration.recommended_action, ); - await expect(page.getByText(expectedCopy.title)).toBeVisible(); + // Scope to the settings content: the global CommercialMigrationBanner + // renders the same title outside
, which trips strict mode. + const settingsContent = page.getByRole('main'); + await expect(settingsContent.getByText(expectedCopy.title)).toBeVisible(); for (const fragment of expectedCopy.bodyFragments) { - await expect(page.getByText(fragment)).toBeVisible(); + await expect(settingsContent.getByText(fragment)).toBeVisible(); } await expect(page.getByRole('button', { name: /start 14-day pro trial/i })).toHaveCount(0); } diff --git a/tests/integration/tests/15-settings-shell-consistency.spec.ts b/tests/integration/tests/15-settings-shell-consistency.spec.ts index 2c0f79dbe..ba7edcbaf 100644 --- a/tests/integration/tests/15-settings-shell-consistency.spec.ts +++ b/tests/integration/tests/15-settings-shell-consistency.spec.ts @@ -10,11 +10,13 @@ type WorkerFixtures = { authStorageStatePath: string; }; +// Titles and descriptions mirror the canonical copy in +// frontend-modern/src/components/Settings/settingsHeaderMeta.ts. const SETTINGS_SHELL_ROUTES = [ { route: '/settings/system-general', - title: 'General Settings', - description: 'Configure appearance, layout, and default monitoring cadence.', + title: 'General', + description: 'Manage appearance, layout, and default monitoring cadence.', }, { route: '/settings/organization', @@ -28,8 +30,9 @@ const SETTINGS_SHELL_ROUTES = [ }, { route: '/settings/organization/billing', - title: 'Organization Billing', - description: 'Track plan tier, usage, and upgrade options for multi-tenant deployments.', + title: 'Billing & Usage', + description: + 'Review your organization plan, applicable usage policies, and subscription status for paid access.', }, { route: '/settings/system-relay', @@ -43,8 +46,9 @@ const SETTINGS_SHELL_ROUTES = [ }, { route: '/settings/system-ai', - title: 'Assistant & Patrol', - description: 'Configure providers and models for Pulse Assistant and Patrol.', + title: 'Provider & Models', + description: + 'Configure providers, default models, provider health, budget, and usage for Pulse Intelligence.', }, { route: '/settings/system-updates',