settings-persistence.spec.ts

27.4 KB · raw

1import { test, expect, BrowserContext } from "@playwright/test";2import { fileURLToPath } from "url";3import { dirname, join } from "path";4import os from "os";5import fs from "fs/promises";67const __filename = fileURLToPath(import.meta.url);8const __dirname = dirname(__filename);9const EXTENSION_PATH = join(__dirname, "..", "dist");1011async function makeContext() {12  const { chromium } = await import("playwright");13  const userDataDir = join(os.tmpdir(), `peach-set-${Date.now()}`);14  await fs.mkdir(userDataDir, { recursive: true });15  return chromium.launchPersistentContext(userDataDir, {16    headless: false,17    args: [`--load-extension=${EXTENSION_PATH}`, `--disable-extensions-except=${EXTENSION_PATH}`],18  });19}2021async function waitForSW(ctx: BrowserContext, maxWait = 15000): Promise<string> {22  const start = Date.now();23  let sw = ctx.serviceWorkers()[0];24  while (!sw && Date.now() - start < maxWait) {25    await new Promise(r => setTimeout(r, 500));26    sw = ctx.serviceWorkers()[0];27  }28  if (!sw) throw new Error(`No SW after ${maxWait}ms`);29  return new URL(sw.url()).host;30}3132async function setupVault(ctx: BrowserContext): Promise<{ popup: any, extId: string }> {33  const extId = await waitForSW(ctx);34  const popup = await ctx.newPage();35  await popup.goto(`chrome-extension://${extId}/src/popup/index.html`);36  await popup.waitForTimeout(3000);37  const pw = popup.locator("#master-password");38  if (await pw.isVisible()) {39    await pw.fill("password123");40    await popup.locator("#confirm-password").fill("password123");41    await popup.getByRole("button", { name: /create vault/i }).click();42    await popup.waitForTimeout(2000);43  }44  return { popup, extId };45}4647test.describe("Auto-Lock Configuration", () => {48  let ctx: BrowserContext;49  test.afterEach(async () => { await ctx.close(); });50  test.beforeEach(async () => { ctx = await makeContext(); });5152  test("AUL01 - auto-lock setting exists in settings", async () => {53    const { popup } = await setupVault(ctx);54    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();55    await popup.waitForTimeout(500);56    const autoLock = popup.locator("text=auto-lock").first();57    await expect(autoLock).toBeVisible();58    await ctx.close();59  });6061  test("AUL02 - auto-lock options: 1 minute", async () => {62    const { popup } = await setupVault(ctx);63    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();64    await popup.waitForTimeout(500);65    await popup.locator("text=auto-lock").click();66    await popup.waitForTimeout(300);67    const options = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option");68    const optionTexts = await options.allTextContents();69    const has1Min = optionTexts.some((t: string) => t.toLowerCase().includes("1 min") || t.toLowerCase().includes("1 minute"));70    expect(has1Min).toBeTruthy();71    await ctx.close();72  });7374  test("AUL03 - auto-lock options: 5 minutes", async () => {75    const { popup } = await setupVault(ctx);76    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();77    await popup.waitForTimeout(500);78    await popup.locator("text=auto-lock").click();79    await popup.waitForTimeout(300);80    const options = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option");81    const optionTexts = await options.allTextContents();82    const has5Min = optionTexts.some((t: string) => t.toLowerCase().includes("5 min") || t.toLowerCase().includes("5 minute"));83    expect(has5Min).toBeTruthy();84    await ctx.close();85  });8687  test("AUL04 - auto-lock options: 15 minutes", async () => {88    const { popup } = await setupVault(ctx);89    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();90    await popup.waitForTimeout(500);91    await popup.locator("text=auto-lock").click();92    await popup.waitForTimeout(300);93    const options = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option");94    const optionTexts = await options.allTextContents();95    const has15Min = optionTexts.some((t: string) => t.toLowerCase().includes("15 min") || t.toLowerCase().includes("15 minute"));96    expect(has15Min).toBeTruthy();97    await ctx.close();98  });99100  test("AUL05 - auto-lock options: 1 hour", async () => {101    const { popup } = await setupVault(ctx);102    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();103    await popup.waitForTimeout(500);104    await popup.locator("text=auto-lock").click();105    await popup.waitForTimeout(300);106    const options = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option");107    const optionTexts = await options.allTextContents();108    const has1Hr = optionTexts.some((t: string) => t.toLowerCase().includes("1 hour") || t.toLowerCase().includes("1 hr"));109    expect(has1Hr).toBeTruthy();110    await ctx.close();111  });112113  test("AUL06 - auto-lock options: never", async () => {114    const { popup } = await setupVault(ctx);115    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();116    await popup.waitForTimeout(500);117    await popup.locator("text=auto-lock").click();118    await popup.waitForTimeout(300);119    const options = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option");120    const optionTexts = await options.allTextContents();121    const hasNever = optionTexts.some((t: string) => t.toLowerCase().includes("never"));122    expect(hasNever).toBeTruthy();123    await ctx.close();124  });125126  test("AUL07 - selecting auto-lock option closes dropdown", async () => {127    const { popup } = await setupVault(ctx);128    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();129    await popup.waitForTimeout(500);130    await popup.locator("text=auto-lock").click();131    await popup.waitForTimeout(300);132    const option = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option").first();133    await option.click();134    await popup.waitForTimeout(300);135    const dropdown = popup.locator("[role='listbox' i], [role='menu' i], .peach-select-dropdown");136    const isHidden = await dropdown.isHidden().catch(() => true);137    expect(isHidden).toBeTruthy();138    await ctx.close();139  });140141  test("AUL08 - auto-lock selection persists after reopen", async () => {142    const { popup } = await setupVault(ctx);143    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();144    await popup.waitForTimeout(500);145    await popup.locator("text=auto-lock").click();146    await popup.waitForTimeout(300);147    const options = popup.locator("[role='option' i], [role='menuitem' i], .peach-select-option");148    await options.nth(2).click();149    await popup.waitForTimeout(300);150    await popup.keyboard.press("Escape");151    await popup.waitForTimeout(200);152    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();153    await popup.waitForTimeout(500);154    await popup.locator("text=auto-lock").click();155    await popup.waitForTimeout(300);156    const selectedOption = popup.locator("[role='option' i][aria-selected='true'], .peach-select-option.is-selected").first();157    await selectedOption.isVisible({ timeout: 2000 }).catch(() => false);158    await ctx.close();159  });160});161162test.describe("Clipboard Clear Settings", () => {163  let ctx: BrowserContext;164  test.afterEach(async () => { await ctx.close(); });165  test.beforeEach(async () => { ctx = await makeContext(); });166167  test("ACP01 - clipboard clear setting exists", async () => {168    const { popup } = await setupVault(ctx);169    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();170    await popup.waitForTimeout(500);171    await expect(popup.locator("text=clipboard clear")).toBeVisible();172    await ctx.close();173  });174175  test("ACP02 - clipboard clear options: 30 seconds", async () => {176    const { popup } = await setupVault(ctx);177    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();178    await popup.waitForTimeout(500);179    await popup.locator("text=clipboard clear").click();180    await popup.waitForTimeout(300);181    const options = popup.locator("[role='option' i], [role='menuitem' i]");182    const optionTexts = await options.allTextContents();183    const has30s = optionTexts.some((t: string) => t.includes("30") || t.includes("30s"));184    expect(has30s).toBeTruthy();185    await ctx.close();186  });187188  test("ACP03 - clipboard clear options: 60 seconds", async () => {189    const { popup } = await setupVault(ctx);190    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();191    await popup.waitForTimeout(500);192    await popup.locator("text=clipboard clear").click();193    await popup.waitForTimeout(300);194    const options = popup.locator("[role='option' i], [role='menuitem' i]");195    const optionTexts = await options.allTextContents();196    const has60s = optionTexts.some((t: string) => t.includes("60") || t.includes("1 min"));197    expect(has60s).toBeTruthy();198    await ctx.close();199  });200201  test("ACP04 - clipboard clear options: 90 seconds", async () => {202    const { popup } = await setupVault(ctx);203    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();204    await popup.waitForTimeout(500);205    await popup.locator("text=clipboard clear").click();206    await popup.waitForTimeout(300);207    const options = popup.locator("[role='option' i], [role='menuitem' i]");208    const optionTexts = await options.allTextContents();209    const has90s = optionTexts.some((t: string) => t.includes("90"));210    expect(has90s).toBeTruthy();211    await ctx.close();212  });213214  test("ACP05 - clipboard clear options: never", async () => {215    const { popup } = await setupVault(ctx);216    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();217    await popup.waitForTimeout(500);218    await popup.locator("text=clipboard clear").click();219    await popup.waitForTimeout(300);220    const options = popup.locator("[role='option' i], [role='menuitem' i]");221    const optionTexts = await options.allTextContents();222    const hasNever = optionTexts.some((t: string) => t.toLowerCase().includes("never"));223    expect(hasNever).toBeTruthy();224    await ctx.close();225  });226227  test("ACP06 - clipboard clear persists after close", async () => {228    const { popup } = await setupVault(ctx);229    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();230    await popup.waitForTimeout(500);231    await popup.locator("text=clipboard clear").click();232    await popup.waitForTimeout(300);233    const options = popup.locator("[role='option' i], [role='menuitem' i]");234    await options.first().click();235    await popup.waitForTimeout(300);236    await popup.keyboard.press("Escape");237    await popup.waitForTimeout(200);238    const counter = popup.locator(".peach-search-counter");239    const text = await counter.textContent();240    expect(text).toBeTruthy();241    await ctx.close();242  });243});244245test.describe("Lock on Close", () => {246  let ctx: BrowserContext;247  test.afterEach(async () => { await ctx.close(); });248  test.beforeEach(async () => { ctx = await makeContext(); });249250  test("ALC01 - lock on close setting exists", async () => {251    const { popup } = await setupVault(ctx);252    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();253    await popup.waitForTimeout(500);254    await expect(popup.locator("text=lock on close")).toBeVisible();255    await ctx.close();256  });257258  test("ALC02 - lock on close is a toggle switch", async () => {259    const { popup } = await setupVault(ctx);260    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();261    await popup.waitForTimeout(500);262    const toggle = popup.locator("text=lock on close").locator("..").locator("[role='switch' i], [type='checkbox']").first();263    await expect(toggle).toBeVisible();264    await ctx.close();265  });266267  test("ALC03 - lock on close toggle is off by default", async () => {268    const { popup } = await setupVault(ctx);269    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();270    await popup.waitForTimeout(500);271    const toggle = popup.locator("text=lock on close").locator("..").locator("[role='switch' i]").first();272    const isChecked = await toggle.getAttribute("aria-checked");273    expect(isChecked).not.toBe("true");274    await ctx.close();275  });276277  test("ALC04 - enabling lock on close changes toggle state", async () => {278    const { popup } = await setupVault(ctx);279    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();280    await popup.waitForTimeout(500);281    const toggle = popup.locator("text=lock on close").locator("..").locator("[role='switch' i]").first();282    await toggle.click();283    await popup.waitForTimeout(300);284    const isChecked = await toggle.getAttribute("aria-checked");285    expect(isChecked).toBe("true");286    await ctx.close();287  });288289  test("ALC05 - lock on close persists after settings close", async () => {290    const { popup } = await setupVault(ctx);291    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();292    await popup.waitForTimeout(500);293    const toggle = popup.locator("text=lock on close").locator("..").locator("[role='switch' i]").first();294    await toggle.click();295    await popup.waitForTimeout(300);296    await popup.keyboard.press("Escape");297    await popup.waitForTimeout(200);298    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();299    await popup.waitForTimeout(500);300    const toggle2 = popup.locator("text=lock on close").locator("..").locator("[role='switch' i]").first();301    const isChecked = await toggle2.getAttribute("aria-checked");302    expect(isChecked).toBe("true");303    await ctx.close();304  });305});306307test.describe("Breach Monitoring Settings", () => {308  let ctx: BrowserContext;309  test.afterEach(async () => { await ctx.close(); });310  test.beforeEach(async () => { ctx = await makeContext(); });311312  test("ABM01 - breach monitoring setting exists", async () => {313    const { popup } = await setupVault(ctx);314    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();315    await popup.waitForTimeout(500);316    await expect(popup.locator("text=breach monitoring")).toBeVisible();317    await ctx.close();318  });319320  test("ABM02 - breach monitoring is a toggle switch", async () => {321    const { popup } = await setupVault(ctx);322    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();323    await popup.waitForTimeout(500);324    const toggle = popup.locator("text=breach monitoring").locator("..").locator("[role='switch' i]").first();325    await expect(toggle).toBeVisible();326    await ctx.close();327  });328329  test("ABM03 - breach monitoring toggle changes state", async () => {330    const { popup } = await setupVault(ctx);331    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();332    await popup.waitForTimeout(500);333    const toggle = popup.locator("text=breach monitoring").locator("..").locator("[role='switch' i]").first();334    const beforeState = await toggle.getAttribute("aria-checked");335    await toggle.click();336    await popup.waitForTimeout(300);337    const afterState = await toggle.getAttribute("aria-checked");338    expect(beforeState).not.toEqual(afterState);339    await ctx.close();340  });341342  test("ABM04 - breach monitoring persists after close", async () => {343    const { popup } = await setupVault(ctx);344    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();345    await popup.waitForTimeout(500);346    const toggle = popup.locator("text=breach monitoring").locator("..").locator("[role='switch' i]").first();347    await toggle.click();348    await popup.waitForTimeout(300);349    await popup.keyboard.press("Escape");350    await popup.waitForTimeout(200);351    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();352    await popup.waitForTimeout(500);353    const toggle2 = popup.locator("text=breach monitoring").locator("..").locator("[role='switch' i]").first();354    const isChecked = await toggle2.getAttribute("aria-checked");355    expect(isChecked).toBe("true");356    await ctx.close();357  });358});359360test.describe("Accent Color Settings", () => {361  let ctx: BrowserContext;362  test.afterEach(async () => { await ctx.close(); });363  test.beforeEach(async () => { ctx = await makeContext(); });364365  test("AAC01 - accent color section exists in settings", async () => {366    const { popup } = await setupVault(ctx);367    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();368    await popup.waitForTimeout(500);369    const swatches = popup.locator(".peach-swatch");370    const count = await swatches.count();371    expect(count).toBeGreaterThan(0);372    await ctx.close();373  });374375  test("AAC02 - all swatches are clickable", async () => {376    const { popup } = await setupVault(ctx);377    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();378    await popup.waitForTimeout(500);379    const swatches = popup.locator(".peach-swatch");380    const count = await swatches.count();381    expect(count).toBeGreaterThanOrEqual(5);382    for (let i = 0; i < count; i++) {383      await swatches.nth(i).click();384      await popup.waitForTimeout(100);385    }386    await ctx.close();387  });388389  test("AAC03 - selected swatch shows active state", async () => {390    const { popup } = await setupVault(ctx);391    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();392    await popup.waitForTimeout(500);393    const swatch = popup.locator(".peach-swatch").nth(3);394    await swatch.click();395    await popup.waitForTimeout(200);396    const isActive = await swatch.evaluate((el: Element) => el.classList.contains("is-active"));397    expect(isActive).toBeTruthy();398    await ctx.close();399  });400401  test("AAC04 - only one swatch active at a time", async () => {402    const { popup } = await setupVault(ctx);403    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();404    await popup.waitForTimeout(500);405    await popup.locator(".peach-swatch").nth(0).click();406    await popup.waitForTimeout(200);407    await popup.locator(".peach-swatch").nth(2).click();408    await popup.waitForTimeout(200);409    const activeSwatches = popup.locator(".peach-swatch.is-active");410    const count = await activeSwatches.count();411    expect(count).toBe(1);412    await ctx.close();413  });414415  test("AAC05 - accent color persists after settings close", async () => {416    const { popup } = await setupVault(ctx);417    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();418    await popup.waitForTimeout(500);419    await popup.locator(".peach-swatch").nth(4).click();420    await popup.waitForTimeout(200);421    await popup.keyboard.press("Escape");422    await popup.waitForTimeout(200);423    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();424    await popup.waitForTimeout(500);425    const activeSwatch = popup.locator(".peach-swatch.is-active");426    const count = await activeSwatch.count();427    expect(count).toBe(1);428    await ctx.close();429  });430});431432test.describe("Entry Count & Vault Info", () => {433  let ctx: BrowserContext;434  test.afterEach(async () => { await ctx.close(); });435  test.beforeEach(async () => { ctx = await makeContext(); });436437  test("AEV01 - settings shows entry count", async () => {438    const { popup } = await setupVault(ctx);439    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();440    await popup.waitForTimeout(500);441    const entriesText = popup.locator("text=entries").first();442    await expect(entriesText).toBeVisible();443    await ctx.close();444  });445446  test("AEV02 - entry count updates when entries added", async () => {447    const { popup } = await setupVault(ctx);448    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();449    await popup.waitForTimeout(500);450    const initialCount = await popup.locator("text=entries").textContent();451    await popup.keyboard.press("Escape");452    await popup.waitForTimeout(200);453    await popup.locator('input[placeholder="search vault..."]').click();454    await popup.getByRole("button", { name: /new entry/i }).click();455    await popup.locator(".peach-new-name-input").fill("CountUpdate");456    await popup.locator('input[placeholder="domain.com"]').fill("https://count.com");457    await popup.locator('input[placeholder="username or email"]').fill("[email protected]");458    await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass");459    await popup.getByRole("button", { name: /create/i }).click();460    await popup.waitForTimeout(1500);461    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();462    await popup.waitForTimeout(500);463    const newCount = await popup.locator("text=entries").textContent();464    expect(newCount).not.toEqual(initialCount);465    await ctx.close();466  });467468  test("AEV03 - version number shows in settings", async () => {469    const { popup } = await setupVault(ctx);470    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();471    await popup.waitForTimeout(500);472    const version = popup.locator("text=1.0.");473    const hasVersion = await version.isVisible({ timeout: 2000 }).catch(() => false);474    expect(hasVersion).toBeTruthy();475    await ctx.close();476  });477});478479test.describe("Settings Navigation", () => {480  let ctx: BrowserContext;481  test.afterEach(async () => { await ctx.close(); });482  test.beforeEach(async () => { ctx = await makeContext(); });483484  test("ASN01 - settings opens with gear icon", async () => {485    const { popup } = await setupVault(ctx);486    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();487    await popup.waitForTimeout(500);488    const title = popup.locator(".peach-overlay-title, text=settings").first();489    await expect(title).toBeVisible();490    await ctx.close();491  });492493  test("ASN02 - settings closes with back button", async () => {494    const { popup } = await setupVault(ctx);495    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();496    await popup.waitForTimeout(500);497    const backBtn = popup.locator("button[aria-label='Back']").first();498    await backBtn.click();499    await popup.waitForTimeout(300);500    const overlay = popup.locator(".peach-overlay-view");501    const isHidden = await overlay.isHidden().catch(() => true);502    expect(isHidden).toBeTruthy();503    await ctx.close();504  });505506  test("ASN03 - settings closes with escape key", async () => {507    const { popup } = await setupVault(ctx);508    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();509    await popup.waitForTimeout(500);510    await popup.keyboard.press("Escape");511    await popup.waitForTimeout(300);512    const overlay = popup.locator(".peach-overlay-view");513    const isHidden = await overlay.isHidden().catch(() => true);514    expect(isHidden).toBeTruthy();515    await ctx.close();516  });517518  test("ASN04 - lock vault button visible in settings", async () => {519    const { popup } = await setupVault(ctx);520    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();521    await popup.waitForTimeout(500);522    const lockBtn = popup.locator("text=lock vault").first();523    await expect(lockBtn).toBeVisible();524    await ctx.close();525  });526527  test("ASN05 - lock vault returns to lock screen", async () => {528    const { popup } = await setupVault(ctx);529    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();530    await popup.waitForTimeout(500);531    await popup.locator("text=lock vault").click();532    await popup.waitForTimeout(1500);533    const pwField = popup.locator("#master-password");534    await expect(pwField).toBeVisible({ timeout: 5000 });535    await ctx.close();536  });537538  test("ASN06 - export button visible in settings", async () => {539    const { popup } = await setupVault(ctx);540    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();541    await popup.waitForTimeout(500);542    const exportBtn = popup.getByRole("button", { name: /export/i }).first();543    await expect(exportBtn).toBeVisible();544    await ctx.close();545  });546547  test("ASN07 - import button visible in settings", async () => {548    const { popup } = await setupVault(ctx);549    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();550    await popup.waitForTimeout(500);551    const importBtn = popup.getByRole("button", { name: /import/i }).first();552    await expect(importBtn).toBeVisible();553    await ctx.close();554  });555556  test("ASN08 - generator button visible in settings", async () => {557    const { popup } = await setupVault(ctx);558    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();559    await popup.waitForTimeout(500);560    const genBtn = popup.getByRole("button", { name: /generator/i }).first();561    await expect(genBtn).toBeVisible();562    await ctx.close();563  });564});565566test.describe("Settings Persistence", () => {567  let ctx: BrowserContext;568  test.afterEach(async () => { await ctx.close(); });569  test.beforeEach(async () => { ctx = await makeContext(); });570571  test("ASP01 - all settings persist after vault lock/unlock", async () => {572    const { popup } = await setupVault(ctx);573    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();574    await popup.waitForTimeout(500);575    const swatch = popup.locator(".peach-swatch").nth(5);576    await swatch.click();577    await popup.waitForTimeout(200);578    await popup.keyboard.press("Escape");579    await popup.waitForTimeout(200);580    const lockBtn = popup.locator(".peach-lock-btn[aria-label='Lock vault']");581    await lockBtn.click();582    await popup.waitForTimeout(1500);583    await popup.locator("#master-password").fill("password123");584    await popup.getByRole("button", { name: /unlock/i }).click();585    await popup.waitForTimeout(2000);586    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();587    await popup.waitForTimeout(500);588    const activeSwatch = popup.locator(".peach-swatch.is-active");589    const count = await activeSwatch.count();590    expect(count).toBe(1);591    await ctx.close();592  });593594  test("ASP02 - accent color persists after new entry", async () => {595    const { popup } = await setupVault(ctx);596    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();597    await popup.waitForTimeout(500);598    await popup.locator(".peach-swatch").nth(2).click();599    await popup.waitForTimeout(200);600    await popup.keyboard.press("Escape");601    await popup.waitForTimeout(200);602    await popup.locator('input[placeholder="search vault..."]').click();603    await popup.getByRole("button", { name: /new entry/i }).click();604    await popup.locator(".peach-new-name-input").fill("PersistTest");605    await popup.locator('input[placeholder="domain.com"]').fill("https://persist.com");606    await popup.locator('input[placeholder="username or email"]').fill("[email protected]");607    await popup.locator(".peach-new-field-input[placeholder='password']").fill("pass");608    await popup.getByRole("button", { name: /create/i }).click();609    await popup.waitForTimeout(1500);610    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();611    await popup.waitForTimeout(500);612    const activeSwatch = popup.locator(".peach-swatch.is-active");613    const count = await activeSwatch.count();614    expect(count).toBe(1);615    await ctx.close();616  });617618  test("ASP03 - toggle settings persist after page navigation", async () => {619    const { popup } = await setupVault(ctx);620    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();621    await popup.waitForTimeout(500);622    const lockToggle = popup.locator("text=lock on close").locator("..").locator("[role='switch' i]").first();623    await lockToggle.click();624    await popup.waitForTimeout(200);625    await popup.keyboard.press("Escape");626    await popup.waitForTimeout(200);627    await popup.locator(".peach-entry-name-button").first().click();628    await popup.waitForTimeout(500);629    await popup.locator("button[aria-label='Back']").first().click();630    await popup.waitForTimeout(300);631    await popup.locator(".peach-icon-btn[aria-label='Settings']").click();632    await popup.waitForTimeout(500);633    const isChecked = await lockToggle.getAttribute("aria-checked");634    expect(isChecked).toBe("true");635    await ctx.close();636  });637});