1import { test, expect, type BrowserContext } from "@playwright/test";2import { createEntryViaForm, listSearch, makeContext, openList, setupVault } from "./helpers/vault";3456test.describe.configure({ timeout: 90_000 });78test.describe("Entry CRUD", () => {9 let ctx: BrowserContext;10 test.afterEach(async () => { await ctx.close(); });11 test.beforeEach(async () => { ctx = await makeContext("peach-crud"); });1213 test("EC01 - add entry with all fields", async () => {14 const { popup } = await setupVault(ctx);15 await createEntryViaForm(popup, {16 title: "GitHub",17 url: "https://github.com",18 username: "june",19 password: "secret123!",20 });21 await openList(popup);22 await expect(popup.locator(".peach-entry-row-name", { hasText: "GitHub" })).toBeVisible({ timeout: 5000 });23 });2425 test("EC02 - add entry with TOTP shows a live code", async () => {26 const { popup } = await setupVault(ctx);27 await createEntryViaForm(popup, {28 title: "GitHub2FA",29 url: "https://github.com",30 username: "june",31 password: "secret123!",32 totp: "JBSWY3DPEHPK3PXP",33 });34 await openList(popup);35 await popup.locator(".peach-entry-row", { hasText: "GitHub2FA" }).click();36 await expect(popup.locator(".peach-totp-code-text")).toHaveText(/\d{3} \d{3}/, { timeout: 5000 });37 });3839 test("EC03 - edited title persists", async () => {40 const { popup } = await setupVault(ctx);41 await createEntryViaForm(popup, { title: "EditTest", url: "https://edit.test", username: "u", password: "oldpass" });42 await openList(popup);43 await popup.locator(".peach-entry-row", { hasText: "EditTest" }).click();44 await popup.locator(".peach-entry-name-button").click();45 await popup.locator(".peach-inline-title-input").fill("EditedTitle");46 await popup.keyboard.press("Enter");47 await openList(popup);48 await expect(popup.locator(".peach-entry-row-name", { hasText: "EditedTitle" })).toBeVisible({ timeout: 5000 });49 await expect(popup.locator(".peach-entry-row-name", { hasText: "EditTest" })).toHaveCount(0);50 });5152 test("EC04 - delete entry removes it from the vault", async () => {53 const { popup } = await setupVault(ctx);54 await createEntryViaForm(popup, { title: "DeleteMe", url: "https://delete.test", username: "u", password: "p" });55 await openList(popup);56 await popup.locator(".peach-entry-row", { hasText: "DeleteMe" }).click();57 await popup.locator("[aria-label='Move to trash']").click();58 await popup.getByRole("button", { name: /^yes$/i }).click();59 await openList(popup);60 await expect(popup.locator(".peach-entry-row-name", { hasText: "DeleteMe" })).toHaveCount(0, { timeout: 5000 });61 });6263 test("EC05 - search filters entries by title", async () => {64 const { popup } = await setupVault(ctx);65 for (const name of ["Apple", "Amazon"]) {66 await createEntryViaForm(popup, { title: name, url: `https://${name.toLowerCase()}.test`, username: "u", password: "p" });67 }68 await openList(popup);69 await listSearch(popup).fill("Apple");70 await expect(popup.locator(".peach-entry-row-name", { hasText: "Apple" })).toBeVisible();71 await expect(popup.locator(".peach-entry-row-name", { hasText: "Amazon" })).toHaveCount(0);72 });7374 test("EC06 - a fresh vault shows the empty state", async () => {75 const { popup } = await setupVault(ctx);76 await expect(popup.locator(".peach-empty-copy")).toBeVisible({ timeout: 5000 });77 });78});