105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
/**
|
|
* Thread resolve/unresolve tests - adapted from old devtalk.e2e.spec.ts
|
|
* "thread behavior" block.
|
|
*
|
|
* Changes from old plugin:
|
|
* - No sidebar panel with visual resolve/unresolve buttons on server-rendered cards
|
|
* - Resolve functionality exists at API level (threads:resolve-thread)
|
|
* - Resolved threads get .threads-thread--resolved class (opacity: 0.55)
|
|
* - The Lit-rendered threads-thread component has Resolve/Unresolve buttons,
|
|
* but the current inline mode uses server-rendered HTML
|
|
*/
|
|
|
|
import { test, expect } from "@playwright/test";
|
|
import { Actor } from "./screenplay.ts";
|
|
import { cleanThreads, setAuthor, seedAndReload, waitForReload } from "./helpers.ts";
|
|
|
|
let user: Actor;
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
user = new Actor("TestUser", page);
|
|
await page.goto("/");
|
|
await page.waitForSelector("threads-app", { state: "attached", timeout: 10_000 });
|
|
await setAuthor(page, "TestUser");
|
|
await cleanThreads(page);
|
|
await waitForReload(page);
|
|
});
|
|
|
|
test.describe("resolve thread API", () => {
|
|
test("resolving a thread sets resolved state", async () => {
|
|
const { id: threadId } = await seedAndReload(user.page, {
|
|
body: "Thread to resolve",
|
|
});
|
|
|
|
// Resolve via API
|
|
const resolved = await user.page.evaluate(
|
|
async ({ threadId }) => {
|
|
const file = document.body.dataset["sourceFile"];
|
|
return docmd.call("threads:resolve-thread", {
|
|
file,
|
|
threadId,
|
|
resolved_by: "TestUser",
|
|
});
|
|
},
|
|
{ threadId },
|
|
);
|
|
|
|
expect(resolved.resolved).toBeTruthy();
|
|
|
|
// The resolve call wrote to the file, triggering hot-reload. Wait for it.
|
|
await waitForReload(user.page);
|
|
|
|
// Verify via re-fetch
|
|
const threads = await user.page.evaluate(async () => {
|
|
const file = document.body.dataset["sourceFile"];
|
|
return docmd.call("threads:get-threads", { file });
|
|
});
|
|
|
|
const thread = threads.find((t: any) => t.id === threadId);
|
|
expect(thread.resolved).toBeTruthy();
|
|
});
|
|
|
|
test("unresolving a thread toggles back to open", async () => {
|
|
// Seed a resolved thread
|
|
const { id: threadId } = await seedAndReload(user.page, {
|
|
body: "Resolved thread for unresolve test",
|
|
resolved: true,
|
|
});
|
|
|
|
// Unresolve by calling resolve-thread again (it toggles)
|
|
const unresolved = await user.page.evaluate(
|
|
async ({ threadId }) => {
|
|
const file = document.body.dataset["sourceFile"];
|
|
return docmd.call("threads:resolve-thread", {
|
|
file,
|
|
threadId,
|
|
resolved_by: "TestUser",
|
|
});
|
|
},
|
|
{ threadId },
|
|
);
|
|
|
|
expect(unresolved.resolved).toBeFalsy();
|
|
});
|
|
|
|
test("resolved thread gets --resolved CSS class on server render", async () => {
|
|
const { id: threadId } = await seedAndReload(user.page, {
|
|
body: "Thread for CSS test",
|
|
resolved: true,
|
|
});
|
|
|
|
// The resolved state requires an extra reload since seedThread does
|
|
// add-thread + resolve as separate file writes
|
|
await waitForReload(user.page);
|
|
|
|
const threadEl = user.page.locator(`.threads-thread[data-thread-id="${threadId}"]`);
|
|
await expect(threadEl).toBeAttached({ timeout: 5_000 });
|
|
|
|
// Server-rendered resolved threads should have the resolved class
|
|
const hasResolvedClass = await threadEl.evaluate((el) =>
|
|
el.classList.contains("threads-thread--resolved"),
|
|
);
|
|
expect(hasResolvedClass).toBe(true);
|
|
});
|
|
});
|