import { afterEach, describe, expect, test } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import { userEvent } from "@testing-library/user-event"; import { I18nProvider } from "@lingui/react"; import { i18n } from "@lingui/core"; import { BrowserRouter, Route, Routes, useLocation } from "react-router"; import { useState } from "react"; import { AppHeader } from "../../../components/layout/AppHeader.tsx"; import { AuthContext } from "../../../contexts/auth/AuthContext.ts"; import { defaultWSValue, WSContext } from "../../../contexts/ws/WSContext.ts"; import type { Session } from "../../../utils/auth/storage.ts"; import { makeSession } from "../../fixtures.ts"; import { currentPath, renderWithContexts } from "../../render.tsx"; describe("AppHeader", () => { test("guests get a login button", async () => { const user = userEvent.setup(); renderWithContexts(); await user.click(screen.getByRole("button", { name: "Log in" })); expect(currentPath()).toBe("/login"); }); test("members get their links, chat, bell and the new-dump button", () => { renderWithContexts(, { session: makeSession({ username: "ann" }), }); expect(screen.getByRole("link", { name: "Playlists" })).toHaveAttribute( "href", "/@ann/playlists", ); expect(screen.getByRole("button", { name: "User menu" })) .toBeInTheDocument(); expect(screen.getByRole("button", { name: "Chat" })).toBeInTheDocument(); expect(screen.getByRole("button", { name: "Notifications" })) .toBeInTheDocument(); const dump = screen.getByRole("button", { name: /Dump/ }); expect(dump).toBeDisabled(); expect(dump).toHaveAttribute("title", "Server unreachable"); }); test("shows the live-updates banner when disconnected", () => { renderWithContexts(, { ws: { wsStatus: "disconnected", wsErrorMessage: "Trying to reconnect…" }, }); expect(screen.getByRole("alert")).toHaveTextContent( "Live updates unavailable. Trying to reconnect…", ); }); test("the search toggle opens and closes, giving focus back", async () => { const user = userEvent.setup(); renderWithContexts(); const toggle = screen.getByRole("button", { name: "Search" }); await user.click(toggle); expect(screen.getByRole("button", { name: "Cancel search" })) .toHaveAttribute( "aria-expanded", "true", ); const [input] = screen.getAllByRole("searchbox"); await user.type(input, "x"); await user.keyboard("{Escape}"); expect(screen.getByRole("button", { name: "Search" })).toHaveFocus(); expect(screen.getAllByRole("searchbox")[0]).toHaveValue(""); }); // Leaving search needs the real history stack (React Router keeps its // index in history.state), so these use a BrowserRouter. function Browser({ session }: { session?: Session }) { const [authResponse, setAuthResponse] = useState(session ?? null); function Loc() { const l = useLocation(); return {l.pathname + l.search}; } return ( } /> ); } const loc = () => screen.getByTestId("loc").textContent; afterEach(() => globalThis.history.replaceState(null, "", "/")); test("several searches, then ✕, return to where search began", async () => { globalThis.history.replaceState(null, "", "/start"); const user = userEvent.setup(); render(); await user.click(screen.getByRole("button", { name: "Search" })); await user.type(screen.getAllByRole("searchbox")[0], "cats{Enter}"); expect(loc()).toBe("/search?q=cats"); const bar = () => screen.getAllByRole("searchbox")[0]; expect(bar()).toHaveValue("cats"); await user.clear(bar()); await user.type(bar(), "dogs{Enter}"); expect(loc()).toBe("/search?q=dogs"); await user.click(screen.getByRole("button", { name: "Cancel search" })); await waitFor(() => expect(loc()).toBe("/start")); }); test("Escape on the results page reverts the query instead of leaving", async () => { globalThis.history.replaceState(null, "", "/search?q=cats"); const user = userEvent.setup(); render(); const bar = screen.getAllByRole("searchbox")[0]; expect(bar).toHaveValue("cats"); await user.type(bar, "zzz{Escape}"); expect(bar).toHaveValue("cats"); expect(loc()).toBe("/search?q=cats"); }); test("✕ on results that opened the session goes home", async () => { globalThis.history.replaceState(null, "", "/search?q=cats"); const user = userEvent.setup(); render(); await user.click(screen.getByRole("button", { name: "Cancel search" })); expect(loc()).toBe("/"); }); });