Files
itworx-knowledge-hub-Public/tests/e2e/specs/knowledge-editing.spec.ts
T

142 lines
6.8 KiB
TypeScript

import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";
import { authenticatedStatePath } from "../global-setup";
import { expectAuthenticatedShell, fillMarkdown, openNewKnowledgePage, readMarkdown } from "./support/v2";
// Reuses the single shared login performed once in global-setup.ts (the login
// endpoint is rate-limited — see that file's comment) rather than each test signing
// in for itself; only auth-journey.spec.ts exercises the login endpoint directly.
test.use({ storageState: authenticatedStatePath });
test.describe("knowledge page editing journey", () => {
test("managed import markers stay stored and editable but never appear in the reader view", async ({ page }) => {
const uniqueTitle = `E2E-beheerde-bron ${Date.now()}`;
const notes = "Mijn byte-beschermde notitie.";
const markdown = [
"<!-- managed-source:start -->",
"# Veilige broninhoud",
"<!-- unknown-control -->",
"<script>alert('nooit uitvoeren')</script>",
"<!-- managed-source:end -->",
"",
"<!-- user-notes:start -->",
notes,
"<!-- user-notes:end -->"
].join("\n");
await page.goto("/");
await expectAuthenticatedShell(page);
await openNewKnowledgePage(page);
await page.getByLabel("Paginatitel").fill(uniqueTitle);
await fillMarkdown(page, markdown);
await page.getByLabel(/Labels/).fill("source:canvas, course:zc0026, managed-source");
await page.getByRole("button", { name: "Publiceren", exact: true }).click();
const article = page.locator("article.page-content");
await expect(article).toContainText("Veilige broninhoud");
await expect(article).toContainText(notes);
await expect(article).toContainText("unknown-control");
await expect(article).not.toContainText("managed-source");
await expect(article).not.toContainText("user-notes");
await expect(article.locator("script")).toHaveCount(0);
await expect(page.getByText("Broninformatie en beheerstatus")).toBeVisible();
await expect(page.locator(".tag-chip", { hasText: "source:canvas" })).toHaveCount(0);
await page.getByRole("button", { name: "Bewerken" }).click();
await expect(page.getByRole("note")).toContainText("Laat de vier importmarkeringen");
expect(await readMarkdown(page)).toBe(markdown);
const republished = markdown.replace("# Veilige broninhoud", "# Veilige broninhoud bijgewerkt");
await fillMarkdown(page, republished);
await page.getByRole("button", { name: "Wijzigingen publiceren" }).click();
await expect(article).toContainText("Veilige broninhoud bijgewerkt");
await expect(article).toContainText(notes);
await expect(article).not.toContainText("managed-source");
});
test("a page can be created, edited, moved to the trash and restored", async ({ page }) => {
const uniqueTitle = `E2E-testpagina ${Date.now()}`;
await page.goto("/");
await expectAuthenticatedShell(page);
// --- Create -----------------------------------------------------------------
await openNewKnowledgePage(page);
const createAccessibility = await new AxeBuilder({ page }).analyze();
expect(createAccessibility.violations).toEqual([]);
await page.getByLabel("Paginatitel").fill(uniqueTitle);
await fillMarkdown(page, "# Inleiding\n\nDit is een testpagina voor de E2E-suite.");
await page.getByRole("button", { name: "Publiceren", exact: true }).click();
await expect(page.getByRole("heading", { name: uniqueTitle })).toBeVisible();
await expect(page.getByText("Inleiding")).toBeVisible();
const viewAccessibility = await new AxeBuilder({ page }).analyze();
expect(viewAccessibility.violations).toEqual([]);
// --- Edit ---------------------------------------------------------------------
await page.getByRole("button", { name: "Bewerken" }).click();
await expect(page.getByRole("heading", { name: `Bewerken: ${uniqueTitle}` })).toBeVisible();
const updatedTitle = `${uniqueTitle} (bijgewerkt)`;
await page.getByLabel("Paginatitel").fill(updatedTitle);
await page.getByRole("button", { name: "Wijzigingen publiceren" }).click();
await expect(page.getByRole("heading", { name: updatedTitle })).toBeVisible();
// --- Trash and restore ---------------------------------------------------------
await page.getByRole("button", { name: "Meer pagina-acties" }).click();
await page.getByRole("menuitem", { name: "Naar prullenbak" }).click();
await expect(page.getByText("Deze pagina staat in de prullenbak.")).toBeVisible();
await page.getByRole("button", { name: "Herstellen" }).click();
await expect(page.getByText("Deze pagina staat in de prullenbak.")).not.toBeVisible();
});
test("publishing against a stale version shows an explicit conflict resolution flow", async ({
page,
context
}) => {
const uniqueTitle = `E2E-conflictpagina ${Date.now()}`;
await page.goto("/");
await expectAuthenticatedShell(page);
await openNewKnowledgePage(page);
await page.getByLabel("Paginatitel").fill(uniqueTitle);
await fillMarkdown(page, "Oorspronkelijke inhoud.");
await page.getByRole("button", { name: "Publiceren", exact: true }).click();
await expect(page.getByRole("heading", { name: uniqueTitle })).toBeVisible();
// A second tab opens the same shareable V2 deep link, simulating two concurrent
// editors without relying on transient component state.
const pageUrl = page.url();
const secondPage = await context.newPage();
await secondPage.goto(pageUrl);
await expectAuthenticatedShell(secondPage);
await expect(secondPage.getByRole("heading", { name: uniqueTitle })).toBeVisible();
await secondPage.getByRole("button", { name: "Bewerken" }).click();
await secondPage.getByLabel("Paginatitel").fill(`${uniqueTitle} (tweede editor)`);
// The first tab publishes first, advancing the page's revision/ETag.
await page.getByRole("button", { name: "Bewerken" }).click();
await page.getByLabel("Paginatitel").fill(`${uniqueTitle} (eerste editor)`);
await page.getByRole("button", { name: "Wijzigingen publiceren" }).click();
await expect(page.getByRole("heading", { name: `${uniqueTitle} (eerste editor)` })).toBeVisible();
// The second tab's publish attempt now targets a stale ETag and must surface an
// explicit conflict rather than silently overwriting the first editor's change.
await secondPage.getByRole("button", { name: "Wijzigingen publiceren" }).click();
await expect(secondPage.getByText("Versieconflict")).toBeVisible();
const conflictAccessibility = await new AxeBuilder({ page: secondPage }).analyze();
expect(conflictAccessibility.violations).toEqual([]);
await secondPage.getByRole("button", { name: "Serverversie gebruiken" }).click();
await expect(secondPage.getByLabel("Paginatitel")).toHaveValue(`${uniqueTitle} (eerste editor)`);
await secondPage.close();
});
});