import { expect, test, type BrowserContext } from '@playwright/test'; import { contextForUser } from './helpers'; /** * Settings section navigation pack (issue #145): every settings page derives * a jump nav from its stacked sections; clicking an entry scrolls the section * into view and marks it active. Language-independent selectors (CSS classes) * throughout. */ const BASE_URL = process.env.E2E_BASE_URL ?? 'http://localhost:5173'; async function json(context: BrowserContext, url: string, data: unknown): Promise { const response = await context.request.post(url, { data }); if (!response.ok()) throw new Error(`post ${url} → ${response.status()}`); return response.json() as Promise; } test('user settings show the jump nav and clicking scrolls + activates', async ({ browser }) => { const context = await contextForUser(browser, BASE_URL, 'fixture-user'); const page = await context.newPage(); await page.goto('/settings'); // Let the async section content (sessions, tokens, …) settle first — // sections growing above the target would push it out of view again. await page.waitForLoadState('networkidle'); const nav = page.locator('.settings-nav'); await expect(nav).toBeVisible(); const links = nav.locator('.settings-nav__link'); // Profile, password, sessions, watches, API tokens, feed tokens, data export. // 8 seit #170 (Bedienung), 9 seit #180 (Erscheinungsbild). await expect(links).toHaveCount(9); // Jump to the last section: it scrolls into view and becomes active. const last = links.last(); await last.click(); const lastSection = page.locator('.settings-layout section[id]').last(); // Smooth scrolling needs a moment on a loaded CI runner. await expect(lastSection).toBeInViewport({ timeout: 10_000 }); await expect(last).toHaveClass(/settings-nav__link--active/); await context.close(); }); test('pond settings derive the nav from their sections', async ({ browser }) => { const context = await contextForUser(browser, BASE_URL, 'fixture-user'); const pond = await json<{ id: string; slug: string }>(context, '/api/v1/ponds', { name: `Nav Pack ${Date.now()}`, }); const page = await context.newPage(); await page.goto(`/p/${pond.slug}/settings`); await page.waitForLoadState('networkidle'); const links = page.locator('.settings-nav .settings-nav__link'); // The pond owner sees the full section stack — at least members, labels, // missing links, import, files, appearance, plugins, sidebar, comments, // API, export. await expect(links.first()).toBeVisible(); expect(await links.count()).toBeGreaterThanOrEqual(8); await links.last().click(); await expect(page.locator('.settings-layout section[id]').last()).toBeInViewport({ timeout: 10_000, }); await context.close(); });