126 lines
6.1 KiB
TypeScript
126 lines
6.1 KiB
TypeScript
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||
import { fireEvent, render, screen, waitFor, within } from "@testing-library/react";
|
||
import userEvent from "@testing-library/user-event";
|
||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||
import { setToken } from "../auth/token.ts";
|
||
import { jiraModule } from "../modules/jira/index.tsx";
|
||
import type { HubModule } from "../modules/types.ts";
|
||
import { json, mockFetch } from "../test/fetchMock.ts";
|
||
import { MODULES } from "../modules/index.ts";
|
||
import { NewProjectDialog } from "./NewProjectDialog.tsx";
|
||
|
||
// второй модуль с текстовым полем: окно собирает поля из всех модулей, а не только из jira
|
||
vi.mock("../modules/index.ts", async () => {
|
||
const { jiraModule: jira } = await import("../modules/jira/index.tsx");
|
||
const { wikiModule: wiki } = await import("../modules/wiki/index.tsx");
|
||
const extra: HubModule = {
|
||
name: "extra", title: "Extra", pages: [], nav: [],
|
||
projectFields: [{ name: "space_key", label: "Пространство", hint: "ключ", kind: "text" }],
|
||
};
|
||
return { MODULES: [jira, wiki, extra] };
|
||
});
|
||
|
||
const CREATED = { project: { label: "P", name: "Пэ", created_at: "" }, batch_id: 3, batches: [{ module: "jira", id: 3 }, { module: "wiki", id: 4 }] };
|
||
|
||
function setup() {
|
||
const posts: unknown[] = [];
|
||
mockFetch((method, _url, body) => {
|
||
if (method === "POST") { posts.push(body); return json(201, CREATED); }
|
||
return json(404, { error: "not_found" });
|
||
});
|
||
const onCreated = vi.fn();
|
||
render(
|
||
<QueryClientProvider client={new QueryClient()}>
|
||
<NewProjectDialog onClose={() => {}} onCreated={onCreated} />
|
||
</QueryClientProvider>,
|
||
);
|
||
return { posts, onCreated };
|
||
}
|
||
const fill = async () => {
|
||
await userEvent.type(screen.getByLabelText("Метка"), "P");
|
||
await userEvent.type(screen.getByLabelText("Название"), "Пэ");
|
||
};
|
||
|
||
describe("NewProjectDialog: поля модулей", () => {
|
||
beforeEach(() => setToken("tok"));
|
||
|
||
it("jira описывает поле доски", () => {
|
||
expect(jiraModule.projectFields).toEqual([
|
||
{ name: "board_id", label: "Номер доски Jira", hint: "scrum или kanban определится сам", kind: "int" },
|
||
]);
|
||
});
|
||
|
||
it("пустые поля в тело не попадают", async () => {
|
||
const { posts } = setup();
|
||
await fill();
|
||
await userEvent.click(screen.getByRole("button", { name: "Создать" }));
|
||
await waitFor(() => expect(posts).toHaveLength(1));
|
||
expect(posts[0]).toEqual({ label: "P", name: "Пэ", author: "viewer" });
|
||
});
|
||
|
||
it("доска «5120» уходит числом, текстовое поле другого модуля — строкой", async () => {
|
||
const { posts } = setup();
|
||
await fill();
|
||
await userEvent.type(screen.getByLabelText("Номер доски Jira"), "5120");
|
||
await userEvent.type(screen.getByLabelText("Пространство"), " KEY ");
|
||
await userEvent.click(screen.getByRole("button", { name: "Создать" }));
|
||
await waitFor(() => expect(posts).toHaveLength(1));
|
||
expect(posts[0]).toEqual({ label: "P", name: "Пэ", board_id: 5120, space_key: "KEY", author: "viewer" });
|
||
});
|
||
|
||
it("поля сгруппированы по модулям: fieldset с legend «Jira» и «Вики»", () => {
|
||
setup();
|
||
for (const [legend, field] of [["Jira", "Номер доски Jira"], ["Вики", "Корень вики"]]) {
|
||
const g = screen.getByRole("group", { name: legend });
|
||
expect(within(g).getByLabelText(field)).toBeInTheDocument();
|
||
}
|
||
});
|
||
|
||
it("подсказки — текст под полем, placeholder пустой", () => {
|
||
setup();
|
||
const board = screen.getByLabelText("Номер доски Jira");
|
||
expect(board).not.toHaveAttribute("placeholder");
|
||
expect(board).toHaveAccessibleDescription("scrum или kanban определится сам");
|
||
expect(screen.getByLabelText("Метка")).toHaveAccessibleDescription("метка задач в Jira и имя проекта в хабе");
|
||
});
|
||
|
||
it("51.5 в номере доски — «нужно целое число», запроса нет (T4.1)", async () => {
|
||
const { posts } = setup();
|
||
await fill();
|
||
await userEvent.type(screen.getByLabelText("Номер доски Jira"), "51.5");
|
||
await userEvent.click(screen.getByRole("button", { name: "Создать" }));
|
||
expect(await screen.findByText("нужно целое число")).toBeInTheDocument();
|
||
expect(screen.getByLabelText("Номер доски Jira")).toHaveAttribute("aria-invalid", "true");
|
||
expect(posts).toHaveLength(0);
|
||
});
|
||
|
||
it("onCreated получает пакеты с модулями (M-14)", async () => {
|
||
const { onCreated } = setup();
|
||
await fill();
|
||
await userEvent.click(screen.getByRole("button", { name: "Создать" }));
|
||
await waitFor(() => expect(onCreated).toHaveBeenCalled());
|
||
expect(onCreated.mock.calls[0][1]).toEqual([{ module: "jira", id: 3 }, { module: "wiki", id: 4 }]);
|
||
});
|
||
|
||
it("два быстрых ввода в разные поля не теряют первое (T4.2)", async () => {
|
||
const { posts } = setup();
|
||
await fill();
|
||
const board = screen.getByLabelText("Номер доски Jira"), space = screen.getByLabelText("Пространство");
|
||
fireEvent.change(board, { target: { value: "7" } });
|
||
fireEvent.change(space, { target: { value: "K" } });
|
||
await userEvent.click(screen.getByRole("button", { name: "Создать" }));
|
||
await waitFor(() => expect(posts).toHaveLength(1));
|
||
expect(posts[0]).toMatchObject({ board_id: 7, space_key: "K" });
|
||
});
|
||
|
||
it("поля собираются при отрисовке, а не при импорте (T4.5)", () => {
|
||
const late: HubModule = { name: "late", title: "Late", pages: [], nav: [],
|
||
projectFields: [{ name: "x", label: "Позднее поле", hint: "", kind: "text" }] };
|
||
(MODULES as HubModule[]).push(late);
|
||
try {
|
||
setup();
|
||
expect(screen.getByLabelText("Позднее поле")).toBeInTheDocument();
|
||
} finally { (MODULES as HubModule[]).pop(); }
|
||
});
|
||
});
|