feat(chrome): shared account menu and global app header
Move account actions (Settings, Downloads, Display preferences, Sign out) out of the library-only header into a shared AccountMenu anchored in a global AppHeader, available on every authenticated non-immersive screen. Add a layoutShell helper deciding where chrome shows, expose serverName/serverUrl auth stores, and a display view-mode preference. The settings page also gains the UR-053 WiFi-only toggle. TRACES: UR-054 | DR-075, DR-076, DR-077
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Display preference (grid/list) is a second view onto the library `viewMode`
|
||||
* store. The Settings Display section and the library page-header toggle both
|
||||
* drive it via `library.setViewMode`, so verifying the store writes through and
|
||||
* persists covers the shared data path for both controls.
|
||||
*
|
||||
* TRACES: UR-029 | DR-077 | UT-*
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, beforeAll, afterAll, vi } from "vitest";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
const STORAGE_KEY = "jellytau-view-mode";
|
||||
|
||||
// jsdom here doesn't expose localStorage; stand in a minimal implementation.
|
||||
const backing = new Map<string, string>();
|
||||
const localStorageShim = {
|
||||
getItem: (key: string) => backing.get(key) ?? null,
|
||||
setItem: (key: string, value: string) => void backing.set(key, value),
|
||||
removeItem: (key: string) => void backing.delete(key),
|
||||
clear: () => backing.clear(),
|
||||
};
|
||||
|
||||
// The library store imports the auth store and tauri events at module load;
|
||||
// neither is exercised by these tests.
|
||||
vi.mock("@tauri-apps/api/event", () => ({
|
||||
listen: vi.fn(async () => () => {}),
|
||||
}));
|
||||
vi.mock("./auth", () => ({ auth: { getUserId: vi.fn() } }));
|
||||
|
||||
beforeAll(() => {
|
||||
vi.stubGlobal("localStorage", localStorageShim);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
describe("viewMode display preference", () => {
|
||||
beforeEach(() => {
|
||||
backing.clear();
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
it("setViewMode writes through to the derived store", async () => {
|
||||
const { library, viewMode } = await import("./library");
|
||||
library.setViewMode("list");
|
||||
expect(get(viewMode)).toBe("list");
|
||||
library.setViewMode("grid");
|
||||
expect(get(viewMode)).toBe("grid");
|
||||
});
|
||||
|
||||
it("setViewMode persists the choice to localStorage", async () => {
|
||||
const { library } = await import("./library");
|
||||
library.setViewMode("list");
|
||||
expect(backing.get(STORAGE_KEY)).toBe("list");
|
||||
});
|
||||
|
||||
it("a persisted list preference is restored on load", async () => {
|
||||
backing.set(STORAGE_KEY, "list");
|
||||
const { viewMode } = await import("./library");
|
||||
expect(get(viewMode)).toBe("list");
|
||||
});
|
||||
|
||||
it("defaults to grid when nothing is persisted", async () => {
|
||||
const { viewMode } = await import("./library");
|
||||
expect(get(viewMode)).toBe("grid");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user