import { test, expect, 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 makeContext() { const { chromium } = await import("playwright"); const userDataDir = join(os.tmpdir(), `peach-totp-${Date.now()}`); await fs.mkdir(userDataDir, { recursive: true }); return chromium.launchPersistentContext(userDataDir, { headless: false, args: [`--load-extension=${EXTENSION_PATH}`, `--disable-extensions-except=${EXTENSION_PATH}`], }); } 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 setupVault(ctx: BrowserContext): Promise<{ popup: any, 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); const pw = popup.locator("#master-password"); if (await pw.isVisible()) { await pw.fill("password123"); await popup.locator("#confirm-password").fill("password123"); await popup.getByRole("button", { name: /create vault/i }).click(); await popup.waitForTimeout(2000); } return { popup, extId }; } test.describe("TOTP Base32 Parsing", () => { let ctx: BrowserContext; test.afterEach(async () => { await ctx.close(); }); test.beforeEach(async () => { ctx = await makeContext(); }); test("TOTP01 - standard base32 secret accepted", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("Base32Std"); await popup.locator('input[placeholder="domain.com"]').fill("https://base32.com"); await popup.locator('input[placeholder="username or email"]').fill("base32@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await expect(popup.locator("text=Base32Std")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); test("TOTP02 - base32 with spaces accepted", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("Base32Space"); await popup.locator('input[placeholder="domain.com"]').fill("https://space.com"); await popup.locator('input[placeholder="username or email"]').fill("space@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSW Y3DP EHPK 3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await expect(popup.locator("text=Base32Space")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); test("TOTP03 - base32 with lowercase accepted", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("Base32Lower"); await popup.locator('input[placeholder="domain.com"]').fill("https://lower.com"); await popup.locator('input[placeholder="username or email"]').fill("lower@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("jbswy3dpehpk3pxp"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await expect(popup.locator("text=Base32Lower")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); test("TOTP04 - invalid base32 shows error", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("InvalidBase"); await popup.locator('input[placeholder="domain.com"]').fill("https://invalid.com"); await popup.locator('input[placeholder="username or email"]').fill("invalid@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("INVALID!!!"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(500); const error = popup.locator(".peach-hint-error, .peach-error, text=invalid"); const hasError = await error.isVisible({ timeout: 2000 }).catch(() => false); expect(hasError).toBeTruthy(); await ctx.close(); }); test("TOTP05 - base32 with padding accepted", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("Base32Pad"); await popup.locator('input[placeholder="domain.com"]').fill("https://pad.com"); await popup.locator('input[placeholder="username or email"]').fill("pad@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP===="); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await expect(popup.locator("text=Base32Pad")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); }); test.describe("TOTP Countdown Accuracy", () => { let ctx: BrowserContext; test.afterEach(async () => { await ctx.close(); }); test.beforeEach(async () => { ctx = await makeContext(); }); test("TOTP06 - countdown shows seconds remaining", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("CountDown"); await popup.locator('input[placeholder="domain.com"]').fill("https://count.com"); await popup.locator('input[placeholder="username or email"]').fill("count@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const countdown = popup.locator(".peach-totp-countdown"); await expect(countdown).toBeVisible({ timeout: 3000 }); const text = await countdown.textContent(); expect(text).toMatch(/\d+s/); await ctx.close(); }); test("TOTP07 - countdown decrements in real time", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("Decrement"); await popup.locator('input[placeholder="domain.com"]').fill("https://decrement.com"); await popup.locator('input[placeholder="username or email"]').fill("decrement@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const countdown = popup.locator(".peach-totp-countdown"); const val1 = await countdown.textContent(); await popup.waitForTimeout(2000); const val2 = await countdown.textContent(); expect(parseInt(val2 ?? "0")).toBeLessThan(parseInt(val1 ?? "30")); await ctx.close(); }); test("TOTP08 - ring progress animates with countdown", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("RingAnim"); await popup.locator('input[placeholder="domain.com"]').fill("https://ring.com"); await popup.locator('input[placeholder="username or email"]').fill("ring@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const ring = popup.locator(".peach-totp-ring-progress"); await expect(ring).toBeVisible({ timeout: 3000 }); const dashOffset1 = await ring.getAttribute("stroke-dashoffset"); await popup.waitForTimeout(2000); const dashOffset2 = await ring.getAttribute("stroke-dashoffset"); expect(dashOffset1).not.toEqual(dashOffset2); await ctx.close(); }); test("TOTP09 - code refreshes at 30 second boundary", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("RefreshBound"); await popup.locator('input[placeholder="domain.com"]').fill("https://refresh.com"); await popup.locator('input[placeholder="username or email"]').fill("refresh@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const code1 = await popup.locator(".peach-totp-code").textContent(); const countdown = popup.locator(".peach-totp-countdown"); const remaining = parseInt(await countdown.textContent() ?? "0"); if (remaining > 5) { await popup.waitForTimeout(remaining + 2); const code2 = await popup.locator(".peach-totp-code").textContent(); expect(code1).not.toEqual(code2); } await ctx.close(); }); test("TOTP10 - 6 digit TOTP format correct", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("SixDigit"); await popup.locator('input[placeholder="domain.com"]').fill("https://six.com"); await popup.locator('input[placeholder="username or email"]').fill("six@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const code = await popup.locator(".peach-totp-code").textContent(); const clean = code?.replace(/\s/g, "").replace(/[^0-9]/g, ""); expect(clean?.length).toBe(6); await ctx.close(); }); }); test.describe("TOTP Copy Behavior", () => { let ctx: BrowserContext; test.afterEach(async () => { await ctx.close(); }); test.beforeEach(async () => { ctx = await makeContext(); }); test("TOTP11 - copy button copies current code", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("CopyTOTP"); await popup.locator('input[placeholder="domain.com"]').fill("https://copytotp.com"); await popup.locator('input[placeholder="username or email"]').fill("copy@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const copyBtn = popup.locator("[aria-label='Copy TOTP code']"); if (await copyBtn.isVisible({ timeout: 2000 }).catch(() => false)) { await copyBtn.click(); await popup.waitForTimeout(200); const clipboard = await popup.evaluate(() => navigator.clipboard.readText()); expect(clipboard).toMatch(/^\d{6}$/); } await ctx.close(); }); test("TOTP12 - copy button shows feedback", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("FeedbackTOTP"); await popup.locator('input[placeholder="domain.com"]').fill("https://feedback.com"); await popup.locator('input[placeholder="username or email"]').fill("feedback@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const copyBtn = popup.locator("[aria-label='Copy TOTP code']"); if (await copyBtn.isVisible({ timeout: 2000 }).catch(() => false)) { await copyBtn.click(); await popup.waitForTimeout(200); const isCopied = await copyBtn.evaluate((el: Element) => el.classList.contains("is-copied")); expect(isCopied).toBeTruthy(); } await ctx.close(); }); test("TOTP13 - copied code matches displayed code", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("MatchCode"); await popup.locator('input[placeholder="domain.com"]').fill("https://match.com"); await popup.locator('input[placeholder="username or email"]').fill("match@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const codeText = await popup.locator(".peach-totp-code").textContent(); const copyBtn = popup.locator("[aria-label='Copy TOTP code']"); if (await copyBtn.isVisible({ timeout: 2000 }).catch(() => false)) { await copyBtn.click(); await popup.waitForTimeout(200); const clipboard = await popup.evaluate(() => navigator.clipboard.readText()); const cleanCode = codeText?.replace(/\s/g, "").replace(/[^0-9]/g, ""); expect(clipboard).toBe(cleanCode); } await ctx.close(); }); }); test.describe("TOTP Edge Cases", () => { let ctx: BrowserContext; test.afterEach(async () => { await ctx.close(); }); test.beforeEach(async () => { ctx = await makeContext(); }); test("TOTP14 - entry with empty TOTP shows no TOTP UI", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("NoTOTPHere"); await popup.locator('input[placeholder="domain.com"]').fill("https://nototp.com"); await popup.locator('input[placeholder="username or email"]').fill("nototp@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const totpBand = popup.locator(".peach-totp-band"); const isHidden = await totpBand.isHidden().catch(() => true); expect(isHidden).toBe(true); await ctx.close(); }); test("TOTP15 - TOTP survives vault lock/unlock", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("LockTOTP"); await popup.locator('input[placeholder="domain.com"]').fill("https://locktotp.com"); await popup.locator('input[placeholder="username or email"]').fill("lock@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); const lockBtn = popup.locator(".peach-lock-btn[aria-label='Lock vault']"); await lockBtn.click(); await popup.waitForTimeout(1500); await popup.locator("#master-password").fill("password123"); await popup.getByRole("button", { name: /unlock/i }).click(); await popup.waitForTimeout(2000); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const totpCode = popup.locator(".peach-totp-code"); await expect(totpCode).toBeVisible({ timeout: 3000 }); await ctx.close(); }); test("TOTP16 - very long base32 secret accepted", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("LongBase"); await popup.locator('input[placeholder="domain.com"]').fill("https://long.com"); await popup.locator('input[placeholder="username or email"]').fill("long@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); const longSecret = "JBSWY3DPEHPK3PXPEHPK3PXPJBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP"; await popup.locator("input[placeholder*='totp' i]").fill(longSecret); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await expect(popup.locator("text=LongBase")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); test("TOTP17 - base32 O and 0 treated correctly", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("BaseOZero"); await popup.locator('input[placeholder="domain.com"]').fill("https://ozero.com"); await popup.locator('input[placeholder="username or email"]').fill("ozero@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await expect(popup.locator("text=BaseOZero")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); test("TOTP18 - base32 I and l treated correctly", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("BaseIL"); await popup.locator('input[placeholder="domain.com"]').fill("https://ilandl.com"); await popup.locator('input[placeholder="username or email"]').fill("ilandl@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await expect(popup.locator("text=BaseIL")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); }); test.describe("TOTP Entry Management", () => { let ctx: BrowserContext; test.afterEach(async () => { await ctx.close(); }); test.beforeEach(async () => { ctx = await makeContext(); }); test("TOTP19 - edit TOTP in existing entry", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("EditTOTP"); await popup.locator('input[placeholder="domain.com"]').fill("https://edittotp.com"); await popup.locator('input[placeholder="username or email"]').fill("edit@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); await popup.locator("button[aria-label='Edit']").first().click(); await popup.waitForTimeout(500); const totpInput = popup.locator("input[placeholder*='totp' i]"); await totpInput.fill("NEWBASE32SECRET"); await popup.getByRole("button", { name: /save/i }).click(); await popup.waitForTimeout(1500); await ctx.close(); }); test("TOTP20 - delete TOTP from entry", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("DeleteTOTP"); await popup.locator('input[placeholder="domain.com"]').fill("https://deltotp.com"); await popup.locator('input[placeholder="username or email"]').fill("del@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); await popup.locator("button[aria-label='Edit']").first().click(); await popup.waitForTimeout(500); const totpInput = popup.locator("input[placeholder*='totp' i]"); await totpInput.fill(""); await popup.getByRole("button", { name: /save/i }).click(); await popup.waitForTimeout(1500); await ctx.close(); }); test("TOTP21 - multiple entries with TOTP", async () => { const { popup } = await setupVault(ctx); for (const name of ["TOTP1", "TOTP2", "TOTP3"]) { await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill(name); await popup.locator('input[placeholder="domain.com"]').fill(`https://${name.toLowerCase()}.com`); await popup.locator('input[placeholder="username or email"]').fill(`${name.toLowerCase()}@user.com`); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(800); } await expect(popup.locator("text=TOTP1")).toBeVisible({ timeout: 3000 }); await ctx.close(); }); test("TOTP22 - TOTP entry survives entry edit", async () => { const { popup } = await setupVault(ctx); await popup.locator('input[placeholder="search vault..."]').click(); await popup.getByRole("button", { name: /new entry/i }).click(); await popup.locator(".peach-new-name-input").fill("SurviveEdit"); await popup.locator('input[placeholder="domain.com"]').fill("https://survive.com"); await popup.locator('input[placeholder="username or email"]').fill("survive@user.com"); await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass123"); await popup.locator("input[placeholder*='totp' i]").fill("JBSWY3DPEHPK3PXP"); await popup.getByRole("button", { name: /create/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); await popup.locator("button[aria-label='Edit']").first().click(); await popup.waitForTimeout(500); await popup.locator(".peach-new-name-input").fill("SurviveEditChanged"); await popup.getByRole("button", { name: /save/i }).click(); await popup.waitForTimeout(1500); await popup.locator(".peach-entry-name-button").first().click(); await popup.waitForTimeout(500); const totpCode = popup.locator(".peach-totp-code"); await expect(totpCode).toBeVisible({ timeout: 3000 }); await ctx.close(); }); });