Также: шеврон свёртки секции «Бэклог» — свёрнуто вниз, развёрнуто вверх (T4.5). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
69 lines
3.7 KiB
TypeScript
69 lines
3.7 KiB
TypeScript
import { render, screen, waitFor, within } from "@testing-library/react";
|
||
import userEvent from "@testing-library/user-event";
|
||
import { createMemoryRouter } from "react-router";
|
||
import { beforeEach, describe, expect, it } from "vitest";
|
||
import { App } from "../../../App.tsx";
|
||
import { setToken } from "../../../auth/token.ts";
|
||
import settings from "../board/__fixtures__/settings.json";
|
||
import { routes } from "../../../routes.tsx";
|
||
import { json, mockFetch } from "../../../test/fetchMock.ts";
|
||
import type { AgileResponse } from "../api/types.ts";
|
||
|
||
const S = { label: "AWPCA", name: "АРМ КА", board_id: 4216, board_type: "scrum", created_at: "", issues_count: 9, jira_synced_at: null };
|
||
const K = { label: "KAN", name: "Канбан", board_id: 5120, board_type: "kanban", created_at: "", issues_count: 4, jira_synced_at: null };
|
||
const data: AgileResponse = {
|
||
board: { id: 4216, type: "scrum", columns: [{ name: "Новая", statuses: ["Новая"] }], kanban_backlog: null, fetched_at: "2026-10-24T10:00:00+00:00" },
|
||
sprints: [], backlog: [], board_issues: [],
|
||
};
|
||
|
||
const open = (path: string) => {
|
||
const router = createMemoryRouter(routes, { initialEntries: [path], basename: "/app" });
|
||
render(<App router={router} />);
|
||
return router;
|
||
};
|
||
const base = (method: string, pathname: string, projects: unknown[]) => {
|
||
const k = `${method} ${pathname}`;
|
||
if (k === "GET /projects") return json(200, { projects });
|
||
if (k === "GET /settings") return json(200, settings);
|
||
if (k === "GET /issues") return json(200, { issues: [] });
|
||
if (k === "GET /batches") return json(200, { batches: [] });
|
||
if (k === "GET /agents") return json(200, { agents: [] });
|
||
return null;
|
||
};
|
||
|
||
describe("AgileGate (T9.4)", () => {
|
||
beforeEach(() => { setToken("tok"); localStorage.clear(); });
|
||
|
||
it("пока /agile не ответил — «Загрузка…»", async () => {
|
||
mockFetch((method, url) => {
|
||
if (`${method} ${url.pathname}` === "GET /agile") return new Promise<Response>(() => {});
|
||
return base(method, url.pathname, [S]) ?? json(404, { error: "not_found" });
|
||
});
|
||
open("/app/jira/sprint?project=AWPCA");
|
||
expect(await screen.findByText("Загрузка…")).toBeInTheDocument();
|
||
});
|
||
|
||
it("ошибка /agile — текст ошибки и «Повторить», щелчок повторяет запрос", async () => {
|
||
let calls = 0;
|
||
mockFetch((method, url) => {
|
||
if (`${method} ${url.pathname}` === "GET /agile") { calls += 1; return calls === 1 ? json(500, { error: "hub_down" }) : json(200, data); }
|
||
return base(method, url.pathname, [S]) ?? json(404, { error: "not_found" });
|
||
});
|
||
open("/app/jira/sprint?project=AWPCA");
|
||
const retry = await screen.findByRole("button", { name: "Повторить" });
|
||
expect(screen.queryByText("Загрузка…")).not.toBeInTheDocument();
|
||
await userEvent.click(retry);
|
||
await waitFor(() => expect(calls).toBe(2));
|
||
await waitFor(() => expect(screen.queryByRole("button", { name: "Повторить" })).not.toBeInTheDocument());
|
||
});
|
||
|
||
it("меню kanban-проекта: «Kanban» есть, «Бэклог» и «Спринт» нет", async () => {
|
||
mockFetch((method, url) => base(method, url.pathname, [K]) ?? json(200, { ...data, board: { ...data.board, type: "kanban" }, sprints: [], backlog: null }));
|
||
open("/app/jira/kanban?project=KAN");
|
||
const menu = await screen.findByRole("group", { name: "Jira" });
|
||
expect(await within(menu).findByRole("link", { name: "Kanban" })).toBeInTheDocument();
|
||
expect(within(menu).queryByRole("link", { name: "Бэклог" })).not.toBeInTheDocument();
|
||
expect(within(menu).queryByRole("link", { name: "Спринт" })).not.toBeInTheDocument();
|
||
});
|
||
});
|