| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- import { test, expect } from "@playwright/test";
- import AxeBuilder from "@axe-core/playwright";
- const product = "/product/the-original-salted-egg-cornflakes-clan";
- test("bag quantities, subtotal, persistence and removal", async ({ page }) => {
- await page.goto("/");
- await page
- .getByRole("button", {
- name: "Quick add The Original Salted Egg Cornflakes 180g",
- exact: true,
- })
- .click();
- let dialog = page.getByRole("dialog");
- await expect(dialog).toBeVisible();
- await expect(dialog).toContainText("RM 17.90");
- await dialog
- .getByRole("button", {
- name: "Increase The Original Salted Egg Cornflakes",
- })
- .click();
- await expect(dialog).toContainText("RM 35.80");
- await page.keyboard.press("Escape");
- await page.reload();
- await page.getByRole("button", { name: "Open shopping bag (2)" }).click();
- await expect(dialog).toContainText("RM 35.80");
- await dialog.getByRole("link", { name: "View your bag" }).click();
- await expect(page).toHaveURL("/cart");
- await page
- .getByRole("button", {
- name: "Remove The Original Salted Egg Cornflakes",
- exact: true,
- })
- .click();
- await expect(
- page.getByRole("heading", { name: "Your cart is empty" }),
- ).toBeVisible();
- });
- test("wishlist persists and can be removed", async ({ page }) => {
- await page.goto("/");
- await page
- .getByRole("button", {
- name: "Save The Original Salted Egg Cornflakes to wishlist",
- exact: true,
- })
- .click();
- await page.goto("/wishlist");
- await expect(page.locator(".product-card")).toHaveCount(1);
- await page
- .getByRole("button", {
- name: "Remove The Original Salted Egg Cornflakes from wishlist",
- exact: true,
- })
- .click();
- await expect(
- page.getByRole("heading", { name: "A little room for favourites" }),
- ).toBeVisible();
- });
- test("filters, sorting, load more and no results", async ({ page }) => {
- await page.goto("/shop");
- await expect(page.locator(".product-card")).toHaveCount(12);
- await page.getByRole("button", { name: "LOAD MORE" }).click();
- await expect(page.locator(".product-card")).toHaveCount(13);
- await page.getByRole("button", { name: "Tempeh chips", exact: true }).click();
- await expect(page.locator(".product-card")).toHaveCount(2);
- await page.getByRole("button", { name: "All snacks", exact: true }).click();
- await page.getByLabel("Sort by").selectOption("low");
- await expect(page.locator(".product-card").first()).toContainText("RM 3.50");
- await page
- .getByRole("searchbox", { name: "Search products" })
- .fill("nothingmatches");
- await expect(
- page.getByRole("heading", { name: "No snacks found" }),
- ).toBeVisible();
- await page.getByRole("button", { name: "Clear filters" }).click();
- await expect(page.locator(".result-count")).toContainText("13 snacks");
- });
- test("search returns products and journal articles and restores focus", async ({
- page,
- }) => {
- await page.goto("/");
- const trigger = page.getByRole("button", { name: "Search", exact: true });
- await trigger.click();
- const search = page.getByRole("searchbox", {
- name: "Search snacks, collections and stories",
- });
- await search.fill("mushroom");
- await expect(page.locator(".search-results>a")).toHaveCount(3);
- await search.fill("Mauritius");
- await expect(
- page.getByRole("link", { name: "Journal: Mauritius, We’ve Arrived" }),
- ).toBeVisible();
- await page.keyboard.press("Escape");
- await expect(trigger).toBeFocused();
- await trigger.click();
- await page.getByRole("searchbox").fill("tempeh");
- await page.getByRole("button", { name: "View all search results" }).click();
- await expect(page).toHaveURL("/shop?q=tempeh");
- await expect(page.locator(".product-card")).toHaveCount(2);
- });
- test("gallery, quantity, alternate packs and checkout preview", async ({
- page,
- }) => {
- await page.goto(product);
- await page
- .getByRole("button", { name: "View product image 2", exact: true })
- .click();
- await expect(page.locator(".gallery-main img")).toHaveAttribute(
- "src",
- "/images/snack-23-1.webp",
- );
- await page.getByRole("button", { name: "Zoom product image" }).click();
- await expect(page.getByRole("dialog")).toBeVisible();
- await page.keyboard.press("Escape");
- await page.getByRole("button", { name: "Increase Quantity" }).click();
- await page.getByRole("button", { name: "BUY NOW" }).click();
- await expect(page).toHaveURL("/checkout");
- await expect(page.locator(".checkout-layout")).toContainText("RM 35.80");
- await expect(page.getByRole("radio", { name: /Credit \/ debit card/ })).toBeChecked();
- await expect(page.locator(".checkout-order-summary .checkout-subtotal")).toContainText("RM 40.80");
- });
- test("mobile navigation and filter panel", async ({ page }) => {
- await page.setViewportSize({ width: 390, height: 844 });
- await page.goto("/");
- await page.getByRole("button", { name: "Open menu" }).click();
- await page
- .getByRole("dialog")
- .getByRole("link", { name: "Shop", exact: true })
- .click();
- await expect(page).toHaveURL("/shop");
- await expect(page.getByRole("dialog")).toHaveCount(0);
- await page.getByRole("button", { name: "Filters", exact: true }).click();
- await page.getByLabel("Pack size").selectOption("Fun pack");
- await expect(page.locator(".product-card")).toHaveCount(2);
- });
- test("contact validation and honest email preparation state", async ({
- page,
- }) => {
- await page.goto("/contact");
- await page.getByRole("button", { name: "SEND MESSAGE" }).click();
- await expect(page.locator("input[name=name]")).toBeFocused();
- await page.getByLabel("Your name").fill("Test Customer");
- await page
- .getByLabel("Email address", { exact: true })
- .first()
- .fill("customer@example.com");
- await page
- .getByLabel("Your message")
- .fill("I would like to ask about product ingredients.");
- await page.getByRole("button", { name: "SEND MESSAGE" }).click();
- await expect(page.locator(".form-status")).toContainText(
- "Send it there to reach ADUCKTIVE",
- );
- });
- test("newsletter validates email and does not claim a subscription", async ({
- page,
- }) => {
- await page.goto("/");
- await page.locator("#newsletter-email").fill("snacker@example.com");
- await page.getByRole("button", { name: "Subscribe to newsletter" }).click();
- await expect(page.locator(".newsletter [role=status]")).toContainText(
- "Send it to ask our team to subscribe you",
- );
- });
- test("journal filtering and article navigation", async ({ page }) => {
- await page.goto("/journal");
- await page
- .getByRole("searchbox", { name: "Search journal" })
- .fill("Mauritius");
- await expect(page.locator(".featured-article")).toContainText("Mauritius");
- await page.locator(".featured-article").click();
- await expect(page.getByRole("heading", { level: 1 })).toHaveText(
- "Mauritius, We’ve Arrived",
- );
- await expect(page.locator(".article-body")).toContainText("official debut");
- });
- test("major routes render without browser errors and respect every target width", async ({
- page,
- }) => {
- const errors: string[] = [];
- page.on("pageerror", (e) => errors.push(e.message));
- for (const width of [320, 390, 768, 1024, 1200, 1440]) {
- await page.setViewportSize({ width, height: 900 });
- for (const route of [
- "/",
- "/shop",
- "/collections",
- product,
- "/about",
- "/contact",
- "/journal",
- "/journal/90",
- "/cart",
- "/checkout",
- "/account",
- "/help/faq",
- "/help/shipping",
- "/help/returns",
- "/help/privacy",
- "/help/terms",
- ]) {
- await page.goto(route);
- await expect(
- page
- .getByRole("heading", { level: 1 })
- .or(page.getByRole("heading", { name: "Your cart is empty" }))
- .first(),
- ).toBeVisible();
- const overflow = await page.evaluate(
- () => document.documentElement.scrollWidth > innerWidth + 1,
- );
- expect(overflow, `${route} at ${width}px`).toBe(false);
- }
- }
- expect(errors).toEqual([]);
- });
- test("core pages pass automated WCAG checks", async ({ page }) => {
- await page.emulateMedia({ reducedMotion: "reduce" });
- for (const route of ["/", "/shop", product, "/contact", "/cart"]) {
- await page.goto(route);
- const result = await new AxeBuilder({ page })
- .withTags(["wcag2a", "wcag2aa", "wcag21aa"])
- .analyze();
- expect(
- result.violations.map((v) => ({
- id: v.id,
- nodes: v.nodes.map((n) => n.target),
- })),
- route,
- ).toEqual([]);
- }
- });
-
- test("scroll reveals appear and respect reduced-motion preferences", async ({
- page,
- }) => {
- await page.emulateMedia({ reducedMotion: "no-preference" });
- await page.goto("/");
- const story = page.locator(".story-copy");
- await expect(story).toHaveCSS("opacity", "0");
- await story.scrollIntoViewIfNeeded();
- await expect(story).toHaveCSS("opacity", "1");
- await page.emulateMedia({ reducedMotion: "reduce" });
- await page.reload();
- await expect(story).toHaveCSS("opacity", "1");
- await expect(page.locator(".pack-original")).toHaveCSS(
- "animation-name",
- "none",
- );
- });
-
- test("shop dropdown supports keyboard dismissal, outside click and category navigation", async ({ page }) => {
- await page.goto("/");
- const trigger = page.getByRole("button", { name: "Shop", exact: true });
- await trigger.focus();
- await page.keyboard.press("Enter");
- await expect(trigger).toHaveAttribute("aria-expanded", "true");
- await page.keyboard.press("Tab");
- await expect(page.locator("#desktop-shop-links a").first()).toBeFocused();
- await page.keyboard.press("Escape");
- await expect(trigger).toBeFocused();
- await expect(trigger).toHaveAttribute("aria-expanded", "false");
- await trigger.click();
- await page.locator("h1").click();
- await expect(trigger).toHaveAttribute("aria-expanded", "false");
- await trigger.click();
- await page.locator("#desktop-shop-links").getByRole("link", { name: "Tempeh chips" }).click();
- await expect(page).toHaveURL("/shop?category=Tempeh%20chips");
- await expect(page.locator(".product-card")).toHaveCount(2);
- await expect(trigger).toHaveAttribute("aria-expanded", "false");
- });
-
- test("mobile shop categories expand and close the drawer on selection", async ({ page }) => {
- await page.setViewportSize({ width: 390, height: 844 });
- await page.goto("/");
- await page.getByRole("button", { name: "Open menu" }).click();
- await page.getByRole("button", { name: "Shop categories" }).click();
- await page.locator("#mobile-shop-links").getByRole("link", { name: "Cornflakes", exact: true }).click();
- await expect(page).toHaveURL("/shop?category=Cornflakes");
- await expect(page.getByRole("dialog")).toHaveCount(0);
- await expect(page.getByLabel("Main navigation")).toBeHidden();
- });
-
- test("checkout preview supports delivery, payment, review and completion", async ({ page }) => {
- await page.goto(product);
- await page.getByRole("button", { name: "BUY NOW" }).click();
- await page.getByRole("button", { name: "REVIEW ORDER", exact: true }).click();
- await page.getByRole("button", { name: "SAVE ADDRESS" }).click();
- await expect(page.getByLabel("Full name", { exact: true })).toBeFocused();
- await page.getByLabel("Full name", { exact: true }).fill("Test Snacker");
- await page.getByLabel("Phone number", { exact: true }).fill("0123456789");
- await page.getByLabel("Street address", { exact: true }).fill("12 Test Street");
- await page.getByLabel("City", { exact: true }).fill("Subang Jaya");
- await page.getByLabel("Postcode", { exact: true }).fill("47500");
- await page.getByLabel("State / region", { exact: true }).fill("Selangor");
- await page.getByRole("button", { name: "SAVE ADDRESS" }).click();
- await expect(page.locator(".address-card")).toContainText("Test Snacker");
- await page.locator(".address-card button").click();
- await page.getByLabel("Full name", { exact: true }).fill("Unsaved edit");
- await page.keyboard.press("Escape");
- await expect(page.locator(".address-card")).toContainText("Test Snacker");
- await page.getByLabel("Voucher code").fill("SNACK10");
- await page.getByRole("button", { name: "Check code", exact: true }).click();
- await expect(page.locator(".checkout-option-note[role=status]")).toContainText("No discount has been applied");
- await page.getByRole("button", { name: "Increase The Original Salted Egg Cornflakes" }).click();
- await expect(page.locator(".checkout-order-summary .checkout-subtotal")).toContainText("RM 40.80");
- await page.getByRole("radio", { name: /Express delivery/ }).check();
- await expect(page.locator(".checkout-order-summary .checkout-subtotal")).toContainText("RM 45.80");
- await page.getByRole("radio", { name: /Online banking/ }).check();
- await page.getByRole("radio", { name: /E-wallet/ }).check();
- await page.getByRole("button", { name: "REVIEW ORDER", exact: true }).click();
- await expect(page.getByRole("dialog")).toContainText("Express delivery");
- await expect(page.getByRole("dialog")).toContainText("E-wallet");
- await expect(page.getByRole("dialog")).toContainText("RM 45.80");
- await expect(page.locator('.checkout-page a[href^="https:"]')).toHaveCount(0);
- await page.getByRole("button", { name: "COMPLETE CHECKOUT PREVIEW" }).click();
- await expect(page.getByRole("dialog")).toContainText("No order was placed, no payment was taken");
- await expect(page).toHaveURL("/checkout");
- await page.keyboard.press("Escape");
- await page.reload();
- await expect(page.locator(".address-card")).toContainText("Add a delivery address");
- await expect(page.locator(".checkout-card-stack")).not.toContainText("SNACK10");
- await page.getByRole("button", { name: "Remove The Original Salted Egg Cornflakes", exact: true }).click();
- await expect(page.getByRole("heading", { name: "Your cart is empty" })).toBeVisible();
- await expect(page.locator(".checkout-paybar")).toHaveCount(0);
- });
-
- test("local account forms validate and do not simulate authentication", async ({ page }) => {
- await page.goto("/account");
- await page.getByRole("link", { name: "CREATE AN ACCOUNT", exact: true }).click();
- await expect(page).toHaveURL("/register");
- await page.getByLabel("Full name", { exact: true }).fill("Test Snacker");
- await page.getByLabel("Email address", { exact: true }).fill("snacker@example.com");
- await page.getByLabel("Password", { exact: true }).fill("sample-password");
- await page.getByRole("button", { name: "Show password", exact: true }).click();
- await expect(page.locator("#club-password")).toHaveAttribute("type", "text");
- await page.getByLabel("Confirm password", { exact: true }).fill("different-password");
- await page.getByRole("button", { name: "CREATE AN ACCOUNT", exact: true }).click();
- await expect(page.locator("#club-confirm")).toBeFocused();
- expect(await page.locator("#club-confirm").evaluate((input: HTMLInputElement) => input.validity.customError)).toBe(true);
- await page.getByLabel("Confirm password", { exact: true }).fill("sample-password");
- await page.getByRole("button", { name: "CREATE AN ACCOUNT", exact: true }).click();
- await expect(page.locator(".club-form-status")).toContainText("no account has been created");
- await expect(page.locator("#club-password")).toHaveValue("");
- await page.getByRole("link", { name: "Log in", exact: true }).click();
- await expect(page).toHaveURL("/login");
- await page.getByLabel("Email address", { exact: true }).fill("snacker@example.com");
- await page.getByLabel("Password", { exact: true }).fill("sample-password");
- await page.getByRole("button", { name: "LOG IN", exact: true }).click();
- await expect(page.locator(".club-form-status")).toContainText("you haven’t been signed in");
- await expect(page.locator("#club-password")).toHaveValue("");
- await page.getByRole("link", { name: "Forgot your password?" }).click();
- await expect(page).toHaveURL("/forgot-password");
- await page.getByLabel("Email address", { exact: true }).fill("snacker@example.com");
- await page.getByRole("button", { name: "REQUEST PASSWORD RESET" }).click();
- await expect(page.locator(".club-form-status")).toContainText("no reset email has been sent");
- expect(await page.evaluate(() => JSON.stringify({...localStorage, ...sessionStorage}))).not.toContain("sample-password");
- });
|