// @vitest-environment jsdom // // The download dialog opens on the format used last (per account), so a pasted link is one Enter // away; a format deleted since falls back to the first. Its "added" notice's View opens the tray on // the new job. The prefs are a map that outlives a mount — a reload, as far as the dialog can tell. import { afterEach, describe, expect, it, vi } from "vitest"; import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useState } from "react"; import { api, type DownloadProfile } from "../lib/api"; const h = vi.hoisted(() => ({ prefs: new Map(), notify: vi.fn(), showInTray: vi.fn(), })); vi.mock("react-i18next", async (importOriginal) => ({ ...(await importOriginal()), useTranslation: () => ({ i18n: { language: "en" }, t: (key: string) => key }), })); vi.mock("../lib/usePref", () => ({ usePref: (key: string, initial: T) => { const [value, setValue] = useState(() => h.prefs.has(key) ? (h.prefs.get(key) as T) : initial, ); return [ value, (next: T) => { h.prefs.set(key, next); setValue(next); }, ]; }, })); vi.mock("../lib/notifications", async (importOriginal) => ({ ...(await importOriginal()), notify: h.notify, })); vi.mock("../lib/downloadQueue", () => ({ showInTray: h.showInTray })); import DownloadDialog from "./DownloadDialog"; const profile = (id: number, name: string) => ({ id, name, is_builtin: false, spec: { mode: "av" } }) as unknown as DownloadProfile; afterEach(() => { cleanup(); vi.restoreAllMocks(); h.prefs.clear(); h.notify.mockClear(); h.showInTray.mockClear(); }); function open() { vi.spyOn(api, "downloadProfiles").mockResolvedValue([profile(1, "Best"), profile(2, "Phone")]); const enqueue = vi.spyOn(api, "enqueueDownload").mockResolvedValue({ id: 77 } as never); render( {}} /> , ); return enqueue; } const picked = () => screen.getByRole("button", { name: /^downloads\.dialog\.profile: / }).getAttribute("aria-label"); describe("DownloadDialog", () => { it("opens on the format used last; a deleted one falls back to the first", async () => { const enqueue = open(); await waitFor(() => expect(picked()).toBe("downloads.dialog.profile: Best")); fireEvent.click(screen.getByRole("button", { name: /^downloads\.dialog\.profile: / })); const phone = (await screen.findAllByRole("menuitemradio", { hidden: true })).find( (o) => o.textContent === "Phone", )!; fireEvent.click(phone); fireEvent.click(screen.getByText("downloads.dialog.submit")); await waitFor(() => expect(enqueue).toHaveBeenCalledWith(expect.objectContaining({ profile_id: 2 })), ); cleanup(); open(); await waitFor(() => expect(picked()).toBe("downloads.dialog.profile: Phone")); cleanup(); h.prefs.set("downloadProfile", 99); open(); await waitFor(() => expect(picked()).toBe("downloads.dialog.profile: Best")); }); it("its notice's View opens the tray on the new job", async () => { open(); await waitFor(() => expect(picked()).toBe("downloads.dialog.profile: Best")); fireEvent.click(screen.getByText("downloads.dialog.submit")); await waitFor(() => expect(h.notify).toHaveBeenCalledTimes(1)); (h.notify.mock.calls[0]![0] as { action: { onClick: () => void } }).action.onClick(); expect(h.showInTray).toHaveBeenCalledWith(77); }); });