From 82ad139f0a5b8764f5a0b66f9f7c0b0429c206d4 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 13:56:57 +0100 Subject: [PATCH 1/3] test(e2e): keep shared multi-tenant fixture non-white-label The multi-tenant bootstrap granted white_label, which security/status maps to commercial suppression. Settings shell tests then reached General instead of the expected billing pages. Keep the shared fixture non-white-label and assert that both general-purpose profiles exclude this presentation-changing entitlement. Dedicated commercial-boundary tests and production policy are unchanged. Change-source: pulse-maintainer --- tests/integration/scripts/entitlement-bootstrap.mjs | 4 +++- .../integration/scripts/entitlement-bootstrap.test.mjs | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/integration/scripts/entitlement-bootstrap.mjs b/tests/integration/scripts/entitlement-bootstrap.mjs index 194909786..834059cfe 100644 --- a/tests/integration/scripts/entitlement-bootstrap.mjs +++ b/tests/integration/scripts/entitlement-bootstrap.mjs @@ -5,6 +5,9 @@ import { spawn } from 'node:child_process'; const truthyValues = new Set(['1', 'true', 'yes', 'on']); const BILLING_PROFILES = { + // General-purpose organization/billing fixture, not a white-label runtime. + // white_label deliberately hides commercial routes via security/status; + // commercial suppression belongs in dedicated boundary scenarios. 'multi-tenant': { capabilities: [ 'advanced_reporting', @@ -25,7 +28,6 @@ const BILLING_PROFILES = { 'sso', 'unlimited', 'update_alerts', - 'white_label', ], limits: {}, meters_enabled: [], diff --git a/tests/integration/scripts/entitlement-bootstrap.test.mjs b/tests/integration/scripts/entitlement-bootstrap.test.mjs index 21cd0bb3f..3595bddbc 100644 --- a/tests/integration/scripts/entitlement-bootstrap.test.mjs +++ b/tests/integration/scripts/entitlement-bootstrap.test.mjs @@ -36,6 +36,16 @@ test('buildBillingState returns enterprise capabilities for multi-tenant profile assert.ok(state.capabilities.includes('rbac')); }); +test('general-purpose entitlement profiles keep commercial routes available', () => { + for (const profile of ['multi-tenant', 'infra']) { + const state = buildBillingState(profile); + assert.ok( + !state.capabilities.includes('white_label'), + `${profile} must not opt the shared runtime into commercial suppression`, + ); + } +}); + test('applyRequestedEntitlementProfile writes a billing state file when a path is provided', async () => { const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'pulse-entitlement-')); const billingPath = path.join(dir, 'billing.json'); From 096480a4e3b1ba7eb0d55a42489e8a3fe3b4cfb6 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 14:24:22 +0100 Subject: [PATCH 2/3] test(web): verify compact settings headings and canonical routes Fresh multi-tenant browser runs reproduced desktop-title expectations on mobile organization panels. Match the compact navigation labels, update the server-updates title, and assert canonical URLs including the legacy AI route redirect. All 33 settings-shell checks pass across Chromium, mobile Chrome and mobile Safari; production presentation policy is unchanged. Change-source: pulse-maintainer --- .../tests/15-settings-shell-consistency.spec.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/integration/tests/15-settings-shell-consistency.spec.ts b/tests/integration/tests/15-settings-shell-consistency.spec.ts index a77167bf9..e87e09689 100644 --- a/tests/integration/tests/15-settings-shell-consistency.spec.ts +++ b/tests/integration/tests/15-settings-shell-consistency.spec.ts @@ -21,18 +21,21 @@ const SETTINGS_SHELL_ROUTES = [ { route: '/settings/organization', title: 'Organization Overview', + mobileTitle: 'Overview', description: 'Review organization metadata, membership footprint, and ownership.', requiresMultiTenant: true, }, { route: '/settings/organization/access', title: 'Organization Access', + mobileTitle: 'Access', description: 'Manage organization invitations, member roles, and ownership transfers.', requiresMultiTenant: true, }, { route: '/settings/organization/billing', title: 'Billing & Usage', + mobileTitle: 'Billing', description: 'Review your organization plan, applicable usage policies, and subscription status for paid access.', requiresMultiTenant: true, @@ -50,13 +53,14 @@ const SETTINGS_SHELL_ROUTES = [ }, { route: '/settings/system-ai', + canonicalRoute: '/settings/pulse-intelligence/provider', title: 'Provider & Models', description: 'Configure providers, default models, provider health, budget, and usage for Pulse Intelligence.', }, { route: '/settings/system-updates', - title: 'Updates', + title: 'Pulse server updates', description: 'Manage Pulse server runtime version checks, update channels, and automatic updates. Agent updates stay under Infrastructure.', }, @@ -144,8 +148,13 @@ test.describe('Settings shell consistency', () => { await expect(navigation).toBeHidden(); } - const pageHeading = page.getByRole('heading', { level: 1, name: panel.title }); + // The compact mobile header uses the navigation label, not the + // desktop page title (SettingsPageShell + settingsNavCatalog). + const title = isMobile && 'mobileTitle' in panel ? panel.mobileTitle : panel.title; + const pageHeading = page.getByRole('heading', { level: 1, name: title, exact: true }); await expect(pageHeading, `${panel.route} should render the canonical page-shell heading`).toBeVisible(); + const canonicalRoute = 'canonicalRoute' in panel ? panel.canonicalRoute : panel.route; + await expect(page).toHaveURL(new RegExp(`${canonicalRoute}$`)); if (!isMobile) { // Panel descriptions are desktop-only copy (hidden sm:block). await expect( From 1dcaee8ae870092f08f1692d9c81935d13229bc7 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 14:59:02 +0100 Subject: [PATCH 3/3] test(web): preserve threshold edits across controlled disclosure toggles Threshold table tests replace the disclosure with a mock, so they cannot protect the controlled collapse/reopen behaviour used by snapshot controls. Exercise the real disclosure with reactive parent state and verify accessibility attributes and retained input identity/value without claiming browser focus or installed-release recovery evidence. Change-source: pulse-maintainer --- .../__tests__/CollapsibleSection.test.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/frontend-modern/src/components/Alerts/Thresholds/sections/__tests__/CollapsibleSection.test.tsx b/frontend-modern/src/components/Alerts/Thresholds/sections/__tests__/CollapsibleSection.test.tsx index e29b68cba..40f9cab7f 100644 --- a/frontend-modern/src/components/Alerts/Thresholds/sections/__tests__/CollapsibleSection.test.tsx +++ b/frontend-modern/src/components/Alerts/Thresholds/sections/__tests__/CollapsibleSection.test.tsx @@ -1,4 +1,5 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; +import { createSignal } from 'solid-js'; import { cleanup, fireEvent, render, screen } from '@solidjs/testing-library'; import { CollapsibleSection, SectionActionButton, NestedGroupHeader } from '../CollapsibleSection'; import { @@ -173,6 +174,47 @@ describe('CollapsibleSection', () => { expect(button).toHaveAttribute('aria-expanded', 'false'); }); + it('preserves an edited threshold across controlled collapse and reopen', () => { + const [collapsed, setCollapsed] = createSignal(true); + render(() => ( + + + + )); + + const disclosure = screen.getByRole('button', { name: 'Snapshot Age' }); + const panel = document.getElementById(disclosure.getAttribute('aria-controls')!); + expect(panel).toHaveAttribute('inert'); + expect(panel).toHaveAttribute('aria-hidden', 'true'); + + fireEvent.click(disclosure); + expect(disclosure).toHaveAttribute('aria-expanded', 'true'); + expect(panel).not.toHaveAttribute('inert'); + expect(panel).not.toHaveAttribute('aria-hidden'); + const input = screen.getByRole('spinbutton', { name: 'Warning days' }); + fireEvent.input(input, { target: { value: '14' } }); + + fireEvent.click(disclosure); + expect(disclosure).toHaveAttribute('aria-expanded', 'false'); + expect(panel).toHaveAttribute('inert'); + expect(panel).toHaveAttribute('aria-hidden', 'true'); + + fireEvent.click(disclosure); + expect(disclosure).toHaveAttribute('aria-expanded', 'true'); + expect(panel).not.toHaveAttribute('inert'); + expect(panel).not.toHaveAttribute('aria-hidden'); + expect(screen.getByRole('spinbutton', { name: 'Warning days' })).toBe(input); + expect(input).toHaveValue(14); + }); + it('shows "Disabled" badge when isGloballyDisabled is true', () => { render(() => (