Add utilities and tests for mobile order management and Subuser navigation:

- Introduced `mobileOrderCompletion.js` for mobile order metadata handling with safety seal syncing, metadata persistence, and booking linking utilities.
- Added tests for Subuser navigation menu (`navigation-menu-items-user-subusers.spec.js`) to validate links and permission gating.
- Created unit and end-to-end tests for Subuser grant permissions and management, including permission nodes and invites (`subuser-grant-permission-nodes.spec.js`, `subuser-management.spec.ts`).
- Implemented `SubuserCompleteRegistrationPage.vue` with validation, token handling, and registration flow for Subuser setup.
- Enhanced Playwright e2e tests for Subuser features (`subuserCompleteRegistration.spec.ts`).
This commit is contained in:
Jeppe Bundgaard
2026-04-14 10:09:10 +02:00
parent a93b0dc954
commit c14f0cc1c4
46 changed files with 4258 additions and 674 deletions
+49 -4
View File
@@ -194,11 +194,18 @@ async function selectPrimaryProduct(page, productId = 53) {
}
async function openVehicleSelectionFromPrimaryProduct(page, productName = "Tank truck wash") {
const currentPrimaryProduct = page.getByText(productName, { exact: true });
await expect(currentPrimaryProduct).toBeVisible({ timeout: 10_000 });
await currentPrimaryProduct.dispatchEvent("pointerdown");
const namedProduct = page.getByText(productName, { exact: true });
const fallbackCard = page.getByTestId("pos-mobile-primary-product-card");
const hasNamedProduct = await namedProduct
.isVisible()
.then(() => true)
.catch(() => false);
const trigger = hasNamedProduct ? namedProduct : fallbackCard;
await expect(trigger).toBeVisible({ timeout: 10_000 });
await trigger.dispatchEvent("pointerdown");
await page.waitForTimeout(650);
await currentPrimaryProduct.dispatchEvent("pointerup");
await trigger.dispatchEvent("pointerup");
await expect(page.getByTestId("pos-mobile-vehicle-selection")).toBeVisible({ timeout: 10_000 });
}
@@ -1894,6 +1901,44 @@ test.describe("POS mobile order flow", () => {
await expect.poll(() => fixture.requestCounters.attachmentUpload, { timeout: 10_000 }).toBe(1);
await waitForStepReset(page);
});
test("shows the safety seal field for mobile baskets with a wash certificate and completes via order completion", async ({
page,
}) => {
const fixture = createMobilePosFixture();
await createOrderFromStep1(page, fixture, {
reg: "SEAL123",
reference: "SEAL-REF",
customerNumber: REGULAR_CUSTOMER_ID,
});
const orderId = Number(new URL(page.url()).searchParams.get("id"));
expect(orderId).toBeGreaterThan(0);
const safetySealInput = page.getByTestId("pos-mobile-safety-seal-step-2-input");
await expect(safetySealInput).toBeVisible({ timeout: 10_000 });
await safetySealInput.fill("SEAL-9001");
await safetySealInput.press("Tab");
await page.getByTestId("pos-mobile-next-step").click();
await expect.poll(() => fixture.requestCounters.markAsCompleted, { timeout: 10_000 }).toBe(1);
await expect(fixture.markCompletedOrderIds).toContain(orderId);
await expect
.poll(() => fixture.ordersById[orderId]?.safety_seal ?? "", { timeout: 10_000 })
.toBe("SEAL-9001");
await expect
.poll(
() =>
Boolean(
fixture.attachmentsByOrderId[orderId]?.some(
(attachment) => String(attachment?.content?.other || "").toUpperCase() === "WASH_CERTIFICATE"
)
),
{ timeout: 10_000 }
)
.toBe(true);
});
});
function fixtureProduct(productId) {