Frontend Labs
⋯

tests/lab.spec.js

import { test, expect } from "@playwright/test";

const STATIONS = ["overview", "network", "render", "eventloop", "engine", "threads", "storage", "vitals", "debug"];

// Fail any test on an error the page did not throw on purpose.
test.beforeEach(async ({ page }) => {
  page.on("pageerror", (err) => {
    if (!/Boom from a timer|Nobody handled me/.test(err.message)) throw err;
  });
});

const open = async (page, id) => {
  await page.goto(`/#/${id}`);
  await expect(page.locator(".station h2")).toBeVisible();
};

for (const id of STATIONS) {
  test(`station ${id} renders`, async ({ page }) => {
    await open(page, id);
    await expect(page.getByRole("link", { name: new RegExp(id === "eventloop" ? "event loop" : "", "i") }).first()).toBeVisible();
    await expect(page.getByRole("list", { name: "Missions" })).toBeVisible();
  });
}

test("the server is cross-origin isolated", async ({ page }) => {
  await open(page, "overview");
  expect(await page.evaluate(() => crossOriginIsolated)).toBe(true);
});

test("the event-loop model matches the real engine for every snippet", async ({ page }) => {
  await open(page, "eventloop");
  for (const tab of await page.getByRole("tab").all()) {
    await tab.click();
    await page.getByRole("button", { name: "Run it for real" }).click();
    await expect(page.locator("[data-match]")).toHaveAttribute("data-match", "true");
  }
  await expect(page.locator('[data-mission="verify"]')).toHaveClass(/done/);
});

test("stepping through a snippet fills the queues", async ({ page }) => {
  await open(page, "eventloop");
  const next = page.getByRole("button", { name: "Step ▶" });
  for (let i = 0; i < 4; i++) await next.click();
  await expect(page.locator(".box.webapis .token")).toHaveCount(1);
  await expect(page.locator(".box.micro .token")).toHaveCount(1);
});

test("request burst: protocol decides how many connections", async ({ page }, testInfo) => {
  await open(page, "network");
  await page.getByLabel("Number of requests").fill("12");
  await page.getByLabel("Server delay (ms)").fill("300");
  await page.getByRole("button", { name: "Fire the burst" }).click();
  const readout = (label) => page.locator(".readout", { hasText: label }).locator("b");
  if (testInfo.project.name === "h2") {
    await expect(readout("Protocol")).toHaveText("h2");
    await expect(readout("Connections used")).toHaveText("1");
  } else {
    await expect(readout("Protocol")).toHaveText("http/1.1");
    // 6 connections per origin, give or take one the page already had open
    await expect(readout("Connections used")).toHaveText(/^[2-7]$/);
  }
  await expect(page.locator(".wf-row")).toHaveCount(12);
});

test("whoami reports TLS 1.3 over HTTP/2", async ({ page }, testInfo) => {
  test.skip(testInfo.project.name !== "h2", "TLS only on the https project");
  await open(page, "network");
  await page.getByRole("button", { name: "Ask the server" }).click();
  await expect(page.locator(".kv dd").first()).toHaveText("2.0");
  await expect(page.getByText("TLSv1.3")).toBeVisible();
});

test("layout thrashing is slower than batching", async ({ page }) => {
  await open(page, "render");
  await page.getByRole("button", { name: "Interleave read/write" }).click();
  await page.getByRole("button", { name: "Batch reads, then writes" }).click();
  const value = async (label) => parseFloat(await page.locator(".readout", { hasText: label }).locator("b").innerText());
  expect(await value("interleaved")).toBeGreaterThan(await value("batched"));
});

test("the render tree drops display:none but keeps ::before", async ({ page }) => {
  await open(page, "render");
  await expect(page.locator(".tree .gone")).toContainText("p [hidden] (display:none → no box)");
  await expect(page.locator(".tree .pseudo")).toContainText("::before");
});

test("Atomics fixes the data race", async ({ page }) => {
  await open(page, "threads");
  await page.getByRole("button", { name: "Fix with Atomics.add" }).click();
  await expect(page.getByText(/Atomics\.add: expected 4,000,000, got 4,000,000 → 0 updates lost/)).toBeVisible({ timeout: 15000 });
});

test("a worker keeps the page responsive", async ({ page }) => {
  await open(page, "threads");
  await page.getByLabel("How much work").selectOption("3000000");
  await page.getByRole("button", { name: "Run in a Web Worker" }).click();
  await expect(page.getByText(/The ball never stopped/)).toBeVisible({ timeout: 15000 });
});

test("IndexedDB: write, read back, and the inactive-transaction pitfall", async ({ page }) => {
  await open(page, "storage");
  await page.getByLabel("Note text").fill("written by Playwright");
  await page.getByRole("button", { name: "Add note" }).click();
  await expect(page.getByRole("list", { name: "Stored notes" })).toContainText("written by Playwright");
  await page.getByRole("button", { name: "Trigger it" }).click();
  await expect(page.getByRole("list", { name: "IndexedDB event log" })).toContainText("TransactionInactiveError");
});

test("a late banner pushes CLS past 0.1", async ({ page }) => {
  await open(page, "vitals");
  await page.getByRole("button", { name: "Load a late banner" }).click();
  await expect(page.locator(".shift-banner")).toHaveCount(1);
  await expect(page.locator('[data-metric="CLS"]')).toHaveClass(/needs-improvement|poor/);
  await expect(page.locator('[data-mission="cls"]')).toHaveClass(/done/);
});

test("a 350ms click handler shows up as a slow interaction", async ({ page }) => {
  await open(page, "vitals");
  await page.getByRole("button", { name: "Slow handler (350ms)" }).click();
  await expect(page.getByText(/Last interaction: .* took (3[5-9]\d|[4-9]\d\d) ms/)).toBeVisible();
});

test("errors, rejections and CSP violations are captured", async ({ page }) => {
  await open(page, "debug");
  await page.getByRole("button", { name: "Throw an uncaught error" }).click();
  await page.getByRole("button", { name: "Reject a promise, never catch it" }).click();
  await page.getByRole("button", { name: "Violate the CSP (eval)" }).click();
  const list = page.getByRole("list", { name: "Captured errors" });
  await expect(list).toContainText("[error] Uncaught Error: Boom from a timer callback");
  await expect(list).toContainText("[unhandledrejection] Nobody handled me");
  await expect(list).toContainText("[csp] script-src blocked eval");
  await expect(page.locator('[data-mission="csp"]')).toHaveClass(/done/);
});

test("missions persist across reloads", async ({ page }) => {
  await open(page, "engine");
  await page.getByRole("button", { name: "{ x, y }", exact: true }).click();
  await page.getByRole("button", { name: "{ y, x }", exact: true }).click();
  await expect(page.locator('[data-mission="shapes"]')).toHaveClass(/done/);
  await page.reload();
  await expect(page.locator('[data-mission="shapes"]')).toHaveClass(/done/);
  await expect(page.locator("#progress-text")).toContainText("1 of");
});

Generated from SOURCE.md · 8 Oct 2026 16:36