85 lines
4.3 KiB
JavaScript
85 lines
4.3 KiB
JavaScript
/**
|
|
* Browser test for the storefront widget against tests/e2e/server.ts.
|
|
* node tests/e2e/widget.e2e.mjs (needs `npm i -D playwright` and the harness running)
|
|
*/
|
|
import { chromium } from "playwright";
|
|
import assert from "node:assert/strict";
|
|
|
|
const BASE = process.env.BASE ?? "http://localhost:4545";
|
|
const SHOTS = process.env.SHOTS ?? "/tmp";
|
|
const browser = await chromium.launch({ executablePath: process.env.CHROMIUM ?? undefined });
|
|
const page = await browser.newPage({ viewport: { width: 520, height: 1100 } });
|
|
const errors = [];
|
|
page.on("pageerror", (e) => errors.push(e.message));
|
|
const cart = () => page.evaluate(() => fetch("/cart.js").then((r) => r.json()));
|
|
const step = (s) => console.log("•", s);
|
|
|
|
await fetch(`${BASE}/__reset`);
|
|
await page.goto(`${BASE}/cart`);
|
|
await page.waitForSelector(".ss-methods");
|
|
|
|
step("shipping is blocked by the fresh-flower rule, with the reason shown");
|
|
const ship = page.locator('.ss-method[data-v="shipping"]');
|
|
assert.equal(await ship.getAttribute("aria-disabled"), "true");
|
|
assert.match(await ship.innerText(), /Fresh flowers are pickup or local delivery only/);
|
|
|
|
step("checkout is stopped until a time is chosen");
|
|
await page.click('button[name="checkout"]');
|
|
assert.match(await page.locator(".ss-live").innerText(), /choose a delivery or pickup time/i);
|
|
assert.equal(await page.locator("#checkedout").innerText(), "");
|
|
|
|
step("delivery: postal code → zone fee → pick first date and slot → hold");
|
|
await page.click('.ss-method[data-v="delivery"]');
|
|
await page.waitForSelector(".ss-postal");
|
|
await page.fill(".ss-postal input", "N2H 5Z6");
|
|
await page.click(".ss-postal button");
|
|
await page.waitForSelector(".ss-day.ss-avail");
|
|
await page.locator(".ss-day.ss-avail").first().click();
|
|
await page.locator('.ss-slot:not([aria-disabled="true"])').first().click();
|
|
await page.waitForSelector("[data-ss-timer]");
|
|
let c = await cart();
|
|
const sel = JSON.parse(c.attributes._datewise);
|
|
assert.equal(sel.m, "delivery");
|
|
const fees = c.items.filter((i) => i.properties._datewise_fee);
|
|
assert.equal(fees.length, 1, "exactly one fee line");
|
|
assert.equal(fees[0].final_price, sel.f, "fee line matches the quote");
|
|
assert.ok(c.attributes["Local delivery date"], "readable attribute for staff");
|
|
await page.screenshot({ path: `${SHOTS}/e2e-held.png`, fullPage: true });
|
|
|
|
step("a rival shopper takes the last place in that slot; ours stays held");
|
|
const rival = await (await fetch(`${BASE}/__rival-hold`, { method: "POST", body: JSON.stringify({ method: "delivery", locationId: sel.l, date: sel.d, slot: sel.s, postal: "N2H 5Z6" }) })).json();
|
|
assert.equal(rival.ok, true, "rival gets the 2nd of 2 places");
|
|
const rival2 = await (await fetch(`${BASE}/__rival-hold`, { method: "POST", body: JSON.stringify({ method: "delivery", locationId: sel.l, date: sel.d, slot: sel.s, postal: "N2H 5Z6" }) })).json();
|
|
assert.equal(rival2.ok, false, "third shopper is refused");
|
|
|
|
step("theme changes the cart quantity → widget re-checks and keeps the still-valid hold");
|
|
await page.locator("[data-k]").nth(2).click(); // + on the second line
|
|
await page.waitForTimeout(1200);
|
|
c = await cart();
|
|
assert.ok(c.attributes._datewise, "selection kept");
|
|
|
|
step("switching to pickup releases the delivery time and removes the fee");
|
|
await page.click('.ss-method[data-v="pickup"]');
|
|
await page.waitForTimeout(1500);
|
|
c = await cart();
|
|
assert.equal(c.attributes._datewise, undefined);
|
|
assert.equal(c.items.filter((i) => i.properties._datewise_fee).length, 0);
|
|
|
|
step("pickup hold → checkout goes through with the selection attached");
|
|
await page.locator(".ss-day.ss-avail").first().click();
|
|
await page.locator('.ss-slot:not([aria-disabled="true"])').first().click();
|
|
await page.waitForSelector("[data-ss-timer]");
|
|
await page.click('button[name="checkout"]');
|
|
await page.waitForFunction(() => document.getElementById("checkedout").textContent.startsWith("CHECKOUT"));
|
|
assert.match(await page.locator("#checkedout").innerText(), /"m\\?":\\?"pickup/);
|
|
await page.screenshot({ path: `${SHOTS}/e2e-pickup.png`, fullPage: true });
|
|
|
|
step("keyboard: arrow keys move between calendar days");
|
|
await page.locator(".ss-day[tabindex='0']").focus();
|
|
await page.keyboard.press("ArrowRight");
|
|
assert.equal(await page.evaluate(() => document.activeElement.classList.contains("ss-day")), true);
|
|
|
|
assert.deepEqual(errors, [], "no page errors");
|
|
console.log("\nAll widget checks passed");
|
|
await browser.close();
|