// @vitest-environment jsdom // // Ending every other session, or changing the password, revokes every API token on the server — so // the Tokens tab must not then show them from its cache as if they still worked. 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 type { Me } from "../lib/api"; import { qk } from "../lib/queryKeys"; const h = vi.hoisted(() => ({ logoutOthers: vi.fn(async () => ({ ok: true })), setPassword: vi.fn(async (_p: string, _c?: string) => ({ ok: true })), })); vi.mock("react-i18next", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, useTranslation: () => ({ t: (key: string) => key, i18n: { language: "en" } }), }; }); vi.mock("../lib/api", async (importOriginal) => ({ ...(await importOriginal()), api: h, })); vi.mock("../lib/notifications", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, notify: vi.fn() }; }); vi.mock("./confirmContext", () => ({ useConfirm: () => vi.fn(async () => true) })); import { SignInMethods } from "./SettingsPanel"; afterEach(cleanup); const me = { email: "a@example.com", has_password: true, google_enabled: false } as Me; function renderIt() { const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } }); qc.setQueryData(qk.apiTokens(), [{ id: 1 }]); render( , ); return qc; } const tokensStale = (qc: QueryClient) => qc.getQueryState(qk.apiTokens())?.isInvalidated; describe("SignInMethods", () => { it("signing the other sessions out marks the token list stale", async () => { const qc = renderIt(); fireEvent.click(screen.getByText("settings.account.sessions.action")); await waitFor(() => expect(h.logoutOthers).toHaveBeenCalled()); await waitFor(() => expect(tokensStale(qc)).toBe(true)); }); it("a password changed marks the token list stale", async () => { const qc = renderIt(); fireEvent.click(screen.getByText("settings.account.password.change")); fireEvent.change(screen.getByPlaceholderText("settings.account.password.current"), { target: { value: "old one" }, }); fireEvent.change(screen.getByPlaceholderText("settings.account.password.new"), { target: { value: "a brand new one" }, }); fireEvent.click(screen.getByText("settings.account.password.save")); await waitFor(() => expect(h.setPassword).toHaveBeenCalled()); await waitFor(() => expect(tokensStale(qc)).toBe(true)); }); });