From 722e4fc53371185f2cbd0fbe0a5f25faf115c4d4 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Thu, 3 Sep 2026 21:58:56 +0200 Subject: [PATCH] fix(e2e): make the chrome specs pass in a real browser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three defects, all found by actually RUNNING the specs rather than collecting them. Until now they had only ever been listed, which proves a spec parses and nothing else. 1. The cn-nav-* testids are on the
  • WRAPPER. The clickable element and the href both live on the inside it, so clicking the li resolved the locator and then never became actionable — a 30s timeout that reads like the navigation is broken — and reading href off the li gave null. 2. On a FRESH instance the setup wizard modal opens over the app and intercepts pointer events. Every nav click failed while every URL navigation passed, which is exactly the shape that hides this: only the click-through tests break, and only on a clean install. 3. A bare getByText('Open') matched the SVG Opens in a new tab on an external-link icon — attached, hidden, unrelated. Single-word probes are now scoped to the page body. Verified against a throwaway Nextcloud (not the shared :8080, and not the neighbouring sessions' containers): planninq 6/6 and keepiq 5/5 green. --- tests/e2e/app-chrome.spec.ts | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/tests/e2e/app-chrome.spec.ts b/tests/e2e/app-chrome.spec.ts index 1f2129b1..167aa253 100644 --- a/tests/e2e/app-chrome.spec.ts +++ b/tests/e2e/app-chrome.spec.ts @@ -24,16 +24,39 @@ * The config supplies `use.storageState`, so specs start signed in. */ +import type { Page } from '@playwright/test' + import { expect, test } from '@playwright/test' const APP_BASE = '/index.php/apps/hermiq' +/** + * Dismiss the first-run setup wizard if it is open. + * + * ⚠️ On a FRESH instance CnSetupWizard opens over the app and its modal + * intercepts pointer events, so every nav click resolves its locator and then + * times out after 30s — a failure that reads like the navigation is broken. + * Tests that navigate by URL pass, which is what makes this so easy to miss: + * only the click-through tests fail, and only on a clean install. + * + * @param page The page. + */ +async function dismissSetupWizard(page: Page): Promise { + const modal = page.locator('[data-testid="cn-modal"]') + if ((await modal.count()) === 0) { + return + } + await modal.first().getByRole('button', { name: 'Close' }).click() + await expect(modal).toHaveCount(0, { timeout: 15_000 }) +} + test.describe('app chrome (ADR-114)', () => { test.beforeEach(async ({ page }) => { await page.goto(`${APP_BASE}/`, { waitUntil: 'domcontentloaded' }) await expect(page.locator('[data-testid="cn-nav"]')).toBeVisible({ timeout: 30_000, }) + await dismissSetupWizard(page) }) test('the footer reads Documentation, Store, Reports, Features & roadmap, each with a glyph', async ({ @@ -80,7 +103,10 @@ test.describe('app chrome (ADR-114)', () => { nav.locator('[data-testid="cn-nav-entry-AiOversightMenu"]'), ).toHaveCount(0) - await nav.locator('[data-testid="cn-nav-entry-ReportsMenu"]').click() + await nav + .locator('[data-testid="cn-nav-entry-ReportsMenu"] a') + .first() + .click() await expect(page).toHaveURL(/\/apps\/hermiq\/reports(\?|$)/, { timeout: 15_000, }) @@ -131,6 +157,9 @@ test.describe('app chrome (ADR-114)', () => { const admin = nav.locator('[data-testid="cn-nav-admin-settings"]') await expect(admin).toBeAttached() - await expect(admin).toHaveAttribute('href', /\/settings\/admin\/hermiq$/) + await expect(admin.locator('a').first()).toHaveAttribute( + 'href', + /\/settings\/admin\/hermiq$/, + ) }) })