sync-alerts.spec.ts

2.9 KB · raw

1import { test, expect, BrowserContext } from "@playwright/test";2import { makeContext, setupVault, waitForSW } from "./helpers/vault";34// Device-trust alerts (DEVICE_REVOKED / DEVICE_KEY_ROTATED) carry peer-supplied5// device names. A long or unbreakable name must never widen the fixed-width6// extension shell — that regressed as a >1000px scroll surface in a 320px7// popup, clipping and distorting everything else in the shell.8test.describe.configure({ timeout: 120_000 });910test.describe("Sync Alerts", () => {11  let ctx: BrowserContext;12  test.afterEach(async () => { await ctx.close(); });1314  test("SA01 - long device names stay contained inside the shell", async () => {15    ctx = await makeContext();16    const { popup } = await setupVault(ctx);17    await expect(popup.locator(".peach-lock-btn[aria-label='Lock vault']")).toBeVisible();1819    const alerts = [20      {21        type: "DEVICE_REVOKED",22        entryId: "",23        entryTitle: "",24        deviceName: "June's MacBook Pro (16-inch, M4 Max, 2024, Work Profile)",25        timestamp: Date.now(),26      },27      {28        type: "DEVICE_KEY_ROTATED",29        entryId: "",30        entryTitle: "",31        deviceName: "Android-Backup-Device-With-An-Extremely-Long-Unbreakable-Identifier-0123456789",32        timestamp: Date.now(),33      },34    ];35    await popup.evaluate((a) => chrome.storage.local.set({ peach_pending_sync_alerts_v1: a }), alerts);3637    // A fresh popup boots unlocked and consumes the pending alert queue.38    const extId = await waitForSW(ctx);39    const p2 = await ctx.newPage();40    await p2.goto(`chrome-extension://${extId}/src/popup/index.html`);41    await expect(p2.locator(".peach-sync-alert")).toHaveCount(2, { timeout: 20000 });4243    const geo = await p2.evaluate(() => {44      const shell = document.querySelector(".peach-shell")!;45      const shellRect = shell.getBoundingClientRect();46      const rows = [...document.querySelectorAll(".peach-sync-alert")].map((r) => {47        const rrect = r.getBoundingClientRect();48        const text = r.querySelector(".peach-sync-alert-text") as HTMLElement;49        return {50          rowLeftDelta: rrect.left - shellRect.left,51          rowRightDelta: rrect.right - shellRect.right,52          textScrollW: text.scrollWidth,53          textClientW: text.clientWidth,54        };55      });56      return { shellScrollW: shell.scrollWidth, rows };57    });5859    // The shell is designed at 320px; the alert blowout stretched its scroll60    // surface past 1000px. It must never exceed the design width.61    expect(geo.shellScrollW).toBeLessThanOrEqual(320);6263    // Every alert row stays inside the shell, and the nowrap text truncates64    // (ellipsis) instead of widening its row.65    for (const row of geo.rows) {66      expect(row.rowLeftDelta).toBeGreaterThanOrEqual(-1);67      expect(row.rowRightDelta).toBeLessThanOrEqual(1);68      expect(row.textScrollW).toBeGreaterThan(row.textClientW);69    }70  });71});