254 lines
8.5 KiB
TypeScript
254 lines
8.5 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { API_HOST } from "./support/network.js";
|
|
import { isDesktopProject } from "./support/projects";
|
|
|
|
const json = (body: unknown, status = 200) => ({
|
|
status,
|
|
contentType: "application/json",
|
|
body: JSON.stringify(body),
|
|
});
|
|
|
|
test.describe("Assign draft order modal layout", () => {
|
|
test("keeps the close button aligned and footer actions separated", async ({ page }, testInfo) => {
|
|
test.skip(!isDesktopProject(testInfo), "Desktop only");
|
|
|
|
const pageErrors: string[] = [];
|
|
const consoleErrors: string[] = [];
|
|
|
|
page.on("pageerror", (error) => {
|
|
pageErrors.push(error.stack || error.message);
|
|
});
|
|
|
|
page.on("console", (message) => {
|
|
if (message.type() === "error") {
|
|
consoleErrors.push(message.text());
|
|
}
|
|
});
|
|
|
|
await page.route(API_HOST, async (route) => {
|
|
await route.fulfill(json({ data: [], meta: { pagination: { page: 1, per_page: 100, total: 0 } } }));
|
|
});
|
|
|
|
await page.goto("/tests/e2e/harness/assign-draft-order-customer-modal.html");
|
|
|
|
const modal = page.getByTestId("draft-order-assign-customer-modal");
|
|
await expect(modal).toBeVisible();
|
|
|
|
const [titleBox, closeBox, cancelBox, submitBox] = await Promise.all([
|
|
page.getByTestId("draft-order-assign-title").boundingBox(),
|
|
page.getByTestId("draft-order-assign-close").boundingBox(),
|
|
page.getByTestId("draft-order-assign-cancel").boundingBox(),
|
|
page.getByTestId("draft-order-assign-submit").boundingBox(),
|
|
]);
|
|
|
|
expect(titleBox).not.toBeNull();
|
|
expect(closeBox).not.toBeNull();
|
|
expect(cancelBox).not.toBeNull();
|
|
expect(submitBox).not.toBeNull();
|
|
|
|
if (!titleBox || !closeBox || !cancelBox || !submitBox) {
|
|
throw new Error("Expected modal controls to have measurable layout");
|
|
}
|
|
|
|
expect(Math.abs(closeBox.y - titleBox.y)).toBeLessThanOrEqual(12);
|
|
expect(submitBox.x - (cancelBox.x + cancelBox.width)).toBeGreaterThanOrEqual(8);
|
|
expect(pageErrors).toEqual([]);
|
|
expect(consoleErrors).toEqual([]);
|
|
});
|
|
|
|
test("shows order count and total net amount on invoice collection options", async ({ page }, testInfo) => {
|
|
test.skip(!isDesktopProject(testInfo), "Desktop only");
|
|
|
|
await page.addInitScript(() => {
|
|
window.localStorage.setItem("token", "e2e-token");
|
|
});
|
|
|
|
await page.route(API_HOST, async (route) => {
|
|
const url = route.request().url();
|
|
|
|
if (url.includes("/customers")) {
|
|
await route.fulfill(
|
|
json({
|
|
data: [
|
|
{
|
|
customerNumber: 12345679,
|
|
name: "(TEST) Pleno Vognmandsforretning",
|
|
city: "Taastrup",
|
|
},
|
|
],
|
|
meta: {
|
|
pagination: {
|
|
page: 1,
|
|
per_page: 100,
|
|
total: 1,
|
|
},
|
|
},
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (url.includes("/collected-invoices")) {
|
|
await route.fulfill(
|
|
json({
|
|
data: [
|
|
{
|
|
id: 15559,
|
|
customer_number: 12345679,
|
|
customer_name: "(TEST) Pleno Vognmandsforretning",
|
|
created_at: "2026-04-20 11:06:18",
|
|
closed_at: null,
|
|
total_net_amount: 1562,
|
|
orders: [{ id: 1 }, { id: 2 }, { id: 3 }],
|
|
},
|
|
{
|
|
id: 15401,
|
|
customer_number: 12345679,
|
|
customer_name: "(TEST) Pleno Vognmandsforretning",
|
|
created_at: "2026-04-15 12:43:23",
|
|
closed_at: null,
|
|
total_net_amount: 840,
|
|
orders: 2,
|
|
},
|
|
],
|
|
meta: {
|
|
pagination: {
|
|
page: 1,
|
|
per_page: 100,
|
|
total: 2,
|
|
},
|
|
},
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
await route.fulfill(json({ data: [], meta: { pagination: { page: 1, per_page: 100, total: 0 } } }));
|
|
});
|
|
|
|
await page.goto("/tests/e2e/harness/assign-draft-order-customer-modal.html");
|
|
|
|
await page.getByTestId("draft-order-assign-customer-search").fill("Pleno");
|
|
await page.getByTestId("draft-order-customer-option-12345679").click();
|
|
|
|
const firstSummary = page.getByTestId("draft-order-invoice-collection-summary-15559");
|
|
const secondSummary = page.getByTestId("draft-order-invoice-collection-summary-15401");
|
|
const firstMetrics = firstSummary.locator(".draft-order-assign-collection-metric");
|
|
const secondMetrics = secondSummary.locator(".draft-order-assign-collection-metric");
|
|
|
|
await expect(firstSummary).toBeVisible();
|
|
await expect(firstMetrics).toHaveCount(2);
|
|
await expect(firstMetrics.nth(0)).toContainText(/Ordrer\s*3/);
|
|
await expect(firstMetrics.nth(1)).toContainText(/1\.562,00\s*kr\./);
|
|
await expect(secondMetrics.nth(0)).toContainText(/Ordrer\s*2/);
|
|
await expect(secondMetrics.nth(1)).toContainText(/840,00\s*kr\./);
|
|
|
|
const [firstOrdersMetricBox, firstTotalMetricBox] = await Promise.all([
|
|
firstMetrics.nth(0).boundingBox(),
|
|
firstMetrics.nth(1).boundingBox(),
|
|
]);
|
|
|
|
expect(firstOrdersMetricBox).not.toBeNull();
|
|
expect(firstTotalMetricBox).not.toBeNull();
|
|
|
|
if (!firstOrdersMetricBox || !firstTotalMetricBox) {
|
|
throw new Error("Expected invoice collection metrics to have measurable layout");
|
|
}
|
|
|
|
expect(Math.abs(firstTotalMetricBox.y - firstOrdersMetricBox.y)).toBeLessThanOrEqual(4);
|
|
expect(firstTotalMetricBox.x).toBeGreaterThan(firstOrdersMetricBox.x);
|
|
});
|
|
|
|
test("keeps the modal inside the viewport and scrolls the body when the list is long", async ({ page }, testInfo) => {
|
|
test.skip(!isDesktopProject(testInfo), "Desktop only");
|
|
|
|
await page.setViewportSize({ width: 1280, height: 720 });
|
|
await page.addInitScript(() => {
|
|
window.localStorage.setItem("token", "e2e-token");
|
|
});
|
|
|
|
await page.route(API_HOST, async (route) => {
|
|
const url = route.request().url();
|
|
|
|
if (url.includes("/customers")) {
|
|
await route.fulfill(
|
|
json({
|
|
data: [
|
|
{
|
|
customerNumber: 12345679,
|
|
name: "(TEST) Pleno Vognmandsforretning",
|
|
city: "Taastrup",
|
|
},
|
|
],
|
|
meta: {
|
|
pagination: {
|
|
page: 1,
|
|
per_page: 100,
|
|
total: 1,
|
|
},
|
|
},
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (url.includes("/collected-invoices")) {
|
|
await route.fulfill(
|
|
json({
|
|
data: Array.from({ length: 18 }, (_, index) => ({
|
|
id: 16000 - index,
|
|
customer_number: 12345679,
|
|
customer_name: "(TEST) Pleno Vognmandsforretning",
|
|
created_at: `2026-04-${String((index % 9) + 10).padStart(2, "0")} 11:06:18`,
|
|
closed_at: null,
|
|
total_net_amount: 400 + index * 125,
|
|
orders: index + 1,
|
|
})),
|
|
meta: {
|
|
pagination: {
|
|
page: 1,
|
|
per_page: 100,
|
|
total: 18,
|
|
},
|
|
},
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
await route.fulfill(json({ data: [], meta: { pagination: { page: 1, per_page: 100, total: 0 } } }));
|
|
});
|
|
|
|
await page.goto("/tests/e2e/harness/assign-draft-order-customer-modal.html");
|
|
await page.getByTestId("draft-order-assign-customer-search").fill("Pleno");
|
|
await page.getByTestId("draft-order-customer-option-12345679").click();
|
|
|
|
const modalCard = page.locator(".draft-order-assign-modal");
|
|
const modalBody = page.locator(".draft-order-assign-modal .modal-card-body");
|
|
const footer = page.locator(".draft-order-assign-footer");
|
|
|
|
await expect(footer).toBeVisible();
|
|
|
|
const viewportSize = page.viewportSize();
|
|
const modalCardBox = await modalCard.boundingBox();
|
|
expect(viewportSize).not.toBeNull();
|
|
expect(modalCardBox).not.toBeNull();
|
|
|
|
if (!viewportSize || !modalCardBox) {
|
|
throw new Error("Expected viewport and modal dimensions to be available");
|
|
}
|
|
|
|
expect(modalCardBox.y).toBeGreaterThanOrEqual(0);
|
|
expect(modalCardBox.y + modalCardBox.height).toBeLessThanOrEqual(viewportSize.height - 8);
|
|
|
|
const bodyOverflow = await modalBody.evaluate((element) => ({
|
|
clientHeight: element.clientHeight,
|
|
scrollHeight: element.scrollHeight,
|
|
overflowY: window.getComputedStyle(element).overflowY,
|
|
}));
|
|
|
|
expect(bodyOverflow.overflowY).toBe("auto");
|
|
expect(bodyOverflow.scrollHeight).toBeGreaterThan(bodyOverflow.clientHeight);
|
|
});
|
|
});
|