import { expect, test } from "@playwright/test"; import { mockConfig, mockHouseholdAndStoreShell, seedAuthStorage, } from "./helpers/e2e"; test("assigned items render selected users and keep the picker menu outside the modal", async ({ page }) => { await seedAuthStorage(page, { username: "assignment-user" }); await mockConfig(page); const members = [ { id: 1, username: "owner", name: "Owner User", display_name: "Owner User", role: "owner" }, { id: 2, username: "casey", name: "Casey Client", display_name: "Casey Client", role: "member" }, { id: 3, username: "jordan", name: "Jordan Client", display_name: "Jordan Client", role: "member" }, { id: 4, username: "alex", name: "Alex Member", display_name: "Alex Member", role: "member" }, { id: 5, username: "morgan", name: "Morgan Member", display_name: "Morgan Member", role: "member" }, { id: 6, username: "sam", name: "Sam Member", display_name: "Sam Member", role: "member" }, { id: 7, username: "jamie", name: "Jamie Member", display_name: "Jamie Member", role: "member" }, { id: 8, username: "pat", name: "Pat Member", display_name: "Pat Member", role: "member" }, { id: 9, username: "drew", name: "Drew Member", display_name: "Drew Member", role: "member" }, { id: 10, username: "kai", name: "Kai Member", display_name: "Kai Member", role: "member" }, { id: 11, username: "blair", name: "Blair Member", display_name: "Blair Member", role: "member" }, { id: 12, username: "quinn", name: "Quinn Member", display_name: "Quinn Member", role: "member" }, { id: 13, username: "rowan", name: "Rowan Member", display_name: "Rowan Member", role: "member" }, { id: 14, username: "sage", name: "Sage Member", display_name: "Sage Member", role: "member" }, { id: 15, username: "taylor", name: "Taylor Member", display_name: "Taylor Member", role: "member" }, { id: 16, username: "river", name: "River Member", display_name: "River Member", role: "member" }, ]; let listItems: Array<{ id: number; item_id: number; item_name: string; quantity: number; bought: boolean; item_image: string | null; image_mime_type: string | null; added_by_users: string[]; last_added_on: string; item_type: string | null; item_group: string | null; zone: string | null; }> = []; let addCallCount = 0; await mockHouseholdAndStoreShell(page, { household: { name: "Assignment House" }, }); await page.route("**/households/1/members", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(members), }); }); await page.route("**/households/1/stores/10/list/recent", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify([]), }); }); await page.route("**/households/1/stores/10/list/suggestions**", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify([]), }); }); await page.route("**/households/1/stores/10/list/item**", async (route) => { const url = new URL(route.request().url()); const itemName = (url.searchParams.get("item_name") || "").toLowerCase(); const item = listItems.find((candidate) => candidate.item_name === itemName); await route.fulfill({ status: item ? 200 : 404, contentType: "application/json", body: JSON.stringify(item || { message: "Item not found" }), }); }); await page.route("**/households/1/stores/10/list/add", async (route) => { addCallCount += 1; if (addCallCount === 1) { listItems = [ { id: 201, item_id: 501, item_name: "bananas", quantity: 1, bought: false, item_image: null, image_mime_type: null, added_by_users: ["Casey Client"], last_added_on: "2026-03-28T12:00:00.000Z", item_type: null, item_group: null, zone: null, }, ]; } else { listItems = [ { id: 201, item_id: 501, item_name: "bananas", quantity: 2, bought: false, item_image: null, image_mime_type: null, added_by_users: ["Casey Client", "Jordan Client"], last_added_on: "2026-03-28T12:05:00.000Z", item_type: null, item_group: null, zone: null, }, ]; } await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ message: addCallCount === 1 ? "Item added" : "Item updated", item: { id: 201, item_name: "bananas", quantity: addCallCount === 1 ? 1 : 2, bought: false, }, }), }); }); await page.route("**/households/1/stores/10/list", async (route) => { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ items: listItems }), }); }); await page.goto("/"); await expect(page.getByRole("heading", { name: "Grocery List" })).toBeVisible(); await page.getByPlaceholder("Enter item name").fill("bananas"); await page.getByRole("button", { name: "Others" }).click(); const assignModal = page.locator(".assign-item-for-modal"); await expect(assignModal).toBeVisible(); await assignModal.locator(".assign-item-for-dropdown-trigger").click(); const portalMenu = page.locator("body > .assign-item-for-dropdown-menu"); await expect(portalMenu).toBeVisible(); await expect(page.locator(".assign-item-for-modal .assign-item-for-dropdown-menu")).toHaveCount(0); const dropdownMetrics = await portalMenu.evaluate((element) => { const menu = element as HTMLDivElement; return { position: window.getComputedStyle(menu).position, scrollable: menu.scrollHeight > menu.clientHeight, }; }); expect(dropdownMetrics.position).toBe("fixed"); expect(dropdownMetrics.scrollable).toBe(true); await portalMenu.getByRole("option", { name: "Casey Client" }).click(); await expect(portalMenu).toHaveCount(0); await assignModal.getByRole("button", { name: "Confirm" }).click(); await expect(assignModal).toHaveCount(0); await expect(page.getByText("Adding for: Casey Client")).toBeVisible(); await page.getByRole("button", { name: "Create + Add" }).click(); await page.getByRole("button", { name: "Skip All" }).click(); const bananasRow = page.locator(".glist-li").filter({ hasText: "bananas" }); await expect(bananasRow).toContainText("Casey Client"); await expect(page.locator(".action-toast.action-toast-success")).toContainText("Added item"); await page.getByPlaceholder("Enter item name").fill("bananas"); await page.getByRole("button", { name: "Others" }).click(); await assignModal.locator(".assign-item-for-dropdown-trigger").click(); await portalMenu.getByRole("option", { name: "Jordan Client" }).click(); await expect(portalMenu).toHaveCount(0); await assignModal.getByRole("button", { name: "Confirm" }).click(); await expect(assignModal).toHaveCount(0); await expect(page.getByText("Adding for: Jordan Client")).toBeVisible(); await page.getByRole("button", { name: "Create + Add" }).click(); await page.getByRole("button", { name: "Update Quantity" }).click(); await expect(bananasRow).toContainText("Casey Client"); await expect(bananasRow).toContainText("Jordan Client"); await expect( page.locator(".action-toast.action-toast-success").filter({ hasText: "Updated item quantity" }) ).toContainText("Updated item quantity"); });