BangSo/apps/web/e2e/run-failure.spec.ts

132 lines
6.4 KiB
TypeScript
Raw Normal View History

2026-09-01 16:51:19 +00:00
import { expect, type Locator, type Page, test } from "@playwright/test";
import { captureScreenshot, completeOnboarding, signup } from "./helpers";
function isPresented(error: Locator) {
return error.evaluate((element) => {
const rect = element.getBoundingClientRect();
const topElement = document.elementFromPoint(
rect.left + rect.width / 2,
rect.top + rect.height / 2,
);
return topElement === element || (topElement !== null && element.contains(topElement));
});
}
function seenRunErrorCount(page: Page) {
return page.evaluate(() => {
let count = 0;
for (let index = 0; index < localStorage.length; index += 1) {
if (localStorage.key(index)?.startsWith("rakazo:seen-run-error:")) count += 1;
}
return count;
});
}
test("a failed run is visible once without returning after reload", async ({ page }, testInfo) => {
const stamp = Date.now();
await signup(page, `run-failure-${stamp}@rakazo.test`, "password12", "Run Failure");
await completeOnboarding(page);
// "fail this run" makes the scripted runtime throw, so the run fails the same way a
// real provider error would, without depending on how models are configured.
await page.getByPlaceholder(/^Message /).fill("fail this run");
await page.getByRole("button", { name: "Send" }).click();
const error = page.getByTestId("composer-error");
await expect(error).toBeVisible({ timeout: 30_000 });
await expect(error).toContainText("Scripted run failure");
await captureScreenshot(page, testInfo, "new-run-error-visible");
await page.reload();
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true");
await expect(
page.getByTestId("transcript").getByText("fail this run", { exact: true }),
).toBeVisible();
await expect(error).toBeHidden();
await captureScreenshot(page, testInfo, "seen-run-error-hidden-after-reload");
await page.getByPlaceholder(/^Message /).fill("fail this run");
await page.getByRole("button", { name: "Send" }).click();
await expect(error).toBeVisible({ timeout: 30_000 });
await expect(error).toContainText("Scripted run failure");
const dismissError = page.getByTestId("composer-error-dismiss");
await dismissError.focus();
await expect(dismissError).toBeFocused();
await dismissError.press("Enter");
await expect(error).toBeHidden();
await expect(page.getByPlaceholder(/^Message /)).toBeFocused();
});
test("a covered run error is not remembered until it is presented", async ({ page }, testInfo) => {
const stamp = Date.now();
await signup(page, `covered-run-failure-${stamp}@rakazo.test`, "password12", "Covered Failure");
await completeOnboarding(page);
await page.setViewportSize({ width: 390, height: 844 });
await page.getByPlaceholder(/^Message /).fill("fail this run");
const sendButton = await page.getByRole("button", { name: "Send" }).elementHandle();
if (!sendButton) throw new Error("Send button not found");
await page.getByRole("button", { name: "Open navigation" }).click();
await expect(page.getByRole("button", { name: "Close navigation" })).toBeVisible();
await expect(page.locator("main")).toHaveAttribute("aria-hidden", "true");
await expect(page.locator("main")).toHaveJSProperty("inert", true);
await sendButton.evaluate((button) => (button as HTMLButtonElement).click());
const error = page.getByTestId("composer-error");
await expect(error).toContainText("Scripted run failure", { timeout: 30_000 });
expect(await isPresented(error)).toBe(false);
await captureScreenshot(page, testInfo, "run-error-covered-by-mobile-navigation");
await page.reload();
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true");
await expect(error).toBeVisible();
expect(await isPresented(error)).toBe(true);
await captureScreenshot(page, testInfo, "covered-run-error-presented-after-reload");
await page.reload();
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true");
await expect(error).toBeHidden();
const recordedErrorCount = await seenRunErrorCount(page);
await page.getByPlaceholder(/^Message /).fill("fail this run");
const nextSendButton = await page.getByRole("button", { name: "Send" }).elementHandle();
if (!nextSendButton) throw new Error("Send button not found");
await page.getByRole("button", { name: "Open navigation" }).click();
await nextSendButton.evaluate((button) => (button as HTMLButtonElement).click());
await expect(error).toContainText("Scripted run failure", { timeout: 30_000 });
await page.getByRole("button", { name: "Close navigation" }).click();
await expect.poll(() => isPresented(error)).toBe(true);
await expect.poll(() => seenRunErrorCount(page)).toBe(recordedErrorCount + 1);
await captureScreenshot(page, testInfo, "covered-run-error-presented-after-drawer-close");
await page.reload();
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true");
await expect(error).toBeHidden();
await page.getByRole("button", { name: "Open navigation" }).click();
await expect(page.locator("main")).toHaveJSProperty("inert", true);
await page.setViewportSize({ width: 1280, height: 720 });
await expect(page.locator("main")).not.toHaveAttribute("aria-hidden", "true");
await expect(page.locator("main")).toHaveJSProperty("inert", false);
await page.getByPlaceholder(/^Message /).fill("fail this run");
const modalSendButton = await page.getByRole("button", { name: "Send" }).elementHandle();
if (!modalSendButton) throw new Error("Send button not found");
await page.getByTitle("Create").click();
await page.getByRole("button", { name: "New space" }).click();
const newSpaceDialog = page.getByRole("dialog", { name: "New space" });
await expect(newSpaceDialog).toBeVisible();
await modalSendButton.evaluate((button) => (button as HTMLButtonElement).click());
await expect(error).toContainText("Scripted run failure", { timeout: 30_000 });
expect(await isPresented(error)).toBe(false);
await expect.poll(() => seenRunErrorCount(page)).toBe(recordedErrorCount + 1);
await newSpaceDialog.getByRole("button", { name: "Cancel" }).click();
await expect(newSpaceDialog).toHaveCount(0);
await expect.poll(() => isPresented(error)).toBe(true);
await expect.poll(() => seenRunErrorCount(page)).toBe(recordedErrorCount + 2);
await page.reload();
await expect(page.getByTestId("shell-root")).toHaveAttribute("data-ready", "true");
await expect(error).toBeHidden();
});