diff --git a/web/e2e/favorites.spec.ts b/web/e2e/favorites.spec.ts index 0f13c6f3..55649948 100644 --- a/web/e2e/favorites.spec.ts +++ b/web/e2e/favorites.spec.ts @@ -54,7 +54,21 @@ test("favoriting a dish from the menu shows it on /favorites, un-favoriting remo const favoriteRow = page.getByRole("listitem").filter({ hasText: "French Toast" }); await expect(favoriteRow).toBeVisible(); + // #40: favorites list rows need the same card treatment as the other list screens (dining + // halls, hall menu) — a non-transparent surface visually distinct from the page background, + // not the page's `
` color leaking straight through into every row. + const pageBg = await page.evaluate(() => getComputedStyle(document.body).backgroundColor); + const rowBg = await favoriteRow.evaluate((el) => getComputedStyle(el).backgroundColor); + expect(rowBg).not.toBe("rgba(0, 0, 0, 0)"); + expect(rowBg).not.toBe(pageBg); + await favoriteRow.getByRole("button", { name: "Remove" }).click(); await expect(page.getByText("No favorite dishes yet.")).toBeVisible(); await expect(favoriteRow).toHaveCount(0); + + // #40: the empty state needs the shared dashed-outline `.empty-state` treatment used elsewhere + // in the app, not a bare unstyled paragraph — checked via the one CSS property that treatment + // actually produces, not by naming the class. + const emptyState = page.getByText("No favorite dishes yet.").locator("xpath=.."); + await expect(emptyState).toHaveCSS("border-style", "dashed"); }); diff --git a/web/e2e/filters.spec.ts b/web/e2e/filters.spec.ts index 32ffef9a..6da05a44 100644 --- a/web/e2e/filters.spec.ts +++ b/web/e2e/filters.spec.ts @@ -73,7 +73,16 @@ test("setting an allergen filter hides a conflicting dish and keeps a non-confli await page.getByRole("link", { name: "Filters" }).click(); + // #40: filters are toggle/checkbox-heavy and need a clear on/off state — a checked filter must + // be visually distinct from an unchecked one, not just carry a different checkbox attribute. + // Scoped through the checkbox's own accessible name (not a listitem text filter) so this stays + // unambiguous even if another allergen option's name contains "Milk" as a substring. + const milkLabel = page.getByRole("checkbox", { name: "Milk" }).locator("xpath=.."); + const milkBgBeforeCheck = await milkLabel.evaluate((el) => getComputedStyle(el).backgroundColor); + await page.getByRole("checkbox", { name: "Milk" }).check(); + await expect(milkLabel).not.toHaveCSS("background-color", milkBgBeforeCheck); + await page.getByRole("button", { name: "Save" }).click(); await expect(page.getByRole("status")).toHaveText("Saved"); diff --git a/web/src/routes/favorites/+page.svelte b/web/src/routes/favorites/+page.svelte index 8dc83cbc..ba695116 100644 --- a/web/src/routes/favorites/+page.svelte +++ b/web/src/routes/favorites/+page.svelte @@ -30,24 +30,47 @@ } -No favorite dishes yet.
-{/if} -No favorite dining halls yet.
-{/if} -No favorite dishes yet.
+No favorite dining halls yet.
+Applied to menus on the dining hall pages. Stored on this device only.
++ Applied to menus on the dining hall pages. Stored on this device only. +
+Saved
{/if} - -No allergen data found on today's menus.
+{#if saved} +Saved
{/if} -No diet-tag data found on today's menus.
-{/if} -No allergen data found on today's menus.
+No diet-tag data found on today's menus.
+