mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-06 08:24:46 +00:00
test(e2e): keep transient developer toasts from stalling checks
Concurrent locator handlers can wait for a dismiss button another handler removed. Dismiss existing toast DOM at document lifetime, including its open shadow root, without intercepting app actions.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { metroTest as test, expect } from "../support/fixtures";
|
||||
import { installDeveloperToastDismissal } from "../support/developer-ui.mjs";
|
||||
import type { Page } from "@playwright/test";
|
||||
|
||||
async function showTransientDeveloperToast(page: Page, shadow: boolean) {
|
||||
await page.evaluate((useShadow) => {
|
||||
const toast = document.createElement("div");
|
||||
toast.id = "error-toast";
|
||||
document.body.append(toast);
|
||||
const root = useShadow ? toast.attachShadow({ mode: "open" }) : toast;
|
||||
const button = document.createElement("button");
|
||||
button.style.cssText = "width:32px;height:32px";
|
||||
button.addEventListener("click", () => button.remove());
|
||||
root.append(button);
|
||||
}, shadow);
|
||||
}
|
||||
|
||||
async function openTransientDeveloperToast(page: Page) {
|
||||
await page.setContent("<button>Continue</button>");
|
||||
await showTransientDeveloperToast(page, false);
|
||||
await installDeveloperToastDismissal(page);
|
||||
}
|
||||
|
||||
async function navigateWithDeveloperToastDismissal(page: Page) {
|
||||
await installDeveloperToastDismissal(page);
|
||||
await page.goto("data:text/html,<button>Continue</button>");
|
||||
await showTransientDeveloperToast(page, true);
|
||||
}
|
||||
|
||||
async function inspectLayoutWhileToastDisappears(page: Page) {
|
||||
const action = page.getByRole("button", { name: "Continue", exact: true });
|
||||
const boxes = await Promise.all(Array.from({ length: 4 }, () => action.boundingBox()));
|
||||
for (const box of boxes) expect(box).not.toBeNull();
|
||||
await expect(page.locator("#error-toast").getByRole("button")).toHaveCount(0);
|
||||
await action.click();
|
||||
}
|
||||
|
||||
test("a disappearing developer toast does not stall concurrent layout checks", async ({ page }) => {
|
||||
test.setTimeout(10000);
|
||||
await openTransientDeveloperToast(page);
|
||||
await inspectLayoutWhileToastDisappears(page);
|
||||
});
|
||||
|
||||
test("developer toast dismissal survives navigation and observes Expo shadow-root updates", async ({
|
||||
page,
|
||||
}) => {
|
||||
test.setTimeout(10000);
|
||||
await navigateWithDeveloperToastDismissal(page);
|
||||
await inspectLayoutWhileToastDisappears(page);
|
||||
await page.evaluate(() => {
|
||||
const root = document.getElementById("error-toast")!.shadowRoot!;
|
||||
const replacement = document.createElement("button");
|
||||
replacement.style.cssText = "width:32px;height:32px";
|
||||
replacement.addEventListener("click", () => replacement.remove());
|
||||
root.append(replacement);
|
||||
});
|
||||
await inspectLayoutWhileToastDisappears(page);
|
||||
});
|
||||
@@ -1,10 +1,27 @@
|
||||
/** @param {import('@playwright/test').Page} page */
|
||||
export async function installDeveloperToastDismissal(page) {
|
||||
// Developer chrome must not cover app actions or move the test's pointer/focus.
|
||||
// Console errors remain in the runner's logs.
|
||||
const dismiss = page.locator("#error-toast").getByRole("button", { name: "", exact: true });
|
||||
await page.addLocatorHandler(dismiss, () => dismiss.dispatchEvent("click"), {
|
||||
// A new logged error can replace the toast before the old one disappears.
|
||||
noWaitAfter: true,
|
||||
});
|
||||
// Keep developer chrome out of app actions without pointer/focus changes.
|
||||
// Locator handlers can deadlock when concurrent checks dismiss the same toast.
|
||||
const install = () => {
|
||||
let observedRoot;
|
||||
const options = { childList: true, subtree: true };
|
||||
const dismiss = () => {
|
||||
const toast = document.getElementById("error-toast");
|
||||
const root = toast?.shadowRoot ?? toast;
|
||||
if (root && root !== observedRoot) {
|
||||
observer.disconnect();
|
||||
observer.observe(document, options);
|
||||
observer.observe(root, options);
|
||||
observedRoot = root;
|
||||
}
|
||||
// Expo's toast root contains dismiss buttons; its overlay has a different ID.
|
||||
for (const button of root?.querySelectorAll("button") ?? [])
|
||||
button.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
};
|
||||
const observer = new MutationObserver(dismiss);
|
||||
observer.observe(document, options);
|
||||
dismiss();
|
||||
};
|
||||
await page.addInitScript(install);
|
||||
await page.evaluate(install);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user