From 1d6c5f051eafaf39ca4065d892fab5d4aed1a925 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sun, 16 Aug 2026 19:02:02 +0200 Subject: [PATCH] =?UTF-8?q?fix(plex):=20address=20S3=20review=20nits=20?= =?UTF-8?q?=E2=80=94=20tests=20+=20narrow-header=20wrap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add PlexScopeToggle.dom.test.tsx (renders the three scopes, current one pressed, click writes scope back to the provider) and usePlexActiveFilters.dom.test.tsx (emits filter + watch-state chips but never a sort chip, even with a non-default sort active) — the S3 relocation was untested. - Narrow-width header: make the header row flex-wrap so the scope toggle drops to a second line instead of crowding the flex-1 search box to zero width, and let the field-scope pill shrink/truncate. Desktop stays a single line (verified: 1280px header unchanged, search 237px, no wrap). The removed one-click sort-reset chip is intended (sort is an always-visible control now, like the Feed) — no change. FE suite 174 green; typecheck + eslint clean. --- frontend/src/components/Header.tsx | 2 +- .../components/PlexScopeToggle.dom.test.tsx | 50 +++++++++++++++++++ frontend/src/components/PlexSearchBox.tsx | 4 +- .../usePlexActiveFilters.dom.test.tsx | 43 ++++++++++++++++ 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 frontend/src/components/PlexScopeToggle.dom.test.tsx create mode 100644 frontend/src/components/usePlexActiveFilters.dom.test.tsx diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index bfa6fbca..3d2498a1 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -94,7 +94,7 @@ export default function Header({ // Absolutely positioned within the (relative) content column, so its left edge tracks the // actual left zone: it sits just inside the content, reclaiming the space when the nav rail is // slim and/or no filter sidebar is present — no hard-coded offset. -
+
{ + const actual = await importOriginal(); + return { ...actual, useTranslation: () => ({ t: (key: string) => key }) }; +}); + +const plexState = { scope: "both" } as { scope: string }; +const setScope = vi.fn(); +vi.mock("./PlexProvider", () => ({ + usePlex: () => plexState, + usePlexActions: () => ({ setScope }), +})); + +import PlexScopeToggle from "./PlexScopeToggle"; + +beforeEach(() => { + plexState.scope = "both"; + setScope.mockReset(); +}); +afterEach(cleanup); + +describe("PlexScopeToggle", () => { + it("renders the three library scopes, current one pressed", () => { + plexState.scope = "movie"; + render(); + const group = screen.getByRole("group", { name: "plex.filter.scope" }); + const btns = [...group.querySelectorAll("button")]; + expect(btns.map((b) => b.textContent)).toEqual([ + "plex.filter.scopeOpt.both", + "plex.filter.scopeOpt.movie", + "plex.filter.scopeOpt.show", + ]); + const pressed = btns.filter((b) => b.getAttribute("aria-pressed") === "true"); + expect(pressed.map((b) => b.textContent)).toEqual(["plex.filter.scopeOpt.movie"]); + }); + + it("writes the picked scope back to the provider", () => { + render(); + fireEvent.click(screen.getByRole("button", { name: "plex.filter.scopeOpt.show" })); + expect(setScope).toHaveBeenCalledWith("show"); + }); +}); diff --git a/frontend/src/components/PlexSearchBox.tsx b/frontend/src/components/PlexSearchBox.tsx index 69311b42..c6fc3e8f 100644 --- a/frontend/src/components/PlexSearchBox.tsx +++ b/frontend/src/components/PlexSearchBox.tsx @@ -117,10 +117,10 @@ export default function PlexSearchBox() { leading={ - {pillLabel} + {pillLabel}