212 lines
7.4 KiB
TypeScript
212 lines
7.4 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/*/map", async (route) => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
location: stores.find((store) => String(store.id) === route.request().url().match(/locations\/(\d+)\/map/)?.[1]) || stores[0],
|
|
map: null,
|
|
draft_map: null,
|
|
published_map: null,
|
|
objects: [],
|
|
draft_objects: [],
|
|
published_objects: [],
|
|
zones: [],
|
|
items: [],
|
|
unmapped_count: 0,
|
|
can_manage: true,
|
|
}),
|
|
});
|
|
});
|
|
|
|
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: 13,
|
|
household_store_id: 100,
|
|
name: "Costco",
|
|
location_name: "Fontana",
|
|
display_name: "Costco - Fontana",
|
|
is_default: false,
|
|
},
|
|
{
|
|
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 storeSelector = page.locator(".store-selector-trigger").first();
|
|
const locationSelector = page.locator(".location-selector-trigger");
|
|
await expect(storeSelector).toBeVisible();
|
|
await expect(storeSelector).toContainText("Costco");
|
|
await expect(locationSelector).toBeVisible();
|
|
await expect(locationSelector).toContainText("Eastvale");
|
|
await expect(page.getByRole("button", { name: "Manage Map" })).toBeVisible();
|
|
await expect(page.locator(".store-tabs")).not.toContainText("Costco - Eastvale");
|
|
await expect(page.locator(".store-tabs")).not.toContainText("99 Ranch");
|
|
await expect(page.locator(".store-tabs")).not.toContainText("Stater Bros");
|
|
|
|
await storeSelector.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(storeSelector).toContainText("99 Ranch");
|
|
await expect(locationSelector).toContainText("Eastvale");
|
|
await expect.poll(() => page.evaluate(() => localStorage.getItem("activeHouseholdStoreId_1"))).toBe("200");
|
|
await expect.poll(() => page.evaluate(() => localStorage.getItem("activeStoreLocationId_1_200"))).toBe("11");
|
|
|
|
await storeSelector.click();
|
|
await expect(modal).toBeVisible();
|
|
await page.locator(".store-selector-modal-overlay").click({ position: { x: 4, y: 4 } });
|
|
await expect(modal).toHaveCount(0);
|
|
|
|
await storeSelector.click();
|
|
await modal.getByRole("button", { name: "Costco" }).click();
|
|
await locationSelector.click();
|
|
const locationModal = page.getByRole("dialog", { name: "Select location" });
|
|
await expect(locationModal).toBeVisible();
|
|
await expect(locationModal.getByRole("button", { name: "Eastvale" })).toBeVisible();
|
|
await expect(locationModal.getByRole("button", { name: "Fontana" })).toBeVisible();
|
|
await expect(locationModal).not.toContainText("Costco - Eastvale");
|
|
|
|
await locationModal.getByRole("button", { name: "Fontana" }).click();
|
|
await expect(locationModal).toHaveCount(0);
|
|
await expect(storeSelector).toContainText("Costco");
|
|
await expect(locationSelector).toContainText("Fontana");
|
|
await expect.poll(() => page.evaluate(() => localStorage.getItem("activeHouseholdStoreId_1"))).toBe("100");
|
|
await expect.poll(() => page.evaluate(() => localStorage.getItem("activeStoreLocationId_1_100"))).toBe("13");
|
|
|
|
await page.getByRole("button", { name: "Manage Map" }).click();
|
|
await expect(page).toHaveURL(/\/stores\/100\/locations\/13\/map$/);
|
|
});
|
|
|
|
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 storeSelector = page.locator(".store-selector-trigger").first();
|
|
const locationSelector = page.locator(".location-selector-trigger");
|
|
await expect(storeSelector).toBeVisible();
|
|
await expect(storeSelector).toContainText("Costco");
|
|
await expect(locationSelector).toBeVisible();
|
|
await expect(locationSelector).toContainText("Default");
|
|
await storeSelector.click();
|
|
await expect(page.getByRole("dialog", { name: "Select store" })).toHaveCount(0);
|
|
await locationSelector.click();
|
|
await expect(page.getByRole("dialog", { name: "Select location" })).toHaveCount(0);
|
|
});
|