import { test, expect, Page, BrowserContext } from "@playwright/test"; import { fileURLToPath } from "url"; import { dirname, join } from "path"; import os from "os"; import fs from "fs/promises"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const EXTENSION_PATH = join(__dirname, "..", "dist"); async function waitForSW(ctx: BrowserContext, maxWait = 15000): Promise { const start = Date.now(); let sw = ctx.serviceWorkers()[0]; while (!sw && Date.now() - start < maxWait) { await new Promise(r => setTimeout(r, 500)); sw = ctx.serviceWorkers()[0]; } if (!sw) throw new Error(`No SW after ${maxWait}ms`); return new URL(sw.url()).host; } async function loadPopup(ctx: BrowserContext): Promise<{ popup: Page, extId: string }> { const extId = await waitForSW(ctx); const popup = await ctx.newPage(); await popup.goto(`chrome-extension://${extId}/src/popup/index.html`); await popup.waitForTimeout(3000); return { popup, extId }; } async function makeContext() { const { chromium } = await import("playwright"); const userDataDir = join(os.tmpdir(), `peach-${Date.now()}-${Math.random().toString(36).slice(2)}`); await fs.mkdir(userDataDir, { recursive: true }); return chromium.launchPersistentContext(userDataDir, { headless: false, args: [`--load-extension=${EXTENSION_PATH}`, `--disable-extensions-except=${EXTENSION_PATH}`], }); } async function createVault(ctx: BrowserContext, password = "testpassword123") { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); if (await pw.isVisible()) { await pw.fill(password); await popup.locator("#confirm-password").fill(password); await popup.getByRole("button", { name: /create vault/i }).click(); await popup.waitForTimeout(2000); } return { popup }; } async function unlockVault(ctx: BrowserContext, password = "testpassword123") { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); if (await pw.isVisible()) { await pw.fill(password); await popup.getByRole("button", { name: /unlock/i }).click(); await popup.waitForTimeout(1500); } return { popup }; } test.describe("Vault Lifecycle", () => { let ctx: BrowserContext; test.afterEach(async () => { if (ctx) await ctx.close(); }); test.beforeEach(async () => { ctx = await makeContext(); }); test("01 - fresh install shows onboarding create flow", async () => { const { popup } = await loadPopup(ctx); await popup.waitForTimeout(500); const preLock = popup.locator("#pre-lock"); if (await preLock.isVisible().catch(() => false)) { await preLock.waitFor({ state: "hidden", timeout: 5000 }).catch(() => {}); } const headline = popup.locator(".peach-onboarding-headline, .peach-unlock-headline").first(); await expect(headline).toBeVisible({ timeout: 5000 }); const createBtn = popup.getByRole("button", { name: /create vault/i }); await expect(createBtn).toBeVisible(); }); test("02 - create vault with minimum 8-char password", async () => { const { popup } = await createVault(ctx, "12345678"); const entry = popup.locator(".peach-entry-name, .peach-ghost, [class*=entry]").first(); await expect(entry).toBeVisible({ timeout: 5000 }); }); test("03 - create vault with 8-char password succeeds", async () => { const { popup } = await createVault(ctx, "abcdefgh"); const entries = popup.locator("[class*=entry]"); await expect(entries.first()).toBeVisible({ timeout: 5000 }); }); test("04 - create vault with long password succeeds", async () => { const { popup } = await createVault(ctx, "thisisaverylongpasswordthatwemightuse123!@#"); const entries = popup.locator("[class*=entry]"); await expect(entries.first()).toBeVisible({ timeout: 5000 }); }); test("05 - create vault with special chars in password", async () => { const { popup } = await createVault(ctx, "P@$$w0rd!#%^&*()_+-=[]{}|;':\",./<>?"); const entries = popup.locator("[class*=entry]"); await expect(entries.first()).toBeVisible({ timeout: 5000 }); }); test("06 - create vault with unicode password", async () => { const { popup } = await createVault(ctx, "пароль密码🔐🔑"); const entries = popup.locator("[class*=entry]"); await expect(entries.first()).toBeVisible({ timeout: 5000 }); }); test("07 - create vault with emoji password", async () => { const { popup } = await createVault(ctx, "🔐🔑🌟💻🖥️⌨️"); const entries = popup.locator("[class*=entry]"); await expect(entries.first()).toBeVisible({ timeout: 5000 }); }); test("08 - wrong password shows shake animation", async () => { await createVault(ctx); await new Promise(r => setTimeout(r, 500)); const newPopup = await ctx.newPage(); const extId = (await loadPopup(ctx)).extId; await newPopup.goto(`chrome-extension://${extId}/src/popup/index.html`); await newPopup.waitForTimeout(1500); await newPopup.locator("#master-password").fill("wrongpassword"); await newPopup.getByRole("button", { name: /unlock/i }).click(); await newPopup.waitForTimeout(500); const error = newPopup.locator(".peach-hint-error, .peach-unlock-headline"); await expect(error).toBeVisible({ timeout: 3000 }); }); test("09 - wrong password does not unlock vault", async () => { await createVault(ctx); const newPopup = await ctx.newPage(); const extId = (await loadPopup(ctx)).extId; await newPopup.goto(`chrome-extension://${extId}/src/popup/index.html`); await newPopup.waitForTimeout(1500); await newPopup.locator("#master-password").fill("wrongpassword"); await newPopup.getByRole("button", { name: /unlock/i }).click(); await newPopup.waitForTimeout(1000); const lockStillVisible = await newPopup.locator("#master-password").isVisible(); expect(lockStillVisible).toBe(true); }); test("10 - correct password unlocks vault", async () => { await createVault(ctx); const newPopup = await ctx.newPage(); const extId = (await loadPopup(ctx)).extId; await newPopup.goto(`chrome-extension://${extId}/src/popup/index.html`); await newPopup.waitForTimeout(1500); await newPopup.locator("#master-password").fill("testpassword123"); await newPopup.getByRole("button", { name: /unlock/i }).click(); await newPopup.waitForTimeout(2000); const entries = newPopup.locator("[class*=entry]"); await expect(entries.first()).toBeVisible({ timeout: 5000 }); }); test("11 - lock button returns to lock screen", async () => { const { popup } = await createVault(ctx); await popup.waitForTimeout(500); const lockBtn = popup.locator(".peach-lock-btn[aria-label='Lock vault']"); await expect(lockBtn).toBeVisible({ timeout: 3000 }); await lockBtn.click(); await popup.waitForTimeout(1500); const pwField = popup.locator("#master-password"); await expect(pwField).toBeVisible({ timeout: 5000 }); }); test("12 - clicking lock icon in header locks vault", async () => { const { popup } = await createVault(ctx); const headerLock = popup.locator("[aria-label*='lock' i]").first(); if (await headerLock.isVisible()) { await headerLock.click(); await popup.waitForTimeout(1000); await expect(popup.locator("#master-password")).toBeVisible({ timeout: 3000 }); } }); test("13 - lock preserves vault data", async () => { const { popup } = await createVault(ctx); await popup.locator('input[placeholder*="search" i]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("TestEntry"); await popup.locator('input[placeholder*="domain" i]').fill("https://test.com"); await popup.locator('input[placeholder*="username" i]').fill("user@test.com"); await popup.locator(".peach-new-field-input[placeholder*='password' i]").fill("secret123"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); const lockBtn = popup.locator(".peach-lock-btn, [aria-label*='lock' i]").first(); await lockBtn.click(); await popup.waitForTimeout(1000); await popup.locator("#master-password").fill("testpassword123"); await popup.getByRole("button", { name: /unlock/i }).click(); await popup.waitForTimeout(2000); await expect(popup.locator("text=TestEntry").first()).toBeVisible({ timeout: 5000 }); }); test("14 - auto-lock after 1 minute configured in settings", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); const autoLockRow = popup.locator("text=auto-lock").first(); await expect(autoLockRow).toBeVisible(); }); test("15 - auto-lock options: 1min, 5min, 15min, 1hr, never", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); await popup.locator("text=auto-lock").click(); await popup.waitForTimeout(300); const options = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option"); const count = await options.count(); expect(count).toBeGreaterThanOrEqual(4); }); test("16 - service worker restart shows lock screen", async () => { const { popup, extId } = await loadPopup(ctx); await createVault(ctx); const newPopup = await ctx.newPage(); await newPopup.goto(`chrome-extension://${extId}/src/popup/index.html`); await newPopup.waitForTimeout(1500); await expect(newPopup.locator("#master-password")).toBeVisible({ timeout: 3000 }); }); test("17 - multiple rapid lock/unlock cycles work", async () => { const { popup } = await createVault(ctx); for (let i = 0; i < 3; i++) { const lockBtn = popup.locator(".peach-lock-btn, [aria-label*='lock' i]").first(); await lockBtn.click(); await popup.waitForTimeout(500); await popup.locator("#master-password").fill("testpassword123"); await popup.getByRole("button", { name: /unlock/i }).click(); await popup.waitForTimeout(1000); } await expect(popup.locator("[class*=entry]").first()).toBeVisible({ timeout: 5000 }); }); test("18 - vault data persists after extension reload", async () => { const { popup } = await createVault(ctx); await popup.locator('input[placeholder*="search" i]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("PersistTest"); await popup.locator('input[placeholder*="domain" i]').fill("https://persist.com"); await popup.locator('input[placeholder*="username" i]').fill("persist@user.com"); await popup.locator(".peach-new-field-input[placeholder*='password' i]").fill("persistentpass"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); const extId = (await loadPopup(ctx)).extId; const newPopup = await ctx.newPage(); await newPopup.goto(`chrome-extension://${extId}/src/popup/index.html`); await newPopup.waitForTimeout(2000); await newPopup.locator("#master-password").fill("testpassword123"); await newPopup.getByRole("button", { name: /unlock/i }).click(); await newPopup.waitForTimeout(2000); await expect(newPopup.locator("text=PersistTest")).toBeVisible({ timeout: 5000 }); }); test("19 - creating vault shows empty state", async () => { const { popup } = await createVault(ctx); const emptyState = popup.locator("text=Your vault is ready, text=first entry, .peach-empty-copy").first(); const hasEmptyState = await emptyState.isVisible().catch(() => false); expect(hasEmptyState).toBeTruthy(); }); test("20 - vault with entries does not show empty state", async () => { const { popup } = await createVault(ctx); await popup.locator('input[placeholder*="search" i]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("FirstEntry"); await popup.locator('input[placeholder*="domain" i]').fill("https://first.com"); await popup.locator('input[placeholder*="username" i]').fill("first@user.com"); await popup.locator(".peach-new-field-input[placeholder*='password' i]").fill("password123"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); const emptyState = popup.locator("text=empty, text=no entries").first(); await expect(emptyState).not.toBeVisible(); }); test("21 - password field shows dots by default on lock screen", async () => { const { popup } = await loadPopup(ctx); await createVault(ctx); const newPopup = await ctx.newPage(); const extId = (await loadPopup(ctx)).extId; await newPopup.goto(`chrome-extension://${extId}/src/popup/index.html`); await newPopup.waitForTimeout(1500); const pwInput = newPopup.locator("#master-password"); const type = await pwInput.getAttribute("type"); expect(type).toBe("password"); }); test("22 - reveal password toggle on lock screen", async () => { const { popup } = await loadPopup(ctx); await createVault(ctx); const newPopup = await ctx.newPage(); const extId = (await loadPopup(ctx)).extId; await newPopup.goto(`chrome-extension://${extId}/src/popup/index.html`); await newPopup.waitForTimeout(1500); const revealBtn = newPopup.locator("[aria-label*='show' i], [aria-label*='reveal' i]").first(); if (await revealBtn.isVisible({ timeout: 2000 }).catch(() => false)) { await revealBtn.click(); const pwInput = newPopup.locator("#master-password"); const type = await pwInput.getAttribute("type"); expect(type).toBe("text"); } }); test("23 - clipboard clear option in settings", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); await expect(popup.locator("text=clipboard clear")).toBeVisible(); }); test("24 - clipboard clear time options: 30s, 60s, 90s, never", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); await popup.locator("text=clipboard clear").click(); await popup.waitForTimeout(300); const options = popup.locator("[role='option' i], [role='menuitem' i]"); const count = await options.count(); expect(count).toBeGreaterThanOrEqual(3); }); test("25 - lock on close option in settings", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); await expect(popup.locator("text=lock on close")).toBeVisible(); }); test("26 - lock on close toggle works", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); const toggle = popup.locator("text=lock on close").locator("..").locator("[role='switch' i], [type='checkbox']").first(); if (await toggle.isVisible({ timeout: 2000 }).catch(() => false)) { await toggle.click(); await popup.waitForTimeout(300); } }); test("27 - breach monitoring toggle in settings", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); await expect(popup.locator("text=breach monitoring")).toBeVisible(); }); test("28 - vault name displays in header", async () => { const { popup } = await createVault(ctx); const header = popup.locator("[class*='header' i], [class*='title' i]").first(); const hasHeader = await header.isVisible({ timeout: 2000 }).catch(() => false); expect(hasHeader).toBeTruthy(); }); test("29 - vault entry count shows in settings", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); await expect(popup.locator("text=entries").first()).toBeVisible(); }); test("30 - version number shows in settings", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); const version = popup.locator("text=1.0."); const hasVersion = await version.isVisible({ timeout: 2000 }).catch(() => false); expect(hasVersion).toBeTruthy(); }); test("31 - syncing indicator shows for pro users", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); const syncRow = popup.locator("text=sync"); await expect(syncRow).toBeVisible(); }); test("32 - pro badge shows next to sync option", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); const proBadge = popup.locator(".peach-pro-badge, [class*='pro' i]"); const hasBadge = await proBadge.isVisible({ timeout: 2000 }).catch(() => false); expect(hasBadge).toBeTruthy(); }); test("33 - lock screen has peach branding", async () => { const { popup } = await loadPopup(ctx); const brandElements = popup.locator(".peach-wordmark, .wordmark, text=peach, [class*='brand' i]"); const hasBrand = await brandElements.first().isVisible({ timeout: 3000 }).catch(() => false); expect(hasBrand).toBeTruthy(); }); test("34 - unlock screen shows tagline", async () => { const { popup } = await loadPopup(ctx); const tagline = popup.locator("text=secrets, text=your secrets, [class*='tagline' i]"); const hasTagline = await tagline.first().isVisible({ timeout: 3000 }).catch(() => false); expect(hasTagline).toBeTruthy(); }); test("35 - password strength indicator during vault creation", async () => { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); if (await pw.isVisible()) { await pw.fill("weak"); await popup.waitForTimeout(300); const strength = popup.locator("[class*='strength' i], text=weak, text=strong"); const hasStrength = await strength.first().isVisible({ timeout: 2000 }).catch(() => false); expect(hasStrength).toBeTruthy(); } }); test("36 - password strength updates as user types", async () => { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); const confirm = popup.locator("#confirm-password"); if (await pw.isVisible()) { await pw.fill("w"); await popup.waitForTimeout(200); await pw.fill("we"); await popup.waitForTimeout(200); await pw.fill("weak"); await popup.waitForTimeout(200); await pw.fill("WeakPassword123!"); await popup.waitForTimeout(200); } }); test("37 - passwords must match on create", async () => { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); const confirm = popup.locator("#confirm-password"); if (await pw.isVisible()) { await pw.fill("password123"); await confirm.fill("differentpassword"); await popup.getByRole("button", { name: /create vault/i }).click(); await popup.waitForTimeout(500); const error = popup.locator("text=mismatch, text=do not match, text=not match"); await expect(error.first()).toBeVisible({ timeout: 3000 }); } }); test("38 - passwords must be at least 8 chars", async () => { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); const confirm = popup.locator("#confirm-password"); if (await pw.isVisible()) { await pw.fill("1234567"); await confirm.fill("1234567"); await popup.getByRole("button", { name: /create vault/i }).click(); await popup.waitForTimeout(500); const error = popup.locator("text=8 characters, text=minimum, text=at least"); await expect(error.first()).toBeVisible({ timeout: 3000 }); } }); test("39 - vault creation shows loading state", async () => { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); const confirm = popup.locator("#confirm-password"); if (await pw.isVisible()) { await pw.fill("testpassword123"); await confirm.fill("testpassword123"); await popup.getByRole("button", { name: /create vault/i }).click(); await popup.waitForTimeout(300); const loading = popup.locator("[class*='loading' i], [class*='spinner' i], text=creating"); const hasLoading = await loading.first().isVisible({ timeout: 3000 }).catch(() => false); expect(hasLoading).toBeTruthy(); } }); test("40 - successful vault creation transitions to unlocked state", async () => { const { popup } = await loadPopup(ctx); const pw = popup.locator("#master-password"); const confirm = popup.locator("#confirm-password"); if (await pw.isVisible()) { await pw.fill("testpassword123"); await confirm.fill("testpassword123"); await popup.getByRole("button", { name: /create vault/i }).click(); await popup.waitForTimeout(2500); const entries = popup.locator("[class*=entry]"); await expect(entries.first()).toBeVisible({ timeout: 5000 }); } }); test("41 - empty vault shows encouraging empty state message", async () => { const { popup } = await createVault(ctx); const emptyCopy = popup.locator("text=empty, text=no entries, text=get started, text=add your first"); const hasMessage = await emptyCopy.first().isVisible({ timeout: 3000 }).catch(() => false); expect(hasMessage).toBeTruthy(); }); test("42 - adding first entry has prominent CTA", async () => { const { popup } = await createVault(ctx); const cta = popup.locator("text=add entry, text=new entry, button:has-text('new')"); await expect(cta.first()).toBeVisible(); }); test("43 - header shows vault status (locked/unlocked)", async () => { const { popup } = await createVault(ctx); const status = popup.locator("[class*='status' i], [class*='badge' i]"); const hasStatus = await status.first().isVisible({ timeout: 2000 }).catch(() => false); expect(hasStatus).toBeTruthy(); }); test("44 - biometric unlock option shows if available", async () => { const { popup } = await loadPopup(ctx); const biometric = popup.locator("text=biometric, text=fingerprint, text=face id, text=touch id"); const hasBio = await biometric.first().isVisible({ timeout: 2000 }).catch(() => false); }); test("45 - keyboard shortcut hint on lock screen", async () => { const { popup } = await loadPopup(ctx); const shortcut = popup.locator("text=enter, text=shortcut, text=ctrl+enter"); const hasShortcut = await shortcut.first().isVisible({ timeout: 2000 }).catch(() => false); }); test("46 - remember master password option", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(500); const remember = popup.locator("text=remember master password, text=master password reminder"); const hasRemember = await remember.first().isVisible({ timeout: 2000 }).catch(() => false); }); test("47 - vault export encrypts with password", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(300); await popup.getByRole("button", { name: /export/i }).click(); await popup.waitForTimeout(500); const exportPw = popup.locator('input[type="password"]').first(); await expect(exportPw).toBeVisible(); }); test("48 - vault import shows file picker", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(300); await popup.getByRole("button", { name: /import/i }).click(); await popup.waitForTimeout(500); const fileInput = popup.locator('input[type="file"]'); await expect(fileInput).toBeAttached(); }); test("49 - password generator accessible from main view", async () => { const { popup } = await createVault(ctx); const genBtn = popup.locator("[aria-label*='generate' i], text=generator, text=generate password"); await expect(genBtn.first()).toBeVisible({ timeout: 2000 }); }); test("50 - search vault with no entries shows no results", async () => { const { popup } = await createVault(ctx); await popup.locator('input[placeholder*="search" i]').click(); await popup.locator('input[placeholder*="search" i]').fill("nonexistent"); await popup.waitForTimeout(500); const noResults = popup.locator("text=no results, text=not found, text=0 results"); const hasNoResults = await noResults.first().isVisible({ timeout: 2000 }).catch(() => false); expect(hasNoResults).toBeTruthy(); }); }); test.describe("Vault Lifecycle Part 2", () => { let ctx: BrowserContext; test.afterEach(async () => { if (ctx) await ctx.close(); }); test.beforeEach(async () => { ctx = await makeContext(); }); test("51 - changing auto-lock time persists", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(300); await popup.locator("text=auto-lock").click(); await popup.waitForTimeout(300); const option = popup.locator("[role='option' i], [role='menuitem' i]").nth(1); await option.click(); await popup.waitForTimeout(300); await popup.keyboard.press("Escape"); await popup.waitForTimeout(200); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(300); await popup.locator("text=auto-lock").click(); await popup.waitForTimeout(300); }); test("52 - changing clipboard clear time persists", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(300); await popup.locator("text=clipboard clear").click(); await popup.waitForTimeout(300); const option = popup.locator("[role='option' i], [role='menuitem' i]").nth(1); await option.click(); await popup.waitForTimeout(300); await popup.keyboard.press("Escape"); }); test("53 - vault data survives browser restart", async () => { const { popup } = await createVault(ctx); await popup.locator('input[placeholder*="search" i]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("RestartTest"); await popup.locator('input[placeholder*="domain" i]').fill("https://restart.com"); await popup.locator('input[placeholder*="username" i]').fill("restart@user.com"); await popup.locator(".peach-new-field-input[placeholder*='password' i]").fill("restartpass"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); }); test("54 - clearing vault shows confirmation", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(300); const dangerZone = popup.locator("text=clear vault, text=delete all, text=destroy vault"); const hasDanger = await dangerZone.first().isVisible({ timeout: 2000 }).catch(() => false); }); test("55 - clear vault requires password confirmation", async () => { const { popup } = await createVault(ctx); await popup.locator("[aria-label*='settings' i]").click(); await popup.waitForTimeout(300); }); });