import { expect, test } from "@playwright/test"; import { mockApi, seedAuthenticatedState } from "./support/network.js"; async function suppressVueDevtoolsOverlay(page) { await page.addInitScript(() => { const STYLE_ID = "__e2e-hide-vue-devtools"; const apply = () => { if (!document.getElementById(STYLE_ID)) { const style = document.createElement("style"); style.id = STYLE_ID; style.textContent = "#__vue-devtools-container__, .vue-devtools__anchor-btn, .vue-devtools__panel-content { display: none !important; visibility: hidden !important; pointer-events: none !important; }"; (document.head || document.documentElement).appendChild(style); } const container = document.getElementById("__vue-devtools-container__"); if (container) { container.style.display = "none"; container.style.pointerEvents = "none"; } }; apply(); const observer = new MutationObserver(apply); observer.observe(document.documentElement, { childList: true, subtree: true }); }); } async function primeSuperuserSession(page) { const token = "superuser-e2e-token"; await seedAuthenticatedState(page, token); await page.goto("/login"); await page.evaluate(async (sessionToken) => { const sessionModule = await import("/src/components/session/token/SessionUser.vue"); window.localStorage.setItem("token", sessionToken); sessionModule.SessionUser.token.value = sessionToken; sessionModule.SessionUser.authenticated.value = true; sessionModule.SessionUser.permissions.value = ["superuser", "user"]; sessionModule.SessionUser.initiated.value = true; }, token); } test.describe("Invoice distribution smoke", () => { test.beforeEach(async ({ page }) => { await suppressVueDevtoolsOverlay(page); await mockApi(page, { authenticated: true, permissions: ["superuser", "user"], invoiceDistribution: true, }); await primeSuperuserSession(page); }); test("@smoke overview loads and quick-open month action works", async ({ page }) => { await page.goto("/superuser/invoices?activeTab=distribution"); await expect(page.getByTestId("distribution-overview-page")).toBeVisible(); await expect(page.locator('[data-testid="distribution-overview-page"] h2').first()).toBeVisible(); const openMonthButton = page.getByTestId("distribution-overview-open-month").first(); await expect(openMonthButton).toBeVisible({ timeout: 15_000 }); const popupPromise = page.waitForEvent("popup", { timeout: 3000 }).catch(() => null); await openMonthButton.click(); const popup = await popupPromise; if (popup) { await expect(popup).toHaveURL(/\/superuser\/invoices\/distribution\/\d+\/\d+/); return; } await expect(page).toHaveURL(/\/superuser\/invoices\/distribution\/\d+\/\d+/); }); test("@smoke monthly tabs keep URL query-state in sync", async ({ page }) => { await page.goto( "/superuser/invoices/distribution/2026/3/customers?customerSearch=acme&customerSource=fixed_pricing&customerDepartment=Copenhagen&compareMode=line_by_line" ); await expect(page.getByTestId("distribution-month-tabs")).toBeVisible(); await expect(page).toHaveURL(/customerSearch=acme/); await expect(page).toHaveURL(/customerSource=fixed_pricing/); await page.getByRole("tab", { name: /Departments|Afdelinger/i }).click(); await page.getByTestId("distribution-department-search").fill("Odense"); await expect(page).toHaveURL(/departmentSearch=Odense/); await page.getByRole("tab", { name: /Customers|Kunder/i }).click(); await page.getByTestId("distribution-customer-search").fill("Nordic"); await expect(page).toHaveURL(/customerSearch=Nordic/); await page.getByRole("tab", { name: /Compare|Sammenlign/i }).click(); await expect(page).toHaveURL(/\/compare/); await expect(page).toHaveURL(/compareMode=line_by_line/); }); test("@smoke compare flow shows progress and mismatch-first results", async ({ page }) => { await page.goto("/superuser/invoices/distribution/2026/3/compare?compareMode=line_by_line"); await page.getByTestId("distribution-compare-submit").click(); const compareTable = page.getByTestId("distribution-compare-table"); const progress = page.locator(".compare-progress"); await Promise.race([ progress.waitFor({ state: "visible", timeout: 6_000 }).catch(() => null), compareTable.waitFor({ state: "visible", timeout: 10_000 }), ]); await expect(compareTable).toBeVisible(); await expect(compareTable.getByText("#101")).toBeVisible(); await expect(compareTable.getByText("#102")).toBeVisible(); const firstDataRow = compareTable.locator("tbody tr").first(); await expect(firstDataRow).toContainText("#101"); }); test("@smoke mobile layout sanity keeps primary controls visible", async ({ page }) => { await page.goto("/superuser/invoices/distribution/2026/3/overview"); await expect(page.getByTestId("distribution-month-toolbar")).toBeVisible(); await expect(page.getByTestId("distribution-month-prev")).toBeVisible(); await expect(page.getByTestId("distribution-month-next")).toBeVisible(); await expect(page.locator(".summary-ribbon:visible").first()).toBeVisible(); await page.getByRole("tab", { name: /Departments|Afdelinger/i }).click(); await expect(page.locator(".table-container--scroll:visible").first()).toBeVisible(); }); test("@smoke fallback mode keeps results and surfaces warning banners", async ({ page }) => { await mockApi(page, { authenticated: true, permissions: ["superuser", "user"], invoiceDistribution: true, invoiceDistributionForceLegacyFallback: true, invoiceDistributionForceCompareFallback: true, }); await primeSuperuserSession(page); await page.goto("/superuser/invoices?activeTab=distribution"); await expect(page.locator(".message.is-warning").filter({ hasText: /v2/i }).first()).toBeVisible({ timeout: 15_000, }); await page.goto("/superuser/invoices/distribution/2026/3/compare?compareMode=line_by_line"); await expect(page.locator(".message.is-warning").filter({ hasText: /v2/i }).first()).toBeVisible(); await page.getByTestId("distribution-compare-submit").click(); await expect(page.getByTestId("distribution-compare-table")).toBeVisible(); await expect(page.locator(".message.is-warning").filter({ hasText: /v2/i }).first()).toBeVisible(); }); });