Publish curated projectbrain source from 88fab8df1542019289e947f092c2b387e0825c60
This commit is contained in:
1 parent
48e72d07e0
commit
eca2891b07
45 files changed
+2697
-328
No files matched your search
@@ -39,6 +39,105 @@ const autoModeState = (): AutoModeState => ({
|
||||
updatedBy: "owner",
|
||||
});
|
||||
|
||||
const queueState = (manualOrder = false): AutoModeState => {
|
||||
const base = autoModeState();
|
||||
const roadmap = base.roadmap!;
|
||||
return {
|
||||
...base,
|
||||
roadmap: {
|
||||
...roadmap,
|
||||
phases: roadmap.phases.map((phase) => ({
|
||||
...phase,
|
||||
items: [
|
||||
{ id: "item-a", title: "Item A", status: "pending", attempts: 0, ...(manualOrder ? { manualOrder: 2 } : {}) },
|
||||
{ id: "item-b", title: "Item B", status: "pending", attempts: 0, ...(manualOrder ? { manualOrder: 1 } : {}) },
|
||||
],
|
||||
})),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const expectQueueOrder = async (page: import("@playwright/test").Page, firstTitle: string) => {
|
||||
const rows = page.locator('section[aria-labelledby="auto-queue-order-heading"] > div.space-y-2 > div');
|
||||
await expect(rows).toHaveCount(2);
|
||||
await expect(rows.nth(0)).toContainText(firstTitle);
|
||||
};
|
||||
|
||||
const exerciseStaleQueueRead = async (
|
||||
page: import("@playwright/test").Page,
|
||||
mutation: "reorder" | "reset",
|
||||
) => {
|
||||
const beforeMutation = queueState(mutation === "reset");
|
||||
let persistedState = beforeMutation;
|
||||
let getCount = 0;
|
||||
let releaseStaleGet!: () => void;
|
||||
let markStaleGetStarted!: () => void;
|
||||
let releaseMutation!: () => void;
|
||||
let markMutationStarted!: () => void;
|
||||
const staleGetGate = new Promise<void>((resolve) => { releaseStaleGet = resolve; });
|
||||
const staleGetStarted = new Promise<void>((resolve) => { markStaleGetStarted = resolve; });
|
||||
const mutationGate = new Promise<void>((resolve) => { releaseMutation = resolve; });
|
||||
const mutationStarted = new Promise<void>((resolve) => { markMutationStarted = resolve; });
|
||||
|
||||
await page.route(`**/api/projects/${projectId}/autonomy**`, async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method() === "GET") {
|
||||
getCount += 1;
|
||||
if (getCount === 2) {
|
||||
markStaleGetStarted();
|
||||
await staleGetGate;
|
||||
await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(envelope(beforeMutation)) });
|
||||
return;
|
||||
}
|
||||
await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(envelope(persistedState)) });
|
||||
return;
|
||||
}
|
||||
if (mutation === "reorder" && request.method() === "PUT") {
|
||||
const { itemIds } = request.postDataJSON() as { itemIds: string[] };
|
||||
markMutationStarted();
|
||||
await mutationGate;
|
||||
const positions = new Map(itemIds.map((id, index) => [id, index]));
|
||||
persistedState = {
|
||||
...beforeMutation,
|
||||
roadmap: {
|
||||
...beforeMutation.roadmap!,
|
||||
phases: beforeMutation.roadmap!.phases.map((phase) => ({
|
||||
...phase,
|
||||
items: phase.items.map((item) => positions.has(item.id)
|
||||
? { ...item, manualOrder: positions.get(item.id) }
|
||||
: item),
|
||||
})),
|
||||
},
|
||||
};
|
||||
} else if (mutation === "reset" && request.method() === "DELETE") {
|
||||
markMutationStarted();
|
||||
await mutationGate;
|
||||
persistedState = queueState();
|
||||
}
|
||||
await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(envelope(persistedState)) });
|
||||
});
|
||||
|
||||
await page.goto(`/projects/${projectId}/auto`);
|
||||
await expect(page.getByRole("heading", { name: "Auto Mode", exact: true })).toBeVisible();
|
||||
await page.getByText("Roadmap en wachtrij", { exact: true }).click();
|
||||
await expectQueueOrder(page, mutation === "reset" ? "Item B" : "Item A");
|
||||
|
||||
await page.getByRole("button", { name: "Vernieuwen", exact: true }).click();
|
||||
await staleGetStarted;
|
||||
if (mutation === "reorder") {
|
||||
await page.getByRole("button", { name: "Item B omhoog" }).click();
|
||||
} else {
|
||||
await page.getByRole("button", { name: "Automatische volgorde herstellen" }).click();
|
||||
}
|
||||
await mutationStarted;
|
||||
await expect(page.getByText("Opslaan…", { exact: true })).toBeVisible();
|
||||
|
||||
releaseMutation();
|
||||
await expectQueueOrder(page, mutation === "reset" ? "Item A" : "Item B");
|
||||
releaseStaleGet();
|
||||
await expectQueueOrder(page, mutation === "reset" ? "Item A" : "Item B");
|
||||
};
|
||||
|
||||
test("attention inbox exposes every visible item as an actionable destination", async ({ page }) => {
|
||||
await page.goto(`/projects/${projectId}/attention`);
|
||||
await expect(page.getByRole("heading", { name: "Jouw aandacht", exact: true })).toBeVisible();
|
||||
@@ -110,3 +209,11 @@ test("Auto Mode distinguishes queued work from real execution and protects roadm
|
||||
const accessibility = await new AxeBuilder({ page }).analyze();
|
||||
expect(accessibility.violations.filter((violation) => ["serious", "critical"].includes(violation.impact ?? ""))).toEqual([]);
|
||||
});
|
||||
|
||||
test("Auto Mode ignores an older read after saving a reordered queue", async ({ page }) => {
|
||||
await exerciseStaleQueueRead(page, "reorder");
|
||||
});
|
||||
|
||||
test("Auto Mode ignores an older read after resetting queue order", async ({ page }) => {
|
||||
await exerciseStaleQueueRead(page, "reset");
|
||||
});
|
||||
Reference in new issue
Block a user