Files
pleno-vue/tests/e2e/pos.visual.spec.js
T
Jeppe Bundgaard a4676f8f87 Add e2e and unit tests for i18n coverage and POS workflows:
- Introduced i18n key usage validation with `tests/e2e/i18n.views.spec.ts` for deterministic locale coverage.
- Added `viewI18nKeyScanner` utility to scan and validate view translation keys.
- Created `PosDepartmentStep1` unit tests for duplicate warnings and booking selection flow.
- Enhanced POS mobile popup with `SelectOrderBookingPopupProps` and new header close options.
- Updated e2e tests with scenarios to verify booking selections, duplicate handling, and locale alignment.
- Added new `test:e2e:i18n:views` npm script for targeted i18n test execution.
2026-04-14 10:49:20 +02:00

966 lines
33 KiB
JavaScript

import { expect, test } from "@playwright/test";
import { createPosFixture, mockApi, seedAuthenticatedState } from "./support/network.js";
import { createMobilePosFixture, REGULAR_CUSTOMER_ID, setupMobilePosPage } from "./support/mobilePos.js";
const POS_PERMISSIONS = [
"admin",
"department_access_12",
"edit_order_items",
"get_user",
"list_customer_notes",
"list_customer_attributes",
"get_custom_prices_other",
];
async function primeSession(page, token = "pos-visual-token") {
await seedAuthenticatedState(page, token);
const sessionRequest = page.waitForResponse((response) => {
return response.request().method() === "GET" && response.url().includes("/auth/session");
});
await page.goto("/login");
await sessionRequest;
}
async function seedMobileStepTwoState(page, { customerId = 12345679, orderId = 54518 } = {}) {
await page.addInitScript(
({ activeCustomerId, activeOrderId }) => {
window.localStorage.removeItem("pos_order_id");
window.localStorage.setItem(
"pos",
JSON.stringify({
vehicles: {
vehicle_1: {
reg: "EC21235",
status: "verified",
reference: "EC21233 - Test Ref. / Intern nummer",
type: 53,
customer_id: activeCustomerId,
},
vehicle_2: null,
vehicle_3: null,
activeVehicleIndex: 1,
},
views: {
manualInput: false,
vehicleSelection: false,
additionalItemSelection: false,
transactionHistoryView: false,
},
transactionItems: {
primaryItem: {
id: 53,
name: "Forvogn",
price: 649,
addons: [
{
id: 63,
quantity: 1,
product: {
id: 63,
name: "Indvendig vask Forvogn",
price: 399,
},
},
],
},
additionalItems: [
{
id: 65,
name: "Ekstraordinær pr. 10 min inkl. kemi",
price: 299,
quantity: 1,
},
],
},
categories: {
list: [],
selected: null,
},
productList: {
list: [],
},
metadata: {
customerId: activeCustomerId,
notes: "Visual regression note",
reference: "EC21233 - Test Ref. / Intern nummer",
washId: null,
bookingId: null,
laneId: null,
},
attachments: {
files: [],
base64: [],
wash_certificate: false,
},
transactionHistory: [],
lastVehicleOrders: {
vehicle_1: {
id: activeOrderId,
created_at: "2026-04-08 08:44:07",
items: [],
},
vehicle_2: null,
vehicle_3: null,
},
timestamp: Date.now(),
})
);
},
{
activeCustomerId: customerId,
activeOrderId: orderId,
}
);
}
async function expectCustomerTabsDividerSpacing(scope) {
const tabs = scope.locator(".pos-selected-customer__tabs").first();
await expect(tabs).toBeVisible();
const spacing = await tabs.evaluate((element) => Number.parseFloat(window.getComputedStyle(element).marginBottom));
expect(spacing).toBeGreaterThan(5);
}
async function expectPosCardTabsDividerSpacing(scope) {
const tabs = scope.locator(".pos-card-tabs > .tabs").first();
await expect(tabs).toBeVisible();
const spacing = await tabs.evaluate((element) => Number.parseFloat(window.getComputedStyle(element).paddingBottom));
expect(spacing).toBeGreaterThan(5);
}
async function getElementMetrics(locator) {
await expect(locator).toBeVisible();
return locator.evaluate((element) => {
const styles = window.getComputedStyle(element);
const rect = element.getBoundingClientRect();
return {
fontSize: Number.parseFloat(styles.fontSize),
lineHeight: Number.parseFloat(styles.lineHeight),
height: rect.height,
};
});
}
async function getSidebarTabMetrics(locator) {
await expect(locator).toBeVisible();
return locator.evaluate((element) => {
const styles = window.getComputedStyle(element);
const rect = element.getBoundingClientRect();
return {
color: styles.color,
backgroundColor: styles.backgroundColor,
borderRadius: styles.borderRadius,
minHeight: styles.minHeight,
paddingTop: styles.paddingTop,
paddingRight: styles.paddingRight,
paddingBottom: styles.paddingBottom,
paddingLeft: styles.paddingLeft,
height: rect.height,
};
});
}
async function getSidebarTabListMetrics(locator) {
await expect(locator).toBeVisible();
return locator.evaluate((element) => {
const styles = window.getComputedStyle(element);
return {
gap: styles.gap,
rowGap: styles.rowGap,
columnGap: styles.columnGap,
};
});
}
async function getHorizontalBounds(locator) {
await expect(locator).toBeVisible();
return locator.evaluate((element) => {
const rect = element.getBoundingClientRect();
return {
left: rect.left,
right: rect.right,
top: rect.top,
bottom: rect.bottom,
height: rect.height,
width: rect.width,
};
});
}
async function expectPrimaryActionAboveClearAll(primaryAction, clearAllAction) {
const primaryBounds = await getHorizontalBounds(primaryAction);
const clearAllBounds = await getHorizontalBounds(clearAllAction);
expect(primaryBounds.top).toBeLessThan(clearAllBounds.top);
expect(primaryBounds.bottom).toBeLessThan(clearAllBounds.bottom);
}
async function openOrderDetailAddItems(page) {
const addItemsPanel = page.locator('[data-testid="pos-order-add-items-panel"]:visible').first();
const addItemsBackButton = page.locator('[data-testid="pos-order-add-items-back"]:visible').first();
await page.goto("/admin/12/modules/pos/orders/54518");
await expect(page.getByTestId("pos-order-detail")).toBeVisible();
await page.getByTestId("pos-order-add-item").click();
await expect(addItemsPanel).toBeVisible();
await expect(addItemsBackButton).toBeVisible();
}
function getVisibleTestId(page, testId) {
return page.locator(`[data-testid="${testId}"]:visible`).first();
}
function buildTodayTimestamp(time = "10:00:00.000Z") {
const today = new Date().toISOString().split("T")[0];
return `${today}T${time}`;
}
function createRequiredWarningsPosFixture() {
const customerNumber = 12345679;
const baseFixture = createPosFixture();
return createPosFixture({
customerAttributesByNumber: {
[customerNumber]: [
{
id: 11,
customer_number: customerNumber,
attribute: "requiresReferenceNumber",
},
{
id: 12,
customer_number: customerNumber,
attribute: "usePONumbers",
},
],
},
ordersById: {
54518: {
...baseFixture.ordersById[54518],
reference: "",
po: "",
},
},
});
}
test.describe("POS visuals", () => {
test("desktop step 1 snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
const posFixture = createPosFixture({
orderBookings: [
{
id: 77,
reg_1: "AB12345",
reg_2: "",
},
],
});
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: posFixture,
});
await primeSession(page, "pos-visual-desktop-step-1-token");
await page.goto("/admin/12/modules/pos");
const stepOne = page.getByTestId("pos-step-1");
await expect(stepOne).toBeVisible();
await expectPosCardTabsDividerSpacing(stepOne);
await expect(page.getByTestId("pos-recent-scan-row-801")).toBeVisible();
await expect(stepOne.getByText(/^Booket$/)).toBeVisible();
await expect(stepOne).not.toContainText("Booket (fremt. opdat.)");
await expect(stepOne).toHaveScreenshot("pos-step-1-desktop.png", {
maxDiffPixels: 300,
});
});
test("desktop step 1 expanded recent scan snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
const posFixture = createPosFixture({
orderBookings: [
{
id: 77,
reg_1: "AB12345",
reg_2: "",
},
],
});
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: posFixture,
});
await primeSession(page, "pos-visual-desktop-step-1-expanded-token");
await page.goto("/admin/12/modules/pos");
await expect(page.getByTestId("pos-step-1")).toBeVisible();
await expect(page.getByTestId("pos-recent-scan-details-801")).toHaveCount(0);
await page.getByTestId("pos-recent-scan-row-801").click();
await expect(page.locator("#reg_1")).toHaveValue("AB12345");
await expect(page.getByTestId("pos-recent-scan-details-801")).toContainText("RENAULT");
await expect(page.getByTestId("pos-recent-scan-details-801")).toContainText("Captur");
await expect(page.getByTestId("pos-recent-scan-details-801")).toContainText("Booking");
await expect(page.getByTestId("pos-step-1")).toHaveScreenshot("pos-step-1-desktop-expanded-scan.png", {
maxDiffPixels: 300,
});
});
test("desktop step 1 customer snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-desktop-step-1-customer-token");
await page.goto("/admin/12/modules/pos");
await expect(page.getByTestId("pos-step-1")).toBeVisible();
await page.locator("#reg_1").fill("EC21235");
await expect(page.getByTestId("pos-step-1").locator(".pos-card-tabs > .tabs li.is-active")).toContainText("Kunde");
await expectPosCardTabsDividerSpacing(page.getByTestId("pos-step-1"));
await expectCustomerTabsDividerSpacing(page.getByTestId("pos-step-1"));
await expect(page.getByTestId("pos-step-1")).toHaveScreenshot("pos-step-1-customer-desktop.png", {
maxDiffPixels: 300,
});
});
test("desktop step 1 duplicate warning snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
const posFixture = createPosFixture();
posFixture.ordersById[9206] = {
id: 9206,
customer_id: 12345679,
department_id: 12,
reference: "DUP-VISUAL",
po: "",
safety_seal: "",
notes: "",
reg_1: "AB12345",
reg_2: "",
reg_3: "",
invoice_collection_id: null,
booking_id: null,
completed_at: null,
closed_at: null,
created_at: buildTodayTimestamp(),
include_in_invoice: null,
};
posFixture.orderItemsByOrderId[9206] = [];
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: posFixture,
});
await primeSession(page, "pos-visual-desktop-step-1-duplicate-warning-token");
await page.goto("/admin/12/modules/pos");
const stepOne = page.getByTestId("pos-step-1");
await expect(stepOne).toBeVisible();
await page.locator("#reg_1").fill("AB12345");
await page.locator("#reference").click();
await expect(page.getByTestId("pos-desktop-duplicate-warning-inline")).toBeVisible({ timeout: 10_000 });
await expect(stepOne).toHaveScreenshot("pos-step-1-desktop-duplicate-warning.png", {
maxDiffPixels: 300,
});
});
test("desktop step 1 keeps customer notes visible without refetching on blur", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
const customerNoteRequests = [];
page.on("request", (request) => {
if (request.method() === "GET" && request.url().includes("/customer/notes?customer_number=12345679")) {
customerNoteRequests.push(request.url());
}
});
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture({
customerNotesByNumber: {
12345679: [
{
id: 401,
created_at: "2026-04-09 09:15:00",
note: "Ring inden vask",
cashier_id: null,
},
],
},
}),
});
await primeSession(page, "pos-visual-desktop-step-1-notes-token");
await page.goto("/admin/12/modules/pos");
await expect(page.getByTestId("pos-step-1")).toBeVisible();
const stepOne = page.getByTestId("pos-step-1");
const registrationInput = page.locator("#reg_1");
const referenceInput = page.locator("#reference");
const noteRow = stepOne.getByTestId("pos-customer-note-401");
await registrationInput.fill("EC21235");
await expect(noteRow).toBeVisible();
await expect(noteRow).toContainText("Ring inden vask");
await expect.poll(() => customerNoteRequests.length).toBe(1);
await referenceInput.click();
await expect(noteRow).toBeVisible();
await expect(noteRow).toContainText("Ring inden vask");
await page.waitForTimeout(250);
expect(customerNoteRequests).toHaveLength(1);
});
test("desktop order detail snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-desktop-token");
await page.goto("/admin/12/modules/pos/orders/54518");
await expect(page.getByTestId("pos-order-detail")).toBeVisible();
await expect(page.locator('[data-auto-excel-export-button="1"]')).toHaveCount(0);
await expect(page.getByTestId("pos-order-registration-add-2")).toBeVisible();
await expect(page.getByTestId("pos-order-note-empty-state")).toBeVisible();
await expect(page.getByTestId("pos-order-item-edit-9101")).toBeVisible();
await expect(page.getByTestId("pos-order-add-item")).toBeVisible();
await expect(page.getByTestId("pos-order-total")).toContainText("1372 DKK");
await expect(page.getByTestId("pos-order-detail")).toHaveScreenshot("pos-order-detail-desktop.png", {
maxDiffPixels: 300,
});
});
test("desktop order detail required warnings snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createRequiredWarningsPosFixture(),
});
await primeSession(page, "pos-visual-desktop-required-warnings-token");
await page.goto("/admin/12/modules/pos/orders/54518");
await expect(page.getByTestId("pos-order-detail")).toBeVisible();
await expect(page.getByTestId("pos-order-customer-wishes-reference-control")).toHaveAttribute(
"data-warning-state",
"danger"
);
await expect(page.getByTestId("pos-order-customer-wishes-po-control")).toHaveAttribute(
"data-warning-state",
"warning"
);
await expect(page.getByTestId("pos-order-detail")).toHaveScreenshot(
"pos-order-detail-desktop-required-warnings.png",
{
maxDiffPixels: 300,
}
);
});
test("desktop step 2 shared workspace snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-desktop-step-2-title-token");
await page.goto("/admin/12/modules/pos");
await expect(page.getByTestId("pos-step-1")).toBeVisible();
await page.locator("#reg_1").fill("EC21235");
await expect(page.getByTestId("pos-step-1").locator(".pos-card-tabs > .tabs li.is-active")).toContainText("Kunde");
await page.locator('[data-testid="pos-next-step"]:visible').click();
const stepTwo = page.getByTestId("pos-step-2");
const primaryAction = stepTwo.getByTestId("pos-next-step");
const clearAllAction = stepTwo.getByRole("button", { name: /Slet alle/i });
await expect(stepTwo).toBeVisible();
await expect(stepTwo.getByTestId("pos-order-add-items-panel")).toBeVisible();
await expect(stepTwo.getByTestId("pos-order-panel-cart")).toBeVisible();
await expect(stepTwo.getByTestId("pos-order-metadata-grid")).toBeVisible();
await expect(page.locator('[data-testid="pos-order-customer-name"]:visible').first()).toHaveText(
/\(TEST\) Pleno Vognmandsforretning/
);
await expect(primaryAction).toBeVisible();
await expect(clearAllAction).toBeVisible();
await expectPrimaryActionAboveClearAll(primaryAction, clearAllAction);
await expect(stepTwo).toHaveScreenshot("pos-step-2-desktop.png", {
maxDiffPixels: 300,
});
});
test("desktop step 3 shared workspace snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-desktop-step-3-token");
const customerResponse = page.waitForResponse((response) => {
return (
response.request().method() === "GET" && response.url().includes("/users/customer?customer_number=12345679")
);
});
await page.goto("/admin/12/modules/pos?id=54518&customer_id=12345679&step=3");
await customerResponse;
const stepThree = page.getByTestId("pos-step-3");
const primaryAction = stepThree.getByTestId("pos-next-step");
const clearAllAction = stepThree.getByRole("button", { name: /Slet alle/i });
await expect(stepThree).toBeVisible();
await expect(stepThree.getByTestId("pos-order-panel-cart")).toBeVisible();
await expect(stepThree.getByTestId("pos-order-metadata-grid")).toBeVisible();
await expect(stepThree.getByTestId("pos-order-rail")).toBeVisible();
await expect(stepThree).toContainText("Tilføj flere varer");
await expect(primaryAction).toBeVisible();
await expect(clearAllAction).toBeVisible();
await expect(stepThree.getByRole("button", { name: /Fuldfør/i })).toBeVisible();
await expectPrimaryActionAboveClearAll(primaryAction, clearAllAction);
await expect(stepThree).toHaveScreenshot("pos-step-3-desktop.png", {
maxDiffPixels: 300,
});
});
test("desktop step 4 shared workspace snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-desktop-step-4-token");
const customerResponse = page.waitForResponse((response) => {
return (
response.request().method() === "GET" && response.url().includes("/users/customer?customer_number=12345679")
);
});
await page.goto("/admin/12/modules/pos?id=54518&customer_id=12345679&step=4");
await customerResponse;
const stepFour = page.getByTestId("pos-step-4");
const primaryAction = stepFour.getByTestId("pos-next-step");
const clearAllAction = stepFour.getByRole("button", { name: /Slet alle/i });
await expect(stepFour).toBeVisible();
await expect(stepFour.getByTestId("pos-order-panel-cart")).toBeVisible();
await expect(stepFour.getByTestId("pos-order-metadata-grid")).toBeVisible();
await expect(stepFour.getByTestId("pos-order-rail")).toBeVisible();
await expect(stepFour).toContainText("Tilføj flere varer");
await expect(primaryAction).toBeVisible();
await expect(clearAllAction).toBeVisible();
await expect(stepFour.getByRole("button", { name: /Fuldfør/i })).toBeVisible();
await expectPrimaryActionAboveClearAll(primaryAction, clearAllAction);
await expect(stepFour).toHaveScreenshot("pos-step-4-desktop.png", {
maxDiffPixels: 300,
});
});
test("desktop step 3 guest stripe action order", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
const guestStripeCustomer = {
id: 2,
customerNumber: 999,
name: "Card Terminal Customer",
address: "Terminal Street 9",
zip: "2630",
city: "Taastrup",
mobilePhone: "87654321",
email: "card@example.com",
corporateIdentificationNumber: "99999999",
economic_customer: 999,
barred: false,
};
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture({
customersByNumber: {
999: guestStripeCustomer,
12345679: guestStripeCustomer,
},
ordersById: {
54518: {
id: 54518,
customer_id: 999,
department_id: 12,
reference: "CARD-REF-54518",
notes: "Paid at terminal",
reg_1: "ZZ99999",
reg_2: "",
reg_3: "",
invoice_collection_id: null,
booking_id: null,
completed_at: null,
closed_at: null,
created_at: "2026-04-08 08:44:07",
},
},
}),
});
await primeSession(page, "pos-visual-desktop-step-3-guest-token");
await page.goto("/admin/12/modules/pos?id=54518&customer_id=999&step=3");
const stepThree = page.getByTestId("pos-step-3");
const primaryAction = stepThree
.locator(
'[data-testid="pos-stripe-create-intent"], [data-testid="pos-stripe-capture-intent"], [data-testid="pos-stripe-no-readers"], [data-testid="pos-stripe-payment-in-progress"], [data-testid="pos-stripe-payment-succeeded"], [data-testid="pos-stripe-error"]'
)
.first();
const clearAllAction = stepThree.getByRole("button", { name: /Slet alle/i });
await expect(stepThree).toBeVisible();
await expect(stepThree.getByTestId("pos-order-panel-cart")).toBeVisible();
await expect(stepThree.getByTestId("pos-order-metadata-grid")).toBeVisible();
await expect(stepThree.getByTestId("pos-order-rail")).toBeVisible();
await expect(primaryAction).toBeVisible();
await expect(clearAllAction).toBeVisible();
await expectPrimaryActionAboveClearAll(primaryAction, clearAllAction);
});
test("desktop order detail add-items workspace snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-desktop-add-items-token");
await openOrderDetailAddItems(page);
await expect(getVisibleTestId(page, "pos-order-workspace")).toContainText("Transaktion #54518");
await expect(getVisibleTestId(page, "pos-product-card-53")).toBeVisible();
await expect(getVisibleTestId(page, "pos-order-item-edit-9101")).toBeVisible();
await expect(getVisibleTestId(page, "pos-order-total")).toContainText("1372 DKK");
await expect(getVisibleTestId(page, "pos-order-workspace")).toHaveScreenshot(
"pos-order-detail-add-items-desktop.png",
{
maxDiffPixels: 300,
}
);
});
test("desktop order detail edit modal snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("desktop"), "Desktop only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-desktop-edit-modal-token");
await page.goto("/admin/12/modules/pos/orders/54518");
await expect(page.getByTestId("pos-order-detail")).toBeVisible();
await page.getByTestId("pos-order-item-edit-9101").click();
await expect(page.getByTestId("pos-order-item-edit-modal")).toBeVisible();
await expect(page.getByTestId("pos-order-item-edit-modal")).toHaveScreenshot(
"pos-order-detail-edit-modal-desktop.png",
{
maxDiffPixels: 300,
}
);
});
test("mobile step 2 snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("mobile"), "Mobile only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await seedMobileStepTwoState(page);
await primeSession(page, "pos-visual-mobile-step-2-token");
await page.goto("/admin/12/modules/pos?id=54518&customer_id=12345679&step=2");
await expect(page.getByTestId("pos-mobile-step-2")).toBeVisible();
await expect(page.getByTestId("pos-mobile-step-2")).toHaveScreenshot("pos-mobile-step-2.png", {
maxDiffPixels: 300,
});
});
test("mobile step 1 selected customer CTA snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("mobile"), "Mobile only");
const longCustomerName = "(TEST) Pleno Vognmandsforretning";
const fixture = createMobilePosFixture({
customersByNumber: {
[REGULAR_CUSTOMER_ID]: {
id: REGULAR_CUSTOMER_ID,
customerNumber: REGULAR_CUSTOMER_ID,
name: longCustomerName,
address: "Demo Street 1",
zip: "2630",
city: "Taastrup",
mobilePhone: "12345678",
email: "pos-mobile@example.com",
corporateIdentificationNumber: "00012345",
economic_customer: REGULAR_CUSTOMER_ID,
barred: false,
},
},
});
await setupMobilePosPage(page, fixture, {
token: "pos-visual-mobile-step-1-customer-token",
permissions: ["admin", "department_access_1"],
seedState: {
customerId: REGULAR_CUSTOMER_ID,
reg: "EC21235",
reference: "EC21233 - Test Ref. / Intern nummer",
includePrimaryItem: false,
vehicleType: null,
lastOrderId: null,
},
route: {
step: 1,
},
});
await expect(page.getByTestId("pos-mobile-step-1")).toBeVisible();
await expect(page.getByTestId("pos-mobile-next-step")).toContainText(longCustomerName);
await expect(page.getByTestId("pos-mobile-fixed-actions")).toHaveScreenshot("pos-mobile-step-1-fixed-actions.png", {
maxDiffPixels: 300,
});
});
test("mobile transaction history actions keep text left and icons right", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("mobile"), "Mobile only");
const fixture = createMobilePosFixture();
await setupMobilePosPage(page, fixture, {
token: "pos-visual-mobile-transaction-history-token",
permissions: ["admin", "department_access_1"],
seedState: {
customerId: REGULAR_CUSTOMER_ID,
reg: "AB12345",
includePrimaryItem: false,
transactionHistoryView: true,
lastOrderId: 9201,
},
route: {
step: 1,
},
});
await expect(page.getByTestId("pos-mobile-transaction-history")).toBeVisible();
const reloadAction = page.getByTestId("pos-mobile-transaction-history-reload-action");
const reloadLabel = page.getByTestId("pos-mobile-transaction-history-reload-label");
const reloadIcon = page.getByTestId("pos-mobile-transaction-history-reload-icon");
const closeAction = page.getByTestId("pos-mobile-transaction-history-close-action");
const closeLabel = page.getByTestId("pos-mobile-transaction-history-close-label");
const closeIcon = page.getByTestId("pos-mobile-transaction-history-close-icon");
const [
reloadActionBounds,
reloadLabelBounds,
reloadIconBounds,
closeActionBounds,
closeLabelBounds,
closeIconBounds,
] = await Promise.all([
getHorizontalBounds(reloadAction),
getHorizontalBounds(reloadLabel),
getHorizontalBounds(reloadIcon),
getHorizontalBounds(closeAction),
getHorizontalBounds(closeLabel),
getHorizontalBounds(closeIcon),
]);
expect(reloadIconBounds.left).toBeGreaterThan(reloadLabelBounds.right + 8);
expect(reloadActionBounds.right - reloadIconBounds.right).toBeLessThan(24);
expect(
Math.abs(
(reloadIconBounds.top + reloadIconBounds.bottom) / 2 - (reloadActionBounds.top + reloadActionBounds.bottom) / 2
)
).toBeLessThan(6);
expect(closeIconBounds.left).toBeGreaterThan(closeLabelBounds.right + 8);
expect(closeActionBounds.right - closeIconBounds.right).toBeLessThan(24);
expect(
Math.abs(
(closeIconBounds.top + closeIconBounds.bottom) / 2 - (closeActionBounds.top + closeActionBounds.bottom) / 2
)
).toBeLessThan(6);
});
test("mobile attachment view actions keep the same side inset", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("mobile"), "Mobile only");
const fixture = createMobilePosFixture();
await setupMobilePosPage(page, fixture, {
token: "pos-visual-mobile-attachment-view-token",
permissions: ["admin", "department_access_1"],
seedState: {
customerId: REGULAR_CUSTOMER_ID,
reg: "AB12345",
includePrimaryItem: false,
lastOrderId: null,
},
route: {
step: 1,
},
});
await expect(page.getByTestId("pos-mobile-step-1")).toBeVisible();
await page.getByTestId("pos-mobile-attachments-toggle").click();
const takePictureAction = page.getByTestId("pos-mobile-attachment-view-take-picture-action");
const takePictureLabel = page.getByTestId("pos-mobile-attachment-view-take-picture-label");
const takePictureIcon = page.getByTestId("pos-mobile-attachment-view-take-picture-icon");
const closeAction = page.getByTestId("pos-mobile-attachment-view-close-action");
const closeLabel = page.getByTestId("pos-mobile-attachment-view-close-label");
const closeIcon = page.getByTestId("pos-mobile-attachment-view-close-icon");
const [
takePictureActionBounds,
takePictureLabelBounds,
takePictureIconBounds,
closeActionBounds,
closeLabelBounds,
closeIconBounds,
] = await Promise.all([
getHorizontalBounds(takePictureAction),
getHorizontalBounds(takePictureLabel),
getHorizontalBounds(takePictureIcon),
getHorizontalBounds(closeAction),
getHorizontalBounds(closeLabel),
getHorizontalBounds(closeIcon),
]);
expect(takePictureIconBounds.left).toBeGreaterThan(takePictureLabelBounds.right + 8);
expect(takePictureActionBounds.right - takePictureIconBounds.right).toBeLessThan(24);
expect(
Math.abs(
(takePictureIconBounds.top + takePictureIconBounds.bottom) / 2 -
(takePictureActionBounds.top + takePictureActionBounds.bottom) / 2
)
).toBeLessThan(6);
expect(closeIconBounds.left).toBeGreaterThan(closeLabelBounds.right + 8);
expect(closeActionBounds.right - closeIconBounds.right).toBeLessThan(24);
expect(
Math.abs(
(closeIconBounds.top + closeIconBounds.bottom) / 2 - (closeActionBounds.top + closeActionBounds.bottom) / 2
)
).toBeLessThan(6);
});
test("mobile order detail add-items workspace snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("mobile"), "Mobile only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture(),
});
await primeSession(page, "pos-visual-mobile-add-items-token");
await openOrderDetailAddItems(page);
await expect(getVisibleTestId(page, "pos-order-workspace")).toHaveScreenshot(
"pos-order-detail-add-items-mobile.png",
{
maxDiffPixels: 300,
}
);
});
test("mobile step 3 snapshot", async ({ page }, testInfo) => {
test.skip(!testInfo.project.name.includes("mobile"), "Mobile only");
await mockApi(page, {
authenticated: true,
permissions: POS_PERMISSIONS,
edgeGateways: false,
pos: createPosFixture({
ordersById: {
54518: {
id: 54518,
customer_id: 999,
department_id: 12,
reference: "CARD-REF-54518",
notes: "Paid at terminal",
reg_1: "EC21235",
reg_2: "",
reg_3: "",
invoice_collection_id: null,
booking_id: null,
completed_at: null,
closed_at: null,
created_at: "2026-04-08 08:44:07",
},
},
paymentIntentsByOrderId: {
54518: {
id: "pi_54518",
amount: 123400,
amount_capturable: 123400,
amount_received: 0,
currency: "dkk",
status: "requires_capture",
metadata: {
order_id: "54518",
reader_id: "reader_online_1",
tax_percentage: "25",
},
},
},
}),
});
await seedMobileStepTwoState(page, { customerId: 999 });
await primeSession(page, "pos-visual-mobile-step-3-token");
await page.goto("/admin/12/modules/pos?id=54518&customer_id=999&step=3");
await expect(page.getByTestId("pos-mobile-step-3")).toBeVisible();
await expect(page.getByTestId("pos-mobile-step-3")).toHaveScreenshot("pos-mobile-step-3.png", {
maxDiffPixels: 300,
});
});
});