93 lines
5.4 KiB
TypeScript
93 lines
5.4 KiB
TypeScript
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();
|
||
});
|
||
});
|