settings.spec.ts

6.9 KB · raw

1import { test, expect } from "@playwright/test";2import type { BrowserContext } from "@playwright/test";3import { fileURLToPath } from "url";4import { dirname, join } from "path";5import os from "os";6import fs from "fs/promises";78const __filename = fileURLToPath(import.meta.url);9const __dirname = dirname(__filename);10const EXTENSION_PATH = join(__dirname, "..", "dist");1112async function makeContext() {13  const { chromium } = await import("playwright");14  const userDataDir = join(os.tmpdir(), `peach-test-${Date.now()}`);15  await fs.mkdir(userDataDir, { recursive: true });16  return chromium.launchPersistentContext(userDataDir, {17    headless: false,18    args: [`--load-extension=${EXTENSION_PATH}`, `--disable-extensions-except=${EXTENSION_PATH}`],19  });20}2122async function setupVault(ctx: BrowserContext): Promise<{ popup: import("@playwright/test").Page, extId: string }> {23  const maxWait = 15000;24  const start = Date.now();25  let sw = ctx.serviceWorkers()[0];26  while (!sw && Date.now() - start < maxWait) {27    await new Promise(r => setTimeout(r, 500));28    sw = ctx.serviceWorkers()[0];29  }30  if (!sw) throw new Error(`No SW after ${maxWait}ms`);31  const extId = new URL(sw.url()).host;32  const popup = await ctx.newPage();33  await popup.goto(`chrome-extension://${extId}/src/popup/index.html`);34  await popup.waitForTimeout(2000);35  const pw = popup.locator("#master-password");36  if (await pw.isVisible()) {37    await pw.fill("password123");38    await popup.locator("#confirm-password").fill("password123");39    await popup.getByRole("button", { name: /create vault/i }).click();40    await popup.waitForTimeout(2000);41  }42  return { popup, extId };43}4445test.describe("Settings & Appearance", () => {46  let ctx: BrowserContext;47  test.afterEach(async () => { await ctx.close(); });48  test.beforeEach(async () => { ctx = await makeContext(); });4950  test("21 - settings panel opens from chrome bar", async () => {51    const { popup } = await setupVault(ctx);52    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();53    await popup.waitForTimeout(500);54    await expect(popup.locator(".peach-overlay-title").or(popup.locator("text=settings"))).toBeVisible();55  });5657  test("22 - settings shows lock on close, breach monitoring, auto-lock", async () => {58    const { popup } = await setupVault(ctx);59    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();60    await popup.waitForTimeout(500);61    await expect(popup.locator("text=lock on close")).toBeVisible();62    await expect(popup.locator("text=breach monitoring")).toBeVisible();63    await expect(popup.locator("text=auto-lock")).toBeVisible();64    await expect(popup.locator("text=clipboard clear")).toBeVisible();65  });6667  test("23 - settings shows sync stub with pro badge", async () => {68    const { popup } = await setupVault(ctx);69    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();70    await popup.waitForTimeout(500);71    await expect(popup.locator("text=sync")).toBeVisible();72    await expect(popup.locator(".peach-pro-badge")).toBeVisible();73  });7475  test("24 - settings shows vault entry count", async () => {76    const { popup } = await setupVault(ctx);77    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();78    await popup.waitForTimeout(500);79    await expect(popup.locator("text=entries").first()).toBeVisible();80  });8182  test("25 - accent color presets are all clickable", async () => {83    const { popup } = await setupVault(ctx);84    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();85    await popup.waitForTimeout(500);86    const swatches = popup.locator(".peach-swatch");87    const count = await swatches.count();88    expect(count).toBeGreaterThanOrEqual(6);89    for (let i = 0; i < count; i++) {90      await swatches.nth(i).click();91      await popup.waitForTimeout(100);92    }93  });9495  test("26 - lock vault button returns to lock screen", async () => {96    const { popup } = await setupVault(ctx);97    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();98    await popup.waitForTimeout(500);99    await popup.locator("text=lock vault").click();100    await popup.waitForTimeout(1000);101    const pwField = popup.locator("#master-password");102    await expect(pwField).toBeVisible({ timeout: 3000 });103  });104105  test("27 - import passwords button opens import view", async () => {106    const { popup } = await setupVault(ctx);107    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();108    await popup.waitForTimeout(500);109    await popup.getByRole("button", { name: /import passwords/i }).click();110    await popup.waitForTimeout(500);111    await expect(popup.locator(".import-title, text=import")).toBeVisible();112  });113114  test("28 - export backup button opens export view", async () => {115    const { popup } = await setupVault(ctx);116    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();117    await popup.waitForTimeout(500);118    await popup.getByRole("button", { name: /export backup/i }).click();119    await popup.waitForTimeout(500);120    await expect(popup.locator(".export-title, text=export")).toBeVisible();121  });122123  test("29 - onboarding shows peach wordmark and tagline", async () => {124    const c = await makeContext();125    const maxWait = 15000;126    const start = Date.now();127    let sw = c.serviceWorkers()[0];128    while (!sw && Date.now() - start < maxWait) {129      await new Promise(r => setTimeout(r, 500));130      sw = c.serviceWorkers()[0];131    }132    if (!sw) throw new Error("No SW");133    const extId = new URL(sw.url()).host;134    const p = await c.newPage();135    await p.goto(`chrome-extension://${extId}/src/popup/index.html`);136    await p.waitForTimeout(2000);137    await expect(p.locator(".wordmark, .peach-wordmark").first().or(p.locator("text=peach"))).toBeVisible();138    await expect(p.locator(".peach-onboarding-headline, text=your secrets").first().or(p.locator("text=your secrets"))).toBeVisible();139    await c.close();140  });141142  test("30 - lock screen pre-rendered HTML visible before JS", async () => {143    const { chromium } = await import("playwright");144    const userDataDir = join(os.tmpdir(), `peach-prelock-test-${Date.now()}`);145    await fs.mkdir(userDataDir, { recursive: true });146    const c = await chromium.launchPersistentContext(userDataDir, {147      headless: true,148      args: [`--load-extension=${EXTENSION_PATH}`, `--disable-extensions-except=${EXTENSION_PATH}`],149    });150    const maxWait = 15000;151    const start = Date.now();152    let sw = c.serviceWorkers()[0];153    while (!sw && Date.now() - start < maxWait) {154      await new Promise(r => setTimeout(r, 500));155      sw = c.serviceWorkers()[0];156    }157    if (!sw) throw new Error("No SW");158    const extId = new URL(sw.url()).host;159    await c.newPage();160    const p = await c.newPage();161    await p.goto(`chrome-extension://${extId}/src/popup/index.html`);162    await p.waitForTimeout(200);163    const preLock = p.locator("#pre-lock");164    await expect(preLock).toBeAttached();165    await c.close();166  });167});