- Introduced `PosDesktopOrderBookingSelectorModal.vue` to streamline booking selection for desktop POS. - Added `orderBookingDisplay.js` utility for handling booking display and reference value normalization. - Created unit test `select-vehicle-form-pos.spec.js` to validate booking selection flow and registration matching. - Implemented `run-playwright-ci-parallel.mjs` script to optimize Playwright CI with parallel testing. - Updated styles and responsiveness for enhanced booking modal UX.
161 lines
6.4 KiB
JavaScript
161 lines
6.4 KiB
JavaScript
import { expect, test } from "@playwright/test";
|
|
import { mockApi, primeMockSession } from "./support/network.js";
|
|
|
|
async function suppressVueDevtoolsOverlay(page) {
|
|
await page.addInitScript(() => {
|
|
const STYLE_ID = "__e2e-hide-vue-devtools";
|
|
|
|
const apply = () => {
|
|
const target = document.head || document.documentElement;
|
|
if (!target) {
|
|
return;
|
|
}
|
|
|
|
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; }";
|
|
target.appendChild(style);
|
|
}
|
|
|
|
const container = document.getElementById("__vue-devtools-container__");
|
|
if (container) {
|
|
container.style.display = "none";
|
|
container.style.pointerEvents = "none";
|
|
}
|
|
};
|
|
|
|
apply();
|
|
const startObserving = () => {
|
|
if (!document.documentElement) {
|
|
requestAnimationFrame(startObserving);
|
|
return;
|
|
}
|
|
|
|
const observer = new MutationObserver(apply);
|
|
observer.observe(document.documentElement, { childList: true, subtree: true });
|
|
};
|
|
|
|
startObserving();
|
|
});
|
|
}
|
|
|
|
async function primeSuperuserSession(page) {
|
|
const token = "superuser-e2e-token";
|
|
await primeMockSession(page, { token });
|
|
}
|
|
|
|
async function prepareInvoiceDistributionPage(page, overrides = {}) {
|
|
await suppressVueDevtoolsOverlay(page);
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: ["superuser", "user"],
|
|
invoiceDistribution: true,
|
|
...overrides,
|
|
});
|
|
await primeSuperuserSession(page);
|
|
}
|
|
|
|
test.describe("Invoice distribution smoke", () => {
|
|
test("@smoke overview loads and quick-open month action works", async ({ page }) => {
|
|
await prepareInvoiceDistributionPage(page);
|
|
await page.goto("/superuser/invoices?activeTab=distribution");
|
|
|
|
await expect(page.getByTestId("distribution-overview-page")).toBeVisible({ timeout: 15_000 });
|
|
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 prepareInvoiceDistributionPage(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 prepareInvoiceDistributionPage(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 prepareInvoiceDistributionPage(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 prepareInvoiceDistributionPage(page, {
|
|
invoiceDistributionForceLegacyFallback: true,
|
|
invoiceDistributionForceCompareFallback: true,
|
|
});
|
|
|
|
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({
|
|
timeout: 15_000,
|
|
});
|
|
|
|
await page.getByTestId("distribution-compare-submit").click();
|
|
await expect(page.getByTestId("distribution-compare-table")).toBeVisible({ timeout: 15_000 });
|
|
await expect(page.locator(".message.is-warning").filter({ hasText: /v2/i }).first()).toBeVisible({
|
|
timeout: 15_000,
|
|
});
|
|
});
|
|
});
|