- T6.1: e2e «описание свёрнуто» проверяет scrollHeight > clientHeight и рост высоты pre после «развернуть» - T6.2: e2e заметки из окна сверяет scrollY после закрытия окна с исходным - T6.3: тест переименован, добавлен маркер на DOM-узле карточки (узел не пересоздан) - T6.4: исправлен разорванный абзац в ARCHITECTURE.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
122 lines
8.0 KiB
TypeScript
122 lines
8.0 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
||
import { login } from "./hub.ts";
|
||
|
||
test("фильтр → карточка окном → заметка сохраняется и переживает перезагрузку", async ({ page }) => {
|
||
await login(page, "/app/issues");
|
||
await page.getByLabel("Исполнитель").selectOption("Петров Пётр Петрович");
|
||
await expect(page).toHaveURL(/assignee=/);
|
||
await page.getByRole("link", { name: "AURORA-9002", exact: true }).click();
|
||
const d = page.getByRole("dialog");
|
||
await expect(d.getByRole("heading", { name: "API свода" })).toBeVisible();
|
||
await d.getByRole("button", { name: "Править" }).click();
|
||
await d.getByLabel("Осталось").fill("e2e: дописать тесты");
|
||
await d.getByRole("button", { name: "Сохранить" }).click();
|
||
await expect(d.getByText("e2e: дописать тесты")).toBeVisible();
|
||
await page.reload();
|
||
await expect(page.getByRole("dialog").getByText("e2e: дописать тесты")).toBeVisible();
|
||
await page.keyboard.press("Escape");
|
||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||
await expect(page).toHaveURL(/\/app\/issues\?assignee=/);
|
||
await expect(page.getByLabel("Исполнитель")).toHaveValue("Петров Пётр Петрович");
|
||
});
|
||
|
||
test("окно поверх списка: прокрутка списка на месте при открытии и после закрытия", async ({ page }) => {
|
||
await page.setViewportSize({ width: 1280, height: 320 });
|
||
await login(page, "/app/issues");
|
||
await expect(page.locator("table.grid tbody tr")).toHaveCount(10);
|
||
const y = await page.evaluate(() => { window.scrollTo(0, document.documentElement.scrollHeight); return window.scrollY; });
|
||
expect(y).toBeGreaterThan(50);
|
||
await page.locator("table.grid tbody tr").last().getByRole("link").click();
|
||
await expect(page.getByRole("dialog")).toBeVisible();
|
||
expect(await page.evaluate(() => window.scrollY)).toBe(y);
|
||
await page.keyboard.press("Escape");
|
||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||
expect(await page.evaluate(() => window.scrollY)).toBe(y);
|
||
});
|
||
|
||
test("переход по связи и «назад»; ✕ и щелчок по фону; после закрытия «назад» не открывает карточку", async ({ page }) => {
|
||
await login(page); // доска
|
||
await page.getByRole("link", { name: "Задачи", exact: true }).click();
|
||
await page.getByRole("link", { name: "AURORA-9001", exact: true }).click();
|
||
const d = page.getByRole("dialog");
|
||
await d.getByRole("link", { name: "AURORA-9002", exact: true }).click();
|
||
await expect(page).toHaveURL(/\/app\/issues\/AURORA-9002$/);
|
||
await expect(d.getByRole("heading", { name: "API свода" })).toBeVisible();
|
||
await page.goBack();
|
||
await expect(d.getByRole("heading", { name: "Схема свода" })).toBeVisible();
|
||
await d.getByRole("link", { name: "AURORA-9002", exact: true }).click();
|
||
await d.getByRole("button", { name: "Закрыть" }).click();
|
||
await expect(page).toHaveURL(/\/app\/issues$/);
|
||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||
await page.getByRole("link", { name: "AURORA-9003", exact: true }).click();
|
||
await expect(page.getByRole("dialog")).toBeVisible();
|
||
await page.mouse.click(5, 300); // фон слева от окна
|
||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||
await page.goBack();
|
||
await expect(page).toHaveURL(/\/app\/board$/);
|
||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||
});
|
||
|
||
test("прямой адрес и перезагрузка: окно поверх списка, ✕ ведёт в список", async ({ page }) => {
|
||
await login(page, "/app/issues/AURORA-9001");
|
||
const d = page.getByRole("dialog");
|
||
await expect(d.getByRole("heading", { name: "Схема свода" })).toBeVisible();
|
||
await expect(page.getByTestId("page-issues")).toBeAttached();
|
||
await page.reload();
|
||
await expect(page.getByRole("dialog").getByRole("heading", { name: "Схема свода" })).toBeVisible();
|
||
await page.getByRole("dialog").getByRole("button", { name: "Закрыть" }).click();
|
||
await expect(page).toHaveURL(/\/app\/issues$/);
|
||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||
});
|
||
|
||
test("карточка: описание свёрнуто, комментарии новые сверху и скрываются с запоминанием, команды свёрнуты", async ({ page }) => {
|
||
await login(page, "/app/issues/AURORA-9001");
|
||
const d = page.getByRole("dialog");
|
||
await expect(d.getByRole("heading", { name: "Комментарии (3)" })).toBeVisible();
|
||
await expect(d.getByTestId("comments").getByRole("listitem").first()).toContainText("[мост] служебный комментарий");
|
||
await expect(d.getByRole("button", { name: "развернуть" })).toBeVisible();
|
||
await expect(d.locator("pre.description")).toHaveClass(/clamped/); // свёрнуто построчным обрезанием (текст в DOM остаётся)
|
||
const hClamped = (await d.locator("pre.description").boundingBox())!.height;
|
||
expect(await d.locator("pre.description").evaluate((e) => e.scrollHeight > e.clientHeight)).toBe(true);
|
||
await d.getByRole("button", { name: "развернуть" }).click();
|
||
await expect(d.locator("pre.description")).not.toHaveClass(/clamped/);
|
||
expect((await d.locator("pre.description").boundingBox())!.height).toBeGreaterThan(hClamped);
|
||
await expect(d.getByText("Конец описания.")).toBeVisible();
|
||
await expect(d.getByRole("cell", { name: "ensure_fields" })).toBeHidden();
|
||
await d.getByText("Команды моста (2)").click();
|
||
await expect(d.getByRole("cell", { name: "ensure_fields" })).toBeVisible();
|
||
await d.getByRole("button", { name: "Скрыть" }).click();
|
||
await expect(d.getByText("Первый комментарий e2e")).toHaveCount(0);
|
||
await page.reload();
|
||
await expect(page.getByRole("dialog").getByRole("button", { name: "Показать" })).toBeVisible();
|
||
await expect(page.getByRole("dialog").getByText("Первый комментарий e2e")).toHaveCount(0);
|
||
});
|
||
|
||
test("несохранённая заметка: Esc спрашивает, «Остаться» оставляет окно, «Уйти» закрывает", async ({ page }) => {
|
||
await login(page, "/app/issues");
|
||
await page.getByRole("link", { name: "AURORA-9003", exact: true }).click();
|
||
const d = page.getByRole("dialog");
|
||
await d.getByRole("button", { name: "Править" }).click();
|
||
await d.getByLabel("Сделано").fill("черновик");
|
||
await page.keyboard.press("Escape");
|
||
await expect(d.getByText("Есть несохранённые правки заметки. Уйти без сохранения?")).toBeVisible();
|
||
await d.getByRole("button", { name: "Остаться" }).click();
|
||
await expect(d.getByLabel("Сделано")).toHaveValue("черновик");
|
||
await page.keyboard.press("Escape");
|
||
await d.getByRole("button", { name: "Уйти" }).click();
|
||
await expect(page.getByRole("dialog")).toHaveCount(0);
|
||
await expect(page).toHaveURL(/\/app\/issues$/);
|
||
});
|
||
|
||
test("узкий экран: окно на всю ширину, заметки выше связей, без горизонтальной прокрутки", async ({ page }) => {
|
||
await page.setViewportSize({ width: 600, height: 800 });
|
||
await login(page, "/app/issues/AURORA-9001");
|
||
const d = page.getByRole("dialog");
|
||
await expect(d.getByRole("heading", { name: "Схема свода" })).toBeVisible();
|
||
expect((await d.boundingBox())!.width).toBeGreaterThan(590);
|
||
const notesY = (await d.getByRole("heading", { name: "Служебные заметки" }).boundingBox())!.y;
|
||
const linksY = (await d.getByRole("heading", { name: "Связи", exact: true }).boundingBox())!.y;
|
||
expect(notesY).toBeLessThan(linksY);
|
||
expect(await d.evaluate((el) => el.scrollWidth <= el.clientWidth + 1)).toBe(true);
|
||
});
|