feat: закрыть остаточный backlog

- keyset-пагинация аудита с курсором (occurred_at, id) и UI «Показать ещё»
- пакетный /api/v1/labs/details и переход progress на один запрос
- абсолютный потолок сессии 30 дней (identity V12 + web), очистка refresh
- админская инвентаризация legacy-активов (/admin/legacy-assets, скрипт)
- E2E в Chromium/Firefox/WebKit (18/18), CI preflight
- LDD: 51 claim, 346 тестов, docs и handoff обновлены
This commit is contained in:
2026-10-28 19:29:23 +03:00
parent d45137220c
commit 1e1e9ae0e4
64 changed files with 2124 additions and 372 deletions

View File

@@ -204,3 +204,39 @@ test("student submits a solution and mobile teacher page renders", async ({ page
await expect(page.locator("h1")).toContainText(seeded.courseTitle);
await expect(page.locator("body")).toContainText(seeded.groupName);
});
test("admin paginates audit with cursor and returns to start", async ({ page }) => {
await login(page, seeded.adminLogin, seeded.adminPassword, "**/admin");
await page.goto("/admin/audit?limit=1");
await expect(page.locator("body")).toContainText("Страница 1");
const nextLink = page.getByRole("link", { name: "Показать ещё" });
await expect(nextLink).toBeVisible();
await expect(nextLink).toHaveAttribute("href", /cursor=/);
await nextLink.click();
await expect(page).toHaveURL(/cursor=/);
await expect(page.locator("body")).toContainText("Продолжение");
await expect(page.getByRole("link", { name: "В начало" })).toBeVisible();
await page.getByRole("link", { name: "Показать ещё" }).click();
await expect(page).toHaveURL(/cursor=/);
await expect(page.locator("body")).toContainText("Продолжение");
await expect(page.getByRole("link", { name: "В начало" })).toBeVisible();
await page.getByRole("link", { name: "В начало" }).click();
await expect(page).not.toHaveURL(/cursor=/);
await expect(page.locator("body")).toContainText("Страница 1");
});
test("admin opens legacy assets inventory", async ({ page }) => {
await login(page, seeded.adminLogin, seeded.adminPassword, "**/admin");
await page.goto("/admin/legacy-assets");
await expect(page.locator("h1")).toContainText("Активы");
await expect(page.locator("body")).toContainText("только администраторам");
const assetRow = page.locator("table tbody tr td.font-mono").first();
const empty = page.getByText("Бесхозных файлов нет.");
await expect(assetRow.or(empty)).toBeVisible();
await expect(page.locator(".toast-error")).toHaveCount(0);
});

View File

@@ -23,5 +23,13 @@ export default defineConfig({
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
],
});