- App.svelte: new 'settings' view with account/actions/about sections, sign-out button, pdsBase()/appviewBase() helpers, showError wired into logout, profile gains open-in-browser + sign-out + recent-posts heading - NavRail: add settings item + gear icon, View union extended to 5 - tests: NavRail.test.ts now expects 5 buttons + covers settings click, NavRailHarness View type extended
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
// End-to-end NavRail test: verify that clicks flip the parent's view
|
|
// state AND the active button class follows. We observe the DOM —
|
|
// that's what the running Tauri webview shows, and it's what the user
|
|
// sees.
|
|
//
|
|
// Pattern: `let view = $state("home")` in the harness, then the
|
|
// `on_select` callback updates it (same shape as App.svelte).
|
|
|
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
import { mount, unmount, tick } from "svelte";
|
|
import NavRailHarness from "./NavRailHarness.svelte";
|
|
|
|
let target: HTMLDivElement;
|
|
let app: ReturnType<typeof mount> | null = null;
|
|
|
|
beforeEach(() => {
|
|
target = document.createElement("div");
|
|
document.body.appendChild(target);
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (app) unmount(app);
|
|
target.remove();
|
|
});
|
|
|
|
async function mountHarness() {
|
|
app = mount(NavRailHarness, { target });
|
|
await tick();
|
|
}
|
|
|
|
describe("NavRail (callback-prop pattern)", () => {
|
|
it("renders 5 buttons with home active", async () => {
|
|
await mountHarness();
|
|
const btns = target.querySelectorAll("button.rail__btn");
|
|
expect(btns.length).toBe(5);
|
|
expect(btns[0].classList.contains("active")).toBe(true);
|
|
expect(target.querySelector('[data-testid="view-value"]')?.textContent).toBe("home");
|
|
});
|
|
|
|
it("flips view + active class on click", async () => {
|
|
await mountHarness();
|
|
const btns = target.querySelectorAll("button.rail__btn");
|
|
|
|
btns[3].dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
await tick();
|
|
expect(target.querySelector('[data-testid="view-value"]')?.textContent).toBe("search");
|
|
expect(btns[3].classList.contains("active")).toBe(true);
|
|
expect(btns[0].classList.contains("active")).toBe(false);
|
|
|
|
btns[1].dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
await tick();
|
|
expect(target.querySelector('[data-testid="view-value"]')?.textContent).toBe("compose");
|
|
expect(btns[1].classList.contains("active")).toBe(true);
|
|
|
|
btns[2].dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
await tick();
|
|
expect(target.querySelector('[data-testid="view-value"]')?.textContent).toBe("profile");
|
|
expect(btns[2].classList.contains("active")).toBe(true);
|
|
|
|
btns[4].dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
await tick();
|
|
expect(target.querySelector('[data-testid="view-value"]')?.textContent).toBe("settings");
|
|
expect(btns[4].classList.contains("active")).toBe(true);
|
|
});
|
|
}); |