/** * 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(".dw-methods"); step("shipping is blocked by the fresh-flower rule, with the reason shown"); const ship = page.locator('.dw-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(".dw-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('.dw-method[data-v="delivery"]'); await page.waitForSelector(".dw-postal"); await page.fill(".dw-postal input", "N2H 5Z6"); await page.click(".dw-postal button"); await page.waitForSelector(".dw-day.dw-avail"); await page.locator(".dw-day.dw-avail").first().click(); await page.locator('.dw-slot:not([aria-disabled="true"])').first().click(); await page.waitForSelector("[data-dw-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('.dw-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(".dw-day.dw-avail").first().click(); await page.locator('.dw-slot:not([aria-disabled="true"])').first().click(); await page.waitForSelector("[data-dw-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(".dw-day[tabindex='0']").focus(); await page.keyboard.press("ArrowRight"); assert.equal(await page.evaluate(() => document.activeElement.classList.contains("dw-day")), true); assert.deepEqual(errors, [], "no page errors"); console.log("\nAll widget checks passed"); await browser.close();