feat(nav): tabs, list views and name searches are named in the address
Settings, Configuration and Users name their tab (stab/cfgtab/utab); a link's tab wins and a tab pre-selected while its page is on screen now switches it. A playlist's sort, filters and grouping (plsort/plf/plgroup), the Files sort (fsort, always written) and the name searches of Channels, Files, Playlists and Plex (cq/fq/plq/pq+pqf) reopen from the address; the searches are written once the typing pauses.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// The URL is the view: a page's name search is named in the address, so a reload or a bookmark opens
|
||||
// the list searched (Channels, Files and Playlists kept it in memory only, Plex in this browser only).
|
||||
// The real navigation and the real stores, read through their hooks; only the network is absent.
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { cleanup, render, waitFor } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { useEffect } from "react";
|
||||
|
||||
vi.mock("react-i18next", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("react-i18next")>()),
|
||||
useTranslation: () => ({ t: (k: string) => k, i18n: { language: "en" } }),
|
||||
}));
|
||||
|
||||
import { NavigationProvider } from "./features/navigation/NavigationProvider";
|
||||
import { ModuleStores } from "./features/navigation/ModuleStores";
|
||||
import { useChannels } from "./modules/channels/channelsContext";
|
||||
import { useFiles } from "./modules/files/filesContext";
|
||||
import { usePlaylists } from "./modules/playlists/playlistsContext";
|
||||
import { usePlex } from "./modules/plex/plexContext";
|
||||
import { claimLocalData, getAccountRaw, LS, setAccountRaw } from "./lib/storage";
|
||||
|
||||
const seen: { current: Record<string, string> } = { current: {} };
|
||||
|
||||
function Probe() {
|
||||
const channels = useChannels();
|
||||
const files = useFiles();
|
||||
const playlists = usePlaylists();
|
||||
const plex = usePlex();
|
||||
useEffect(() => {
|
||||
seen.current = {
|
||||
channels: channels.search,
|
||||
files: files.search,
|
||||
playlists: playlists.search,
|
||||
plex: plex.q,
|
||||
plexField: plex.field,
|
||||
};
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
claimLocalData(3);
|
||||
});
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
window.history.replaceState(null, "", "/");
|
||||
});
|
||||
|
||||
function mountAt(url: string, page: string) {
|
||||
window.history.replaceState({ sfPage: page }, "", url);
|
||||
render(
|
||||
<QueryClientProvider client={new QueryClient()}>
|
||||
<NavigationProvider>
|
||||
<ModuleStores>
|
||||
<Probe />
|
||||
</ModuleStores>
|
||||
</NavigationProvider>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
const search = () => new URLSearchParams(window.location.search);
|
||||
|
||||
describe.each([
|
||||
["channels", "cq", "tom"],
|
||||
["files", "fq", "notes"],
|
||||
["playlists", "plq", "jazz"],
|
||||
["plex", "pq", "poirot"],
|
||||
])("%s's name search", (page, key, value) => {
|
||||
it("opens from the address, and stays in it", async () => {
|
||||
mountAt(`/?page=${page}&${key}=${value}`, page);
|
||||
await waitFor(() => expect(seen.current[page]).toBe(value));
|
||||
expect(search().get(key)).toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Plex's search", () => {
|
||||
it("is named in full, an empty one too: this browser remembers one a link must not inherit", async () => {
|
||||
setAccountRaw(LS.plexQ, "poirot");
|
||||
mountAt("/?page=plex&pq=", "plex");
|
||||
await waitFor(() => expect(seen.current.plex).toBe(""));
|
||||
expect(search().get("pq")).toBe("");
|
||||
});
|
||||
|
||||
it("takes the field a link names, and remembers the link's search", async () => {
|
||||
mountAt("/?page=plex&pq=hastings&pqf=people", "plex");
|
||||
await waitFor(() => expect(seen.current.plexField).toBe("people"));
|
||||
expect(seen.current.plex).toBe("hastings");
|
||||
await waitFor(() => expect(getAccountRaw(LS.plexQ)).toBe("hastings"));
|
||||
expect(search().get("pqf")).toBe("people");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user