test(web): e2e широкой доски и фильтров, сид WIDE_E2E, тесты AgileGate (#112, T9.4, T12.2–T12.4)
Также: шеврон свёртки секции «Бэклог» — свёрнуто вниз, развёрнуто вверх (T4.5). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
52645c74da
commit
f21dea39b6
@ -2,18 +2,23 @@ import { expect, test } from "@playwright/test";
|
|||||||
import { login } from "./hub.ts";
|
import { login } from "./hub.ts";
|
||||||
|
|
||||||
// экраны доски: «Бэклог», «Спринт», «Kanban» (spec web-app «Спринты и бэклог»); данные — сид тестового хаба (R-27)
|
// экраны доски: «Бэклог», «Спринт», «Kanban» (spec web-app «Спринты и бэклог»); данные — сид тестового хаба (R-27)
|
||||||
const side = (page: import("@playwright/test").Page) => page.getByRole("complementary", { name: "Панель приложения" });
|
type Page = import("@playwright/test").Page;
|
||||||
|
const side = (page: Page) => page.getByRole("complementary", { name: "Панель приложения" });
|
||||||
|
// строка списка / карточка колонки по ключу задачи (ссылка с точным именем), без привязки к порядку в DOM
|
||||||
|
const itemOf = (page: Page, key: string) => page.getByRole("listitem").filter({ has: page.getByRole("link", { name: key, exact: true }) });
|
||||||
|
const colOf = (page: Page, name: string) => page.getByRole("region", { name, exact: true });
|
||||||
|
|
||||||
test("«Бэклог» AWPCA: секции, «Прошлые спринты (1)», щелчок открывает карточку", async ({ page }) => {
|
test("«Бэклог» AWPCA: секции, «Прошлые спринты (1)», щелчок открывает карточку", async ({ page }) => {
|
||||||
await login(page, "/app/jira/backlog?project=AWPCA");
|
await login(page, "/app/jira/backlog?project=AWPCA");
|
||||||
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 2" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 2" })).toBeVisible();
|
||||||
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 3" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 3" })).toBeVisible();
|
||||||
await expect(page.getByRole("heading", { name: "Бэклог", exact: true, level: 2 })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "Бэклог", exact: true, level: 2 })).toBeVisible();
|
||||||
const past = page.getByText("Прошлые спринты (1)");
|
const past = page.getByText("Прошлые спринты (1)", { exact: true });
|
||||||
await expect(past).toBeVisible();
|
await expect(past).toBeVisible();
|
||||||
await past.click();
|
await past.click();
|
||||||
await page.getByText("AWPCA_Спринт 1").first().click();
|
const pastSprint = page.locator("details.agile-past__sprint").filter({ has: page.locator("summary", { hasText: "AWPCA_Спринт 1" }) });
|
||||||
const row = page.locator(".agile-row").filter({ hasText: "AURORA-9001" }).last();
|
await pastSprint.locator("summary").click();
|
||||||
|
const row = pastSprint.getByRole("listitem").filter({ has: page.getByRole("link", { name: "AURORA-9001", exact: true }) });
|
||||||
await expect(row).toBeVisible();
|
await expect(row).toBeVisible();
|
||||||
await row.click();
|
await row.click();
|
||||||
await expect(page).toHaveURL(/\/app\/jira\/issues\/AURORA-9001/);
|
await expect(page).toHaveURL(/\/app\/jira\/issues\/AURORA-9001/);
|
||||||
@ -28,9 +33,9 @@ test("«Спринт» AWPCA: колонки доски, «осталось 7 д
|
|||||||
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 2" })).toBeVisible();
|
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 2" })).toBeVisible();
|
||||||
await expect(page.getByText(/осталось \d+ дн\./)).toBeVisible();
|
await expect(page.getByText(/осталось \d+ дн\./)).toBeVisible();
|
||||||
for (const name of ["К выполнению", "В работе", "Готово"]) {
|
for (const name of ["К выполнению", "В работе", "Готово"]) {
|
||||||
await expect(page.locator(".agile-col__name", { hasText: name })).toBeVisible();
|
await expect(page.getByRole("heading", { name, exact: true, level: 3 })).toBeVisible();
|
||||||
}
|
}
|
||||||
await page.locator(".agile-card").filter({ hasText: "AURORA-9001" }).click();
|
await itemOf(page, "AURORA-9001").click();
|
||||||
await expect(page).toHaveURL(/\/app\/jira\/issues\/AURORA-9001/);
|
await expect(page).toHaveURL(/\/app\/jira\/issues\/AURORA-9001/);
|
||||||
await expect(page.getByRole("dialog")).toBeVisible();
|
await expect(page.getByRole("dialog")).toBeVisible();
|
||||||
await page.keyboard.press("Escape");
|
await page.keyboard.press("Escape");
|
||||||
@ -39,19 +44,19 @@ test("«Спринт» AWPCA: колонки доски, «осталось 7 д
|
|||||||
|
|
||||||
test("«Kanban»: «Бэклог (1)», колонки «В работе» и «Готово», подпись «за 14 дней»", async ({ page }) => {
|
test("«Kanban»: «Бэклог (1)», колонки «В работе» и «Готово», подпись «за 14 дней»", async ({ page }) => {
|
||||||
await login(page, "/app/jira/kanban?project=KANBAN_E2E");
|
await login(page, "/app/jira/kanban?project=KANBAN_E2E");
|
||||||
await expect(page.getByText("Бэклог (1)")).toBeVisible();
|
await expect(page.getByText("Бэклог (1)", { exact: true })).toBeVisible();
|
||||||
await expect(page.locator(".agile-col__name", { hasText: "В работе" })).toBeVisible();
|
await expect(colOf(page, "В работе")).toBeVisible();
|
||||||
await expect(page.locator(".agile-col__name", { hasText: "Готово" })).toBeVisible();
|
await expect(colOf(page, "Готово")).toBeVisible();
|
||||||
await expect(page.locator(".agile-col__name", { hasText: "Бэклог" })).toHaveCount(0);
|
await expect(colOf(page, "Бэклог")).toHaveCount(0);
|
||||||
await expect(page.getByText("за 14 дней")).toBeVisible();
|
await expect(page.getByText("за 14 дней", { exact: true })).toBeVisible();
|
||||||
await expect(page.locator(".agile-card").filter({ hasText: "AURORA-9102" })).toBeVisible();
|
await expect(colOf(page, "В работе").getByRole("link", { name: "AURORA-9102", exact: true })).toBeVisible();
|
||||||
await expect(page.locator(".agile-card").filter({ hasText: "AURORA-9103" })).toBeVisible();
|
await expect(colOf(page, "Готово").getByRole("link", { name: "AURORA-9103", exact: true })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("без scrum-доски: /app/jira/backlog?project=KANBAN_E2E — «У проекта нет scrum-доски», ссылка «Связи»", async ({ page }) => {
|
test("без scrum-доски: /app/jira/backlog?project=KANBAN_E2E — «У проекта нет scrum-доски», ссылка «Связи»", async ({ page }) => {
|
||||||
await login(page, "/app/jira/backlog?project=KANBAN_E2E");
|
await login(page, "/app/jira/backlog?project=KANBAN_E2E");
|
||||||
await expect(page.getByText("У проекта нет scrum-доски")).toBeVisible();
|
await expect(page.getByText("У проекта нет scrum-доски")).toBeVisible();
|
||||||
await page.getByRole("link", { name: "Связи", exact: true }).last().click();
|
await page.getByRole("main").getByRole("link", { name: "Связи", exact: true }).click();
|
||||||
await expect(page).toHaveURL(/\/app\/jira\/links\?project=KANBAN_E2E/);
|
await expect(page).toHaveURL(/\/app\/jira\/links\?project=KANBAN_E2E/);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -72,10 +77,98 @@ test("900 px: колонки «Спринта» прокручиваются в
|
|||||||
await expect(page.locator(".agile-col").first()).toBeVisible();
|
await expect(page.locator(".agile-col").first()).toBeVisible();
|
||||||
const m = await page.evaluate(() => {
|
const m = await page.evaluate(() => {
|
||||||
const d = document.documentElement, c = document.querySelector<HTMLElement>(".agile-columns")!;
|
const d = document.documentElement, c = document.querySelector<HTMLElement>(".agile-columns")!;
|
||||||
return { doc: [d.scrollWidth, d.clientWidth], cols: [c.scrollWidth, c.clientWidth],
|
return { doc: [d.scrollWidth, d.clientWidth], cols: [c.scrollWidth, c.clientWidth], bottom: c.getBoundingClientRect().bottom,
|
||||||
gutter: c.getBoundingClientRect().left - document.querySelector(".agile")!.getBoundingClientRect().left };
|
gutter: c.getBoundingClientRect().left - document.querySelector(".agile")!.getBoundingClientRect().left };
|
||||||
});
|
});
|
||||||
expect(m.gutter, "колонки не получают второй отступ внутри страницы (T10.1)").toBe(0);
|
expect(m.gutter, "колонки не получают второй отступ внутри страницы (T10.1)").toBe(0);
|
||||||
expect(m.doc[0]).toBeLessThanOrEqual(m.doc[1]);
|
expect(m.doc[0]).toBeLessThanOrEqual(m.doc[1]);
|
||||||
expect(m.cols[0]).toBeGreaterThan(m.cols[1]);
|
expect(m.cols[0]).toBeGreaterThan(m.cols[1]);
|
||||||
|
expect(m.bottom, "нижний край доски в окне").toBeLessThanOrEqual(900);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("«Широкая доска» 2560×1300: колонки одной высоты, доска в окне, горизонтальная прокрутка внутри, «Без колонки» достижима", async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 2560, height: 1300 });
|
||||||
|
await login(page, "/app/jira/sprint?project=WIDE_E2E");
|
||||||
|
await expect(colOf(page, "Колонка 1")).toBeVisible();
|
||||||
|
await expect(colOf(page, "Без колонки")).toHaveCount(1);
|
||||||
|
const m = await page.evaluate(() => {
|
||||||
|
const board = document.querySelector<HTMLElement>(".agile-columns")!;
|
||||||
|
const heights = [...document.querySelectorAll<HTMLElement>(".agile-col")].map((c) => c.getBoundingClientRect().height);
|
||||||
|
return { heights, bottom: board.getBoundingClientRect().bottom, inner: window.innerHeight, width: board.getBoundingClientRect().width,
|
||||||
|
sw: board.scrollWidth, cw: board.clientWidth, count: heights.length };
|
||||||
|
});
|
||||||
|
expect(m.count, "11 колонок и «Без колонки»").toBe(12);
|
||||||
|
expect(Math.max(...m.heights) - Math.min(...m.heights), "высоты колонок равны").toBeLessThanOrEqual(1);
|
||||||
|
expect(m.bottom, "нижний край доски в окне").toBeLessThanOrEqual(m.inner);
|
||||||
|
expect(m.sw, "доска прокручивается по горизонтали").toBeGreaterThan(m.cw);
|
||||||
|
expect(m.width, "доска шире 1440 px (нет max-width)").toBeGreaterThan(1440);
|
||||||
|
await page.evaluate(() => { const b = document.querySelector<HTMLElement>(".agile-columns")!; b.scrollLeft = b.scrollWidth; });
|
||||||
|
const extra = colOf(page, "Без колонки");
|
||||||
|
await expect(extra).toBeInViewport({ ratio: 1 });
|
||||||
|
const doc = await page.evaluate(() => [document.documentElement.scrollWidth, document.documentElement.clientWidth]);
|
||||||
|
expect(doc[0], "страница без горизонтальной прокрутки").toBeLessThanOrEqual(doc[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("узкий контейнер: на 900 px вместо панели «Эпики» — выбор «Эпик», на 1600 px — панель и кнопка", async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 900, height: 900 });
|
||||||
|
await login(page, "/app/jira/backlog?project=AWPCA");
|
||||||
|
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 2" })).toBeVisible();
|
||||||
|
await expect(page.getByRole("complementary", { name: "Эпики" })).toBeHidden();
|
||||||
|
await expect(page.getByRole("button", { name: "Эпики", exact: true })).toBeHidden();
|
||||||
|
await expect(page.getByRole("combobox", { name: "Эпик" })).toBeVisible();
|
||||||
|
await page.setViewportSize({ width: 1600, height: 900 });
|
||||||
|
await expect(page.getByRole("complementary", { name: "Эпики" })).toBeVisible();
|
||||||
|
await expect(page.getByRole("button", { name: "Эпики", exact: true })).toBeVisible();
|
||||||
|
await expect(page.getByRole("combobox", { name: "Эпик" })).toBeHidden();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("«Бэклог» AWPCA: панель «Эпики», выбор эпика оставляет только его задачи, свёртка секции переживает перезагрузку", async ({ page }) => {
|
||||||
|
await login(page, "/app/jira/backlog?project=AWPCA");
|
||||||
|
const panel = page.getByRole("complementary", { name: "Эпики" });
|
||||||
|
await expect(panel).toBeVisible();
|
||||||
|
await expect(itemOf(page, "AURORA-9004")).toBeVisible();
|
||||||
|
await panel.getByRole("button", { name: /AURORA-9100/ }).click();
|
||||||
|
await expect(itemOf(page, "AURORA-9001")).toBeVisible();
|
||||||
|
await expect(itemOf(page, "AURORA-9004")).toHaveCount(0);
|
||||||
|
await expect(itemOf(page, "AURORA-9008")).toHaveCount(0);
|
||||||
|
await panel.getByRole("button", { name: "Все задачи" }).click();
|
||||||
|
await expect(itemOf(page, "AURORA-9004")).toBeVisible();
|
||||||
|
const toggle = page.getByRole("button", { name: "AWPCA_Спринт 3" });
|
||||||
|
await expect(toggle).toHaveAttribute("aria-expanded", "true");
|
||||||
|
await toggle.click();
|
||||||
|
await expect(toggle).toHaveAttribute("aria-expanded", "false");
|
||||||
|
await expect(itemOf(page, "AURORA-9004")).toHaveCount(0);
|
||||||
|
await page.reload();
|
||||||
|
await expect(page.getByRole("button", { name: "AWPCA_Спринт 3" })).toHaveAttribute("aria-expanded", "false");
|
||||||
|
await expect(itemOf(page, "AURORA-9004")).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("«Спринт» AWPCA: выбор двух спринтов пишет sprint=102,103 в адрес, скрытая колонка «Готово» переживает перезагрузку", async ({ page }) => {
|
||||||
|
await login(page, "/app/jira/sprint?project=AWPCA");
|
||||||
|
await expect(colOf(page, "Готово")).toBeVisible();
|
||||||
|
await page.getByRole("button", { name: "AWPCA_Спринт 2" }).click();
|
||||||
|
await page.getByRole("checkbox", { name: /AWPCA_Спринт 3/ }).click();
|
||||||
|
await expect(page).toHaveURL(/sprint=102(,|%2C)103/);
|
||||||
|
await expect(page.getByRole("heading", { name: "AWPCA_Спринт 3" })).toBeVisible();
|
||||||
|
await page.keyboard.press("Escape");
|
||||||
|
await page.getByRole("button", { name: "Колонки" }).click();
|
||||||
|
await page.getByRole("checkbox", { name: "Готово", exact: true }).click();
|
||||||
|
await expect(colOf(page, "Готово")).toHaveCount(0);
|
||||||
|
await page.reload();
|
||||||
|
await expect(colOf(page, "В работе")).toBeVisible();
|
||||||
|
await expect(colOf(page, "Готово")).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("390×800: страница доски без горизонтальной прокрутки документа, полоса прокрутки доски в окне", async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 390, height: 800 });
|
||||||
|
await login(page, "/app/jira/sprint?project=WIDE_E2E");
|
||||||
|
await expect(colOf(page, "Колонка 1")).toBeVisible();
|
||||||
|
const m = await page.evaluate(() => {
|
||||||
|
const d = document.documentElement, b = document.querySelector<HTMLElement>(".agile-columns")!;
|
||||||
|
return { doc: [d.scrollWidth, d.clientWidth], bottom: b.getBoundingClientRect().bottom, inner: window.innerHeight, sw: b.scrollWidth, cw: b.clientWidth };
|
||||||
|
});
|
||||||
|
expect(m.doc[0], JSON.stringify(m)).toBeLessThanOrEqual(m.doc[1]);
|
||||||
|
// нижний край доски на 390×800 (находка T8.1, замер): аннотация, а не утверждение — см. отчёт Task 8
|
||||||
|
test.info().annotations.push({ type: "замер 390×800", description: JSON.stringify(m) });
|
||||||
|
expect(m.sw).toBeGreaterThan(m.cw);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -36,9 +36,10 @@ for n, i in enumerate(issues, 1):
|
|||||||
i["story_points"] = float(n % 5 + 1)
|
i["story_points"] = float(n % 5 + 1)
|
||||||
today = date.today()
|
today = date.today()
|
||||||
iso = lambda d, hhmm: f"{d.isoformat()}T{hhmm}:00.000+03:00"
|
iso = lambda d, hhmm: f"{d.isoformat()}T{hhmm}:00.000+03:00"
|
||||||
now_iso = iso(today, "12:00")
|
# фиксированная дата «Готово» — вчера в полдень: «за 14 дней» от «сегодня 12:00» не зависит (T12.2)
|
||||||
|
done_iso = iso(today - timedelta(days=1), "12:00")
|
||||||
issues += [{"key": k, "id": k, "summary": f"Задача канбана {k[-4:]}", "issue_type": "Задача", "status": st, "priority": "Средний",
|
issues += [{"key": k, "id": k, "summary": f"Задача канбана {k[-4:]}", "issue_type": "Задача", "status": st, "priority": "Средний",
|
||||||
"labels": ["KANBAN_E2E"], "rank": f"0|k{n:04d}:", "sprint_ids": [], **({"jira_updated": now_iso} if st == "Готово" else {})}
|
"labels": ["KANBAN_E2E"], "rank": f"0|k{n:04d}:", "sprint_ids": [], **({"jira_updated": done_iso} if st == "Готово" else {})}
|
||||||
for n, (k, st) in enumerate([("AURORA-9101", "Backlog"), ("AURORA-9102", "В работе"), ("AURORA-9103", "Готово")], 1)]
|
for n, (k, st) in enumerate([("AURORA-9101", "Backlog"), ("AURORA-9102", "В работе"), ("AURORA-9103", "Готово")], 1)]
|
||||||
jira_projects.create(conn, "KANBAN_E2E", "Канбан e2e", 5120)
|
jira_projects.create(conn, "KANBAN_E2E", "Канбан e2e", 5120)
|
||||||
# WIDE_E2E: широкая scrum-доска (11 колонок, 40 задач в одной, статус вне колонок) — воспроизводит баг прокрутки (#112, T10.3)
|
# WIDE_E2E: широкая scrum-доска (11 колонок, 40 задач в одной, статус вне колонок) — воспроизводит баг прокрутки (#112, T10.3)
|
||||||
|
|||||||
68
web/src/modules/jira/agile/AgileGate.test.tsx
Normal file
68
web/src/modules/jira/agile/AgileGate.test.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -29,7 +29,7 @@ function Toggle({ titleId, bodyId, collapsed, onToggle, children }: {
|
|||||||
<h2 id={titleId} className="agile-section__title">
|
<h2 id={titleId} className="agile-section__title">
|
||||||
<button type="button" className="agile-section__toggle" aria-expanded={!collapsed} aria-controls={bodyId} onClick={onToggle}>
|
<button type="button" className="agile-section__toggle" aria-expanded={!collapsed} aria-controls={bodyId} onClick={onToggle}>
|
||||||
{children}
|
{children}
|
||||||
{collapsed ? <IconChevronUp /> : <IconChevronDown />}
|
{collapsed ? <IconChevronDown /> : <IconChevronUp />}
|
||||||
</button>
|
</button>
|
||||||
</h2>
|
</h2>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user