1import { test, expect, type BrowserContext } from "@playwright/test";2import {3 UNLOCKED,4 VAULT_PASSWORD,5 addEntry,6 loadPopup,7 lockVault,8 makeContext,9 reachCreateScreen,10 setLockOnClose,11 setupVault,12 unlockVault,13} from "./helpers/vault";1415161718test.describe.configure({ timeout: 90_000 });1920212223242526272829test.describe("Vault creation gate", () => {30 let ctx: BrowserContext;31 test.afterEach(async () => { if (ctx) await ctx.close(); });32 test.beforeEach(async () => { ctx = await makeContext("peach-lifecycle"); });3334 test("VL01 - fresh install opens the intro carousel", async () => {35 const { popup } = await loadPopup(ctx);36 await expect(popup.locator(".peach-onboarding-card")).toBeVisible({ timeout: 5000 });37 await expect(popup.locator("#master-password")).toHaveCount(0);38 });3940 test("VL02 - the carousel leads to the create-vault form", async () => {41 const { popup } = await loadPopup(ctx);42 await reachCreateScreen(popup);43 await expect(popup.locator("#confirm-password")).toBeVisible();44 await expect(popup.locator(".peach-newvault-submit")).toBeDisabled();45 });4647 test("VL03 - a password under 12 characters blocks creation", async () => {48 const { popup } = await loadPopup(ctx);49 await reachCreateScreen(popup);50 await popup.locator("#master-password").fill("shortpw12");51 await popup.locator("#confirm-password").fill("shortpw12");52 const submit = popup.locator(".peach-newvault-submit");53 await expect(submit).toBeDisabled();54 await expect(submit).toHaveText(/more characters/i);55 });5657 test("VL04 - a long but weak password blocks creation", async () => {58 const { popup } = await loadPopup(ctx);59 await reachCreateScreen(popup);60 await popup.locator("#master-password").fill("password123456");61 await popup.locator("#confirm-password").fill("password123456");62 const submit = popup.locator(".peach-newvault-submit");63 await expect(submit).toBeDisabled();64 await expect(submit).toHaveText(/too weak/i);65 });6667 test("VL05 - mismatched confirmation blocks creation", async () => {68 const { popup } = await loadPopup(ctx);69 await reachCreateScreen(popup);70 await popup.locator("#master-password").fill(VAULT_PASSWORD);71 await popup.locator("#confirm-password").fill("correct horse battery stapl");72 const submit = popup.locator(".peach-newvault-submit");73 await expect(submit).toBeDisabled();74 await expect(submit).toHaveText(/don't match/i);75 });7677 test("VL06 - the strength meter reacts to the password", async () => {78 const { popup } = await loadPopup(ctx);79 await reachCreateScreen(popup);80 const label = popup.locator(".peach-strength-label");81 await popup.locator("#master-password").fill("aaaa");82 await expect(label).toHaveText("weak");83 await popup.locator("#master-password").fill(VAULT_PASSWORD);84 await expect(label).toHaveText(/good|strong/);85 });8687 test("VL07 - a passing password creates the vault and unlocks it", async () => {88 const { popup } = await setupVault(ctx);89 await expect(popup.locator(UNLOCKED)).toBeVisible();90 });91});9293test.describe("Vault persistence", () => {94 let ctx: BrowserContext;95 test.afterEach(async () => { if (ctx) await ctx.close(); });96 test.beforeEach(async () => { ctx = await makeContext("peach-lifecycle"); });9798 test("VL08 - a new vault shows the empty state", async () => {99 const { popup } = await setupVault(ctx);100 await expect(popup.locator(".peach-empty-copy")).toBeVisible({ timeout: 5000 });101 });102103 test("VL09 - entries survive lock and unlock", async () => {104 const { popup } = await setupVault(ctx);105 await addEntry(popup, { title: "LockRoundTrip", url: "https://roundtrip.test", username: "[email protected]", password: "entry-secret" });106 await lockVault(popup);107 await unlockVault(popup);108 await expect(popup.locator(".peach-entry-name-text").first()).toHaveText("LockRoundTrip", { timeout: 10000 });109 });110111 test("VL10 - reopening the popup requires the password again", async () => {112 const { popup } = await setupVault(ctx);113 await addEntry(popup, { title: "ReopenTest", url: "https://reopen.test", username: "[email protected]", password: "entry-secret" });114 await setLockOnClose(popup, true);115 await lockVault(popup);116 await popup.close();117118 const { popup: reopened } = await loadPopup(ctx);119 await expect(reopened.locator("#unlock-password")).toBeVisible({ timeout: 15000 });120 await unlockVault(reopened);121 await expect(reopened.locator(".peach-entry-name-text").first()).toHaveText("ReopenTest", { timeout: 10000 });122 });123124 test("VL11 - a wrong password does not unlock a reopened popup", async () => {125 const { popup } = await setupVault(ctx);126 await setLockOnClose(popup, true);127 await lockVault(popup);128 await popup.close();129130 const { popup: reopened } = await loadPopup(ctx);131 await expect(reopened.locator("#unlock-password")).toBeVisible({ timeout: 15000 });132 await reopened.locator("#unlock-password").fill("not the right password");133 await reopened.getByRole("button", { name: /unlock/i }).click();134 await expect(reopened.locator(".peach-hint-error")).toBeVisible({ timeout: 15000 });135 await expect(reopened.locator(UNLOCKED)).toHaveCount(0);136 });137138 test("VL12 - default popup close leaves the vault unlocked", async () => {139 const { popup } = await setupVault(ctx);140 await popup.close();141142 const { popup: reopened } = await loadPopup(ctx);143 await expect(reopened.locator(UNLOCKED)).toBeVisible({ timeout: 15000 });144 });145});