test(ui): protect dashboard form cleanup

This commit is contained in:
Yuneng Jiang 2026-09-17 23:20:54 -07:00
parent 43f096dde8
commit 0dc2f0b1c1
No known key found for this signature in database
3 changed files with 61 additions and 58 deletions

View file

@ -12,17 +12,41 @@ export async function captureRequestBody(
match: { method: string; urlIncludes: string },
action: () => Promise<void>,
): Promise<Record<string, any>> {
const pending = page.waitForRequest((req) => req.method() === match.method && req.url().includes(match.urlIncludes));
const pending = page.waitForRequest(
(req) =>
req.method() === match.method && req.url().includes(match.urlIncludes),
);
await action();
const request = await pending;
return JSON.parse(request.postData() ?? "{}") as Record<string, any>;
}
/** Reads an endpoint as the master key, so a failure is bad data and not an expired UI token. */
export async function readBack<T = any>(page: Page, endpoint: string): Promise<T> {
export async function readBack<T = any>(
page: Page,
endpoint: string,
): Promise<T> {
const res = await page.request.get(endpoint, {
headers: { Authorization: `Bearer ${masterKey()}` },
});
expect(res.ok(), `GET ${endpoint}`).toBe(true);
return (await res.json()) as T;
}
export async function runWithCleanup(
action: () => Promise<void>,
cleanup: () => Promise<boolean>,
): Promise<void> {
const outcome = await action().then(
() => ({ status: "success" as const }),
(error: unknown) => ({ status: "failure" as const, error }),
);
try {
if (outcome.status === "failure") throw outcome.error;
} finally {
const cleanupSucceeded = await cleanup().catch(() => false);
if (outcome.status === "success" && !cleanupSucceeded) {
throw new Error("Failed to clean up UI E2E resource");
}
}
}

View file

@ -3,6 +3,7 @@ import { test, expect } from "@playwright/test";
import { ADMIN_STORAGE_PATH } from "../../constants";
import { Page as DashboardPage } from "../../fixtures/pages";
import { navigateToPage } from "../../helpers/navigation";
import { runWithCleanup } from "../../helpers/roundTrip";
import { masterKey, uniqueSuffix } from "../../helpers/traffic";
test.use({ storageState: ADMIN_STORAGE_PATH });
@ -13,21 +14,9 @@ test.describe("Prompt upload form", () => {
}) => {
const promptId = `e2e-prompt-${uniqueSuffix()}`;
const promptContent = "Hello {{name}}";
const cleanup = async (): Promise<boolean> => {
try {
const response = await page.request.delete(
`/prompts/${encodeURIComponent(promptId)}?environment=development`,
{
headers: { Authorization: `Bearer ${masterKey()}` },
},
);
return response.ok();
} catch {
return false;
}
};
const testOutcome = await (async () => {
try {
await runWithCleanup(
async () => {
await navigateToPage(page, DashboardPage.Prompts);
await page.getByRole("button", { name: "Upload .prompt File" }).click();
await expect(
@ -71,17 +60,16 @@ test.describe("Prompt upload form", () => {
})
.toContain(promptContent);
await expect(page.getByText(promptId, { exact: true })).toBeVisible();
return { passed: true as const };
} catch (error) {
return { passed: false as const, error };
}
})();
try {
if (!testOutcome.passed) throw testOutcome.error;
} finally {
const cleanupSucceeded = await cleanup();
if (testOutcome.passed) expect(cleanupSucceeded).toBe(true);
}
},
async () => {
const response = await page.request.delete(
`/prompts/${encodeURIComponent(promptId)}?environment=development`,
{
headers: { Authorization: `Bearer ${masterKey()}` },
},
);
return response.ok();
},
);
});
});

View file

@ -3,7 +3,11 @@ import { test, expect } from "@playwright/test";
import { ADMIN_STORAGE_PATH } from "../../constants";
import { Page as DashboardPage } from "../../fixtures/pages";
import { navigateToPage } from "../../helpers/navigation";
import { captureRequestBody, readBack } from "../../helpers/roundTrip";
import {
captureRequestBody,
readBack,
runWithCleanup,
} from "../../helpers/roundTrip";
import { masterKey, uniqueSuffix } from "../../helpers/traffic";
test.use({ storageState: ADMIN_STORAGE_PATH });
@ -13,22 +17,9 @@ test.describe("Tag management", () => {
const tagName = `e2e-tag-${uniqueSuffix()}`;
const description = "synthetic tag description";
const updatedDescription = `${description} updated`;
const cleanup = async (): Promise<boolean> => {
try {
const response = await page.request.post("/tag/delete", {
headers: {
Authorization: `Bearer ${masterKey()}`,
"Content-Type": "application/json",
},
data: { name: tagName },
});
return response.ok();
} catch {
return false;
}
};
const testOutcome = await (async () => {
try {
await runWithCleanup(
async () => {
await navigateToPage(page, DashboardPage.TagManagement);
await page.getByRole("button", { name: "+ Create New Tag" }).click();
await expect(
@ -76,17 +67,17 @@ test.describe("Tag management", () => {
return info[tagName]?.description;
})
.toBe(updatedDescription);
return { passed: true as const };
} catch (error) {
return { passed: false as const, error };
}
})();
try {
if (!testOutcome.passed) throw testOutcome.error;
} finally {
const cleanupSucceeded = await cleanup();
if (testOutcome.passed) expect(cleanupSucceeded).toBe(true);
}
},
async () => {
const response = await page.request.post("/tag/delete", {
headers: {
Authorization: `Bearer ${masterKey()}`,
"Content-Type": "application/json",
},
data: { name: tagName },
});
return response.ok();
},
);
});
});