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 @@ } -

Favorites

- -

Dishes

-{#if favorites.filter(isDish).length === 0} -

No favorite dishes yet.

-{/if} - - -

Dining Halls

-{#if favorites.filter(isLocation).length === 0} -

No favorite dining halls yet.

-{/if} - +
+

Favorites

+
+
+ +
+

Dishes

+
+ + {#if favorites.filter(isDish).length === 0} +
+

No favorite dishes yet.

+
+ {:else} + + {/if} +
+ +
+

Dining Halls

+
+ + {#if favorites.filter(isLocation).length === 0} +
+

No favorite dining halls yet.

+
+ {:else} + + {/if} +
diff --git a/web/src/routes/filters/+page.svelte b/web/src/routes/filters/+page.svelte index 2c0f47d9..eeba5306 100644 --- a/web/src/routes/filters/+page.svelte +++ b/web/src/routes/filters/+page.svelte @@ -32,39 +32,72 @@ } -

Dietary Filters

-

Applied to menus on the dining hall pages. Stored on this device only.

+
+

Dietary Filters

+
+

+ Applied to menus on the dining hall pages. Stored on this device only. +

+
-{#if saved}

Saved

{/if} - -

Avoid allergens

-{#if data.allergenOptions.length === 0} -

No allergen data found on today's menus.

+{#if saved} +

Saved

{/if} - -

Require diet tags

-{#if data.dietTagOptions.length === 0} -

No diet-tag data found on today's menus.

-{/if} - +
+

Avoid allergens

+
+ + {#if data.allergenOptions.length === 0} +
+

No allergen data found on today's menus.

+
+ {:else} + + {/if} +
+ +
+

Require diet tags

+
+ + {#if data.dietTagOptions.length === 0} +
+

No diet-tag data found on today's menus.

+
+ {:else} + + {/if} +
- +