import type { Page } from "@playwright/test"; import { expect } from "@playwright/test"; export async function expectAuthenticatedShell(page: Page): Promise { await expect(page.getByRole("button", { name: "Accountmenu" })).toBeVisible(); } export async function openPrimaryNavigation(page: Page): Promise { const toggle = page.getByRole("button", { name: "Navigatie openen" }); // toggle.isVisible() alone does not auto-wait — calling it immediately after // page.goto() can race the shell's first paint under load, silently no-op-ing on a // mobile viewport where the toggle genuinely exists but has not rendered yet. // Found via a real, reproducible flake in a full-suite run (V2-M2 shell audit), // not by inspection. waitFor's own timeout distinguishes "not visible yet" from // "never visible" (desktop, where the toggle stays CSS-hidden and the primary // navigation is already on screen without it). try { await toggle.waitFor({ state: "visible", timeout: 2000 }); } catch { return; } await toggle.click(); } export async function followPrimaryNavigation(page: Page, name: string): Promise { await openPrimaryNavigation(page); await page.getByRole("navigation", { name: "Hoofdnavigatie" }).getByRole("link", { name, exact: true }).click(); } export async function openNewKnowledgePage(page: Page): Promise { await page.goto("/knowledge/new"); await expect(page.getByRole("heading", { name: "Nieuwe pagina" })).toBeVisible(); } export async function fillMarkdown(page: Page, markdown: string): Promise { const editor = page.getByRole("textbox", { name: "Inhoud (Markdown)" }); // Explicit select-all + delete before Locator.fill(), rather than relying on // fill()'s own clear heuristic: CodeMirror's contenteditable surface was not // always fully cleared by fill() alone when it already had content, under mobile/ // touch emulation specifically — found via a real V2-M3 test where a second // fillMarkdown() on an existing page's editor produced garbled // old-content-plus-new-content on the chromium-mobile project only (not desktop, // same code), not by inspection. Still uses fill() (not page.keyboard.type()) for // the actual insertion: several existing specs fill markdown containing literal // "[[...]]" wiki-link syntax, which would interact with CodeMirror's // closeBrackets extension if typed via real keystrokes — fill() bypasses that // keystroke-level extension entirely, matching this helper's prior behavior. await editor.click(); await page.keyboard.press("ControlOrMeta+a"); await page.keyboard.press("Delete"); await editor.fill(markdown); } export function markdownEditor(page: Page) { return page.getByRole("textbox", { name: "Inhoud (Markdown)" }); } export async function readMarkdown(page: Page): Promise { return (await markdownEditor(page).locator(".cm-line").allTextContents()).join("\n"); }