sdlc-hub/web/src/auth/LoginScreen.test.tsx

93 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { act, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it } from "vitest";
import { qk, useBoard } from "../api/queries.ts";
import { json, mockFetch } from "../test/fetchMock.ts";
import { renderWithProviders } from "../test/render.tsx";
import { AuthGate } from "./AuthGate.tsx";
import { clearToken, getAuth, setToken } from "./token.ts";
const app = <AuthGate><p>страница приложения</p></AuthGate>;
describe("вход", () => {
beforeEach(() => clearToken());
it("без токена — экран входа, страница не видна", () => {
renderWithProviders(app);
expect(screen.getByRole("heading", { name: "Вход в хаб" })).toBeInTheDocument();
expect(screen.queryByText("страница приложения")).not.toBeInTheDocument();
expect(screen.getByText(/uv run jira-hub tokens/)).toBeInTheDocument();
});
it("верный токен сохраняется и открывает приложение", async () => {
const fetch = mockFetch(() => json(200, {}));
renderWithProviders(app);
await userEvent.type(screen.getByLabelText("Клиентский токен хаба"), "good-token");
await userEvent.click(screen.getByRole("button", { name: "Войти" }));
expect(await screen.findByText("страница приложения")).toBeInTheDocument();
expect(localStorage.getItem("jira-hub-token")).toBe("good-token");
expect(fetch.mock.calls[0][0]).toBe("/settings");
});
it("неверный токен не сохраняется, поле не стирается", async () => {
mockFetch(() => json(401, { error: "unauthorized" }));
renderWithProviders(app);
const input = screen.getByLabelText("Клиентский токен хаба");
await userEvent.type(input, "wrong");
await userEvent.click(screen.getByRole("button", { name: "Войти" }));
expect(await screen.findByText(/Токен не подошёл/)).toBeInTheDocument();
expect(input).toHaveValue("wrong");
expect(localStorage.getItem("jira-hub-token")).toBeNull();
});
it("кириллица или пробел — «недопустимые символы», запроса нет", async () => {
const fetch = mockFetch(() => json(200, {}));
renderWithProviders(app);
await userEvent.type(screen.getByLabelText("Клиентский токен хаба"), "ток ен");
await userEvent.click(screen.getByRole("button", { name: "Войти" }));
expect(screen.getByText(/недопустимые символы/)).toBeInTheDocument();
expect(fetch).not.toHaveBeenCalled();
});
it("хаб не отвечает — своё сообщение, не «токен не подошёл»", async () => {
mockFetch(() => { throw new TypeError("Failed to fetch"); });
renderWithProviders(app);
await userEvent.type(screen.getByLabelText("Клиентский токен хаба"), "tok");
await userEvent.click(screen.getByRole("button", { name: "Войти" }));
expect(await screen.findByText(/Хаб не отвечает/)).toBeInTheDocument();
});
it("401 в запросе страницы — экран входа «токен не подошёл», страница скрыта (T3.6)", async () => {
setToken("stale");
mockFetch(() => json(401, { error: "unauthorized" }));
function Page() { useBoard(); return <p>страница приложения</p>; }
renderWithProviders(<AuthGate><Page /></AuthGate>);
expect(await screen.findByText(/Токен не подошёл/)).toBeInTheDocument();
expect(screen.queryByText("страница приложения")).not.toBeInTheDocument();
expect(getAuth()).toEqual({ token: "", reason: "bad" });
});
it("запоздавший 401 от прежнего токена после входа с новым не выбрасывает на вход (T3.5)", async () => {
setToken("old-token");
let release!: (r: Response) => void;
const slow = new Promise<Response>((r) => { release = r; });
mockFetch((_m, url) => (url.pathname === "/board" ? slow : json(200, {})));
function Page() { useBoard(); return <p>страница приложения</p>; }
const { client } = renderWithProviders(<AuthGate><Page /></AuthGate>);
act(() => setToken("new-token"));
release(json(401, { error: "unauthorized" }));
await waitFor(() => expect(client.getQueryState(qk.board)?.status).toBe("error")); // 401 точно обработан
expect(screen.getByText("страница приложения")).toBeInTheDocument();
expect(getAuth()).toEqual({ token: "new-token", reason: "none" });
});
it("хаб отверг проверку токена (4xx) — текст хаба, не «хаб не отвечает» (T3.2)", async () => {
mockFetch(() => json(400, { error: "bad_request", detail: "заголовок Authorization без Bearer" }));
renderWithProviders(app);
await userEvent.type(screen.getByLabelText("Клиентский токен хаба"), "tok");
await userEvent.click(screen.getByRole("button", { name: "Войти" }));
expect(await screen.findByText(/заголовок Authorization без Bearer/)).toBeInTheDocument();
expect(screen.queryByText(/Хаб не отвечает/)).not.toBeInTheDocument();
});
});