Files
pleno-vue/tests/e2e/userBookWash.spec.ts
T

213 lines
7.9 KiB
TypeScript

import { expect, test, type Page } from "@playwright/test";
import { bookingTestData } from "./fixtures";
import {
completeBookingCreationFlow,
fillBookingField,
goToBookingProductSelectionStep,
goToBookingProductSelectionStepWithOptions,
selectBookingDateTime,
} from "./support/bookingFlow";
import { mockApi, primeMockSession } from "./support/network.js";
import { isCompactProject } from "./support/projects";
async function prepareBookingPage(
page: Page,
pos: true | Record<string, unknown> = true,
sessionData: Record<string, unknown> = {}
) {
await mockApi(page, {
authenticated: true,
sessionData: {
display_name: "Booking User",
customer_number: 12345679,
permissions: ["user"],
...sessionData,
},
pos,
});
await primeMockSession(page, { bootPath: "/user" });
}
test("[BOOKINGS][User][Creation] should create a new booking", async ({ page }) => {
await prepareBookingPage(page);
await completeBookingCreationFlow(page, bookingTestData);
});
test("[BOOKINGS][User][Departments] should hide departments without time booking enabled", async ({
page,
}, testInfo) => {
await prepareBookingPage(page, {
departments: [
{
id: bookingTestData.departmentId,
name: "Bookable Demo",
description: "Bookable address",
exclude_from_invoicing: false,
bookingsystem_time_based_enabled: true,
},
{
id: 77,
name: "Disabled Booking Hall",
description: "Disabled address",
exclude_from_invoicing: false,
bookingsystem_time_based_enabled: false,
},
],
});
await page.goto("/user/bookings/book");
if (isCompactProject(testInfo)) {
const mobileTrigger = page.getByTestId("booking-mobile-department-trigger");
await expect(mobileTrigger).toBeVisible();
await mobileTrigger.click();
await expect(page.getByTestId(`booking-mobile-department-option-${bookingTestData.departmentId}`)).toBeVisible();
await expect(page.getByTestId("booking-mobile-department-option-77")).toHaveCount(0);
} else {
await expect(page.locator(`#department-option-${bookingTestData.departmentId}`)).toBeVisible();
await expect(page.locator("#department-option-77")).toHaveCount(0);
}
await expect(page.getByText("Disabled Booking Hall")).toHaveCount(0);
});
test("[BOOKINGS][User][Creation] should show interior wash products on the interior category", async ({ page }) => {
await prepareBookingPage(page);
await goToBookingProductSelectionStepWithOptions(page, bookingTestData, {
selectInitialProduct: false,
});
const interiorCategoryTab = page.locator('[data-testid="pos-product-category-tab-2"]:visible').first();
if ((await interiorCategoryTab.count()) > 0) {
await interiorCategoryTab.click();
} else {
await page.locator('[data-testid="pos-product-category-select"]:visible').first().selectOption("2");
}
const interiorProductCard = page.locator('[data-testid="pos-product-card-63"]:visible').first();
await expect(interiorProductCard).toBeVisible();
await expect(interiorProductCard).toContainText("Indvendig vask Forvogn");
});
test("[BOOKINGS][User][Creation] should show desktop loading states while categories and products resolve", async ({
page,
}, testInfo) => {
test.skip(!testInfo.project.name.toLowerCase().includes("desktop"), "Desktop only");
await prepareBookingPage(page, {
departmentCategoriesDelayMs: 700,
productsDelayMs: 900,
});
await goToBookingProductSelectionStepWithOptions(page, bookingTestData, {
selectInitialProduct: false,
});
await expect(page.locator('[data-testid="pos-product-categories-loading"]:visible').first()).toBeVisible();
await expect(page.locator('[data-testid="pos-products-loading"]:visible').first()).toBeVisible();
await expect(page.locator('[data-testid="pos-product-categories-loading"]:visible')).toHaveCount(0, {
timeout: 10_000,
});
await expect(page.locator('[data-testid="pos-product-card-53"]:visible').first()).toBeVisible({ timeout: 10_000 });
await expect(page.locator('[data-testid="pos-products-loading"]:visible')).toHaveCount(0, { timeout: 10_000 });
await page.locator('[data-testid="pos-product-category-tab-2"]:visible').first().click();
await expect(page.locator('[data-testid="pos-products-loading"]:visible').first()).toBeVisible();
await expect(page.locator('[data-testid="pos-product-card-63"]:visible').first()).toBeVisible({ timeout: 10_000 });
await expect(page.locator('[data-testid="pos-products-loading"]:visible')).toHaveCount(0, { timeout: 10_000 });
});
test("[BOOKINGS][User][Creation] should submit resolved wash certificate price for visible-price customers", async ({
page,
}) => {
await prepareBookingPage(
page,
{
extraProducts: [
{
id: 41,
name: "Vaskecertifikat",
description: "Wash certificate",
price: 0,
subscription_allowed: false,
category: 8,
piktogram: "certificate",
apply_category_discount: false,
requires_note: false,
is_wash: false,
display_in_booking_form: false,
order_priority: 5,
addons: [],
},
],
productFinalPricesById: {
41: 175,
},
},
{
permissions: ["user", "has_attribute_showPricesOnBookingPage"],
}
);
const { departmentId, registrationNumber, reference, poNumber, notes, mobileWizard } =
await goToBookingProductSelectionStepWithOptions(page, bookingTestData, {
selectInitialProduct: false,
});
const interiorCategoryTab = page.locator('[data-testid="pos-product-category-tab-2"]:visible').first();
if ((await interiorCategoryTab.count()) > 0) {
await interiorCategoryTab.click();
} else {
await page.locator('[data-testid="pos-product-category-select"]:visible').first().selectOption("2");
}
const interiorProductCard = page.locator('[data-testid="pos-product-card-63"]:visible').first();
await expect(interiorProductCard).toBeVisible();
await interiorProductCard.click();
await expect(page.locator("body")).toContainText("Vaskecertifikat");
await expect(page.locator("body")).toContainText(/175,00\s*kr\./);
if (mobileWizard) {
await expect(page.getByTestId("booking-mobile-next")).toBeEnabled();
await page.getByTestId("booking-mobile-next").click();
}
const selectedDateTime = await selectBookingDateTime(page);
await fillBookingField(page, "booking-reference-toggle", "booking-reference-input", reference);
await fillBookingField(page, "booking-po-toggle", "booking-po-input", poNumber);
await fillBookingField(page, "booking-notes-toggle", "booking-notes-input", notes);
if (mobileWizard) {
await page.check("#pickup-mobile");
await expect(page.getByTestId("booking-mobile-next")).toBeEnabled();
await page.getByTestId("booking-mobile-next").click();
} else {
await page.check("#pickup");
await page.click("#go-to-confirmation-button");
}
await expect(page.locator("#booking-summary-title")).toBeVisible();
await expect(page.getByTestId("booking-summary-date-time")).toContainText(selectedDateTime.summaryDateLabel);
const summaryOverlay = page.locator(".booking-summary-overlay:visible").first();
await expect(summaryOverlay).toContainText("Vaskecertifikat");
await expect(summaryOverlay).toContainText(/175,00\s*kr\./);
const [request] = await Promise.all([
page.waitForRequest((request) => request.method() === "POST" && request.url().includes("/order-bookings"), {
timeout: 10_000,
}),
summaryOverlay.getByTestId("booking-summary-confirm-body").click({ force: true }),
]);
const payload = request.postDataJSON();
const certificateItem = payload.items.find((item: { id?: number }) => Number(item.id) === 41);
expect(certificateItem).toBeTruthy();
expect(Number(certificateItem.price)).toBe(175);
expect(Number(certificateItem.quantity)).toBe(1);
expect(Number(payload.department)).toBe(departmentId);
expect(payload.reg_1).toBe(registrationNumber);
});