grocery-app/frontend/tests/store-selector.spec.ts

154 lines
4.8 KiB
TypeScript

import { expect, test, type Page } from "@playwright/test";
import { mockConfig, seedAuthStorage } from "./helpers/e2e";
const household = { id: 1, name: "Selector House", role: "owner", invite_code: "ABCD1234" };
const user = { id: 1, username: "selector-user", role: "owner" };
async function mockGroceryShell(page: Page, stores: Array<Record<string, unknown>>) {
await seedAuthStorage(page, { username: "selector-user", role: "owner" });
await mockConfig(page);
await page.route("**/households", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify([household]),
});
});
await page.route("**/households/1/stores", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(stores),
});
});
await page.route("**/households/1/members", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify([user]),
});
});
await page.route("**/households/1/locations/*/zones", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ zones: [] }),
});
});
await page.route("**/households/1/locations/*/list/recent", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify([]),
});
});
await page.route("**/households/1/locations/*/list/suggestions**", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify([]),
});
});
await page.route("**/households/1/locations/*/list/item**", async (route) => {
await route.fulfill({
status: 404,
contentType: "application/json",
body: JSON.stringify({ message: "Item not found" }),
});
});
await page.route("**/households/1/locations/*/list", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ items: [] }),
});
});
}
test("grocery store selector shows one selected store and picks from a modal", async ({ page }) => {
await page.setViewportSize({ width: 473, height: 1000 });
await mockGroceryShell(page, [
{
id: 10,
household_store_id: 100,
name: "Costco",
location_name: "Eastvale",
display_name: "Costco - Eastvale",
is_default: true,
},
{
id: 11,
household_store_id: 200,
name: "99 Ranch",
location_name: "Eastvale",
display_name: "99 Ranch - Eastvale",
is_default: false,
},
{
id: 12,
household_store_id: 300,
name: "Stater Bros",
location_name: "Ontario Ranch",
display_name: "Stater Bros - Ontario Ranch",
is_default: false,
},
]);
await page.goto("/");
const selector = page.locator(".store-selector-trigger");
await expect(selector).toBeVisible();
await expect(selector).toContainText("Costco");
await expect(page.locator(".store-tabs")).not.toContainText("Eastvale");
await expect(page.locator(".store-tabs")).not.toContainText("99 Ranch");
await expect(page.locator(".store-tabs")).not.toContainText("Stater Bros");
await selector.click();
const modal = page.getByRole("dialog", { name: "Select store" });
await expect(modal).toBeVisible();
await expect(modal.getByRole("button", { name: "Costco" })).toBeVisible();
await expect(modal.getByRole("button", { name: "99 Ranch" })).toBeVisible();
await expect(modal.getByRole("button", { name: "Stater Bros" })).toBeVisible();
await expect(modal).not.toContainText("Eastvale");
await expect(modal).not.toContainText("Ontario Ranch");
await modal.getByRole("button", { name: "99 Ranch" }).click();
await expect(modal).toHaveCount(0);
await expect(selector).toContainText("99 Ranch");
await expect.poll(() => page.evaluate(() => localStorage.getItem("activeHouseholdStoreId_1"))).toBe("200");
await selector.click();
await expect(modal).toBeVisible();
await page.locator(".store-selector-modal-overlay").click({ position: { x: 4, y: 4 } });
await expect(modal).toHaveCount(0);
});
test("single grocery store selector click does not open picker modal", async ({ page }) => {
await mockGroceryShell(page, [
{
id: 10,
household_store_id: 100,
name: "Costco",
location_name: "Default Location",
display_name: "Costco",
is_default: true,
},
]);
await page.goto("/");
const selector = page.locator(".store-selector-trigger");
await expect(selector).toBeVisible();
await expect(selector).toContainText("Costco");
await selector.click();
await expect(page.getByRole("dialog", { name: "Select store" })).toHaveCount(0);
});