diff --git a/frontend/src/context/HouseholdContext.jsx b/frontend/src/context/HouseholdContext.jsx index 326a806..cedda4f 100644 --- a/frontend/src/context/HouseholdContext.jsx +++ b/frontend/src/context/HouseholdContext.jsx @@ -2,6 +2,8 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'rea import { createHousehold as createHouseholdApi, getUserHouseholds } from '../api/households'; import { AuthContext } from './AuthContext'; +const ACTIVE_HOUSEHOLD_STORAGE_KEY = 'activeHouseholdId'; + export const HouseholdContext = createContext({ households: [], activeHousehold: null, @@ -23,7 +25,7 @@ export const HouseholdProvider = ({ children }) => { const clearActiveHousehold = useCallback(() => { setActiveHouseholdState(null); - localStorage.removeItem('activeHouseholdId'); + localStorage.removeItem(ACTIVE_HOUSEHOLD_STORAGE_KEY); }, []); const loadHouseholds = useCallback(async () => { @@ -32,10 +34,8 @@ export const HouseholdProvider = ({ children }) => { setLoading(true); setError(null); try { - console.log('[HouseholdContext] Loading households...'); const response = await getUserHouseholds(); const nextHouseholds = Array.isArray(response.data) ? response.data : []; - console.log('[HouseholdContext] Loaded households:', nextHouseholds); setHouseholds(nextHouseholds); if (nextHouseholds.length === 0) { @@ -69,33 +69,30 @@ export const HouseholdProvider = ({ children }) => { // Load active household from localStorage on mount useEffect(() => { if (households.length === 0) { - clearActiveHousehold(); + setActiveHouseholdState(null); return; } - console.log('[HouseholdContext] Setting active household from:', households); - const savedHouseholdId = localStorage.getItem('activeHouseholdId'); + const savedHouseholdId = localStorage.getItem(ACTIVE_HOUSEHOLD_STORAGE_KEY); if (savedHouseholdId) { - const household = households.find(h => h.id === parseInt(savedHouseholdId, 10)); + const household = households.find((candidate) => String(candidate.id) === savedHouseholdId); if (household) { - console.log('[HouseholdContext] Found saved household:', household); setActiveHouseholdState(household); return; } } // No saved household or not found, use first one - console.log('[HouseholdContext] Using first household:', households[0]); setActiveHouseholdState(households[0]); - localStorage.setItem('activeHouseholdId', households[0].id); - }, [clearActiveHousehold, households]); + localStorage.setItem(ACTIVE_HOUSEHOLD_STORAGE_KEY, String(households[0].id)); + }, [households]); const setActiveHousehold = (household) => { setActiveHouseholdState(household); if (household) { - localStorage.setItem('activeHouseholdId', household.id); + localStorage.setItem(ACTIVE_HOUSEHOLD_STORAGE_KEY, String(household.id)); } else { - localStorage.removeItem('activeHouseholdId'); + localStorage.removeItem(ACTIVE_HOUSEHOLD_STORAGE_KEY); } }; diff --git a/frontend/tests/household-selection-persistence.spec.ts b/frontend/tests/household-selection-persistence.spec.ts new file mode 100644 index 0000000..04de148 --- /dev/null +++ b/frontend/tests/household-selection-persistence.spec.ts @@ -0,0 +1,103 @@ +import { expect, test } from "@playwright/test"; + +function seedAuthStorage(page: import("@playwright/test").Page) { + return page.addInitScript(() => { + localStorage.setItem("token", "test-token"); + localStorage.setItem("userId", "1"); + localStorage.setItem("role", "admin"); + localStorage.setItem("username", "persistent-user"); + }); +} + +async function mockConfig(page: import("@playwright/test").Page) { + await page.route("**/config", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ + maxFileSizeMB: 20, + maxImageDimension: 800, + imageQuality: 85, + }), + }); + }); +} + +test("selected household stays active after refreshing on settings and home pages", async ({ page }) => { + await seedAuthStorage(page); + await mockConfig(page); + + const households = [ + { id: 1, name: "Alpha Home", role: "owner" }, + { id: 2, name: "Bravo Home", role: "admin" }, + ]; + + const storesByHousehold = { + 1: [{ id: 101, name: "Costco", is_default: true }], + 2: [{ id: 201, name: "Trader Joe's", is_default: true }], + }; + + await page.route("**/households", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify(households), + }); + }); + + await page.route("**/stores/household/*", async (route) => { + const householdId = Number(route.request().url().split("/").pop()); + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify( + storesByHousehold[householdId as keyof typeof storesByHousehold] ?? [] + ), + }); + }); + + await page.route("**/households/*/stores/*/list/recent", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify([]), + }); + }); + + await page.route("**/households/*/stores/*/list", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ items: [] }), + }); + }); + + await page.route("**/households/*/members", async (route) => { + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify([{ id: 1, username: "persistent-user", role: "owner" }]), + }); + }); + + await page.goto("/"); + + await expect(page.getByRole("button", { name: "Alpha Home" })).toBeVisible(); + + await page.getByRole("button", { name: "Alpha Home" }).click(); + await page.getByRole("button", { name: "Bravo Home" }).click(); + + await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible(); + await expect.poll(() => page.evaluate(() => localStorage.getItem("activeHouseholdId"))).toBe("2"); + + await page.goto("/settings"); + await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible(); + + await page.reload(); + await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible(); + await expect.poll(() => page.evaluate(() => localStorage.getItem("activeHouseholdId"))).toBe("2"); + + await page.goto("/"); + await expect(page.getByRole("button", { name: "Bravo Home" })).toBeVisible(); + await expect(page.getByRole("button", { name: "Trader Joe's" })).toBeVisible(); +});