diff --git a/e2e/USER_STORIES.md b/e2e/USER_STORIES.md index 6bc9f7f8..efd70061 100644 --- a/e2e/USER_STORIES.md +++ b/e2e/USER_STORIES.md @@ -48,12 +48,16 @@ key in the app, so that I can start participating without an external tool. Acceptance: -- Entering a display name advances to a key-backup step whose "Continue" button - stays disabled until a key file has been downloaded. -- Choosing the encrypted download requires a password of at least 12 characters - and produces a file containing an ncryptsec rather than a plain nsec. +- Entering a display name advances directly to the completion step without showing + the key-backup modal. - Finishing the flow logs the new user in, dismisses the dialog, and lands on the dashboard with the platform's default space visible. +- The dashboard shows a pending "Back Up Your Key" health check until the existing + backup flow completes successfully; leaving the modal keeps the check pending. +- Reloading preserves both the pending reminder and a completed backup. +- Applying all recommendations opens the backup flow alongside the automatic relay fixes. +- Choosing the encrypted download requires a password of at least 12 characters + and produces a file containing an ncryptsec rather than a plain nsec. - The display name entered during signup appears on the new user's own profile. ### US-003 — Log in with an existing private key @@ -68,6 +72,7 @@ Acceptance: - Pasting an ncryptsec reveals a password field: the correct password logs in, a wrong one shows an error and stays logged out. - Text that is not a valid key leaves the submit button disabled. +- Logging in with an existing private key does not enable the "Back Up Your Key" health check. - bob logging in with his own key in a separate context sees his own identity, not alice's. diff --git a/e2e/specs/onboarding.spec.ts b/e2e/specs/onboarding.spec.ts index 1ac3ab7a..bb8ace0f 100644 --- a/e2e/specs/onboarding.spec.ts +++ b/e2e/specs/onboarding.spec.ts @@ -100,36 +100,7 @@ test("US-002 sign up by generating a new key", async ({seed, visit}) => { await page.locator('input[type="text"]').fill("Nova Tester") await page.getByRole("button", {name: "Create Account"}).click() - await expect(page.getByRole("heading", {name: "Your Keys are Ready!"})).toBeVisible() - - const continueButton = page.getByRole("button", {name: "Continue"}) - const password = page.locator('input[type="password"]') - - await expect(continueButton).toBeDisabled() - - await page.getByRole("button", {name: "I want to download an encrypted version"}).click() - await password.fill("hunter2") - await page.getByRole("button", {name: "Download my key"}).click() - - await expect(page.getByRole("alert")).toContainText( - "Your password must be at least 12 characters long.", - ) - await expect(continueButton).toBeDisabled() - - await password.fill("correct horse battery staple") - - const download = page.waitForEvent("download") - - await page.getByRole("button", {name: "Download my key"}).click() - - const contents = await readFile(await (await download).path(), "utf8") - - expect(contents).toContain("ncryptsec1") - expect(contents).not.toContain("nsec1") - - await expect(continueButton).toBeEnabled() - await continueButton.click() - + await expect(page.getByRole("heading", {name: "Backup your Key"})).toHaveCount(0) await expect(page.getByRole("heading", {name: "You're all set!"})).toBeVisible() await page.getByRole("button", {name: "Go to Dashboard"}).click() @@ -138,6 +109,7 @@ test("US-002 sign up by generating a new key", async ({seed, visit}) => { await expect(page.locator(".primary-nav")).toBeVisible() await expect(page.getByRole("heading", {name: "You're all set!"})).toHaveCount(0) await expect(gate(page)).toHaveCount(0) + await expect(page.getByText("Back Up Your Key")).toBeVisible() // A space's nav item is a button rather than a link — PrimaryNavItemSpace passes an onclick, and // PrimaryNavItem renders a Button whenever it has one — so it is addressed by the tooltip it @@ -151,6 +123,58 @@ test("US-002 sign up by generating a new key", async ({seed, visit}) => { await openSettings(page) await expect(page.getByText("Nova Tester")).toBeVisible() + + await page.goto("/home") + await expect(page.getByText("Back Up Your Key")).toBeVisible() + + await page.reload() + + await expect(page.getByText("Back Up Your Key")).toBeVisible() + + const backupCheck = page.getByRole("group", {name: "Back Up Your Key"}) + + await page.getByRole("button", {name: "Apply all recommendations"}).click() + await expect(page.getByRole("heading", {name: "Backup your Key"})).toBeVisible() + await page.getByRole("button", {name: "Go back"}).click() + await expect(backupCheck).toBeVisible() + + await backupCheck.getByRole("button", {name: "Back Up"}).click() + await expect(page.getByRole("heading", {name: "Backup your Key"})).toBeVisible() + await page.getByRole("button", {name: "Go back"}).click() + await expect(page.getByText("Back Up Your Key")).toBeVisible() + + await backupCheck.getByRole("button", {name: "Back Up"}).click() + + const doneButton = page.getByRole("button", {name: "Done"}) + const password = page.locator('input[type="password"]') + + await page.getByRole("button", {name: "I want to download an encrypted version"}).click() + await password.fill("hunter2") + await page.getByRole("button", {name: "Download my key"}).click() + + await expect(page.getByRole("alert")).toContainText( + "Your password must be at least 12 characters long.", + ) + await expect(doneButton).toBeDisabled() + + await password.fill("correct horse battery staple") + + const download = page.waitForEvent("download") + + await page.getByRole("button", {name: "Download my key"}).click() + + const contents = await readFile(await (await download).path(), "utf8") + + expect(contents).toContain("ncryptsec1") + expect(contents).not.toContain("nsec1") + + await expect(doneButton).toBeEnabled() + await doneButton.click() + + await expect(page.getByText("Back Up Your Key")).toHaveCount(0) + await page.reload() + await expect(page.locator(".primary-nav")).toBeVisible() + await expect(page.getByText("Back Up Your Key")).toHaveCount(0) }) test("US-003 log in with an existing private key", async ({seed, visit}) => { @@ -166,6 +190,7 @@ test("US-003 log in with an existing private key", async ({seed, visit}) => { await logInWithKey(withNsec, nsecFor(users.alice)) await expect(withNsec.locator(".primary-nav")).toBeVisible() + await expect(withNsec.getByText("Back Up Your Key")).toHaveCount(0) await openSettings(withNsec) await expect(npubField(withNsec)).toHaveValue(aliceNpub) @@ -173,6 +198,7 @@ test("US-003 log in with an existing private key", async ({seed, visit}) => { await logInWithKey(withHex, users.alice.secret) await expect(withHex.locator(".primary-nav")).toBeVisible() + await expect(withHex.getByText("Back Up Your Key")).toHaveCount(0) await openSettings(withHex) await expect(npubField(withHex)).toHaveValue(aliceNpub) @@ -201,6 +227,7 @@ test("US-003 log in with an existing private key", async ({seed, visit}) => { await submit.click() await expect(withNcryptsec.locator(".primary-nav")).toBeVisible() + await expect(withNcryptsec.getByText("Back Up Your Key")).toHaveCount(0) await openSettings(withNcryptsec) await expect(npubField(withNcryptsec)).toHaveValue(aliceNpub) diff --git a/src/app/components/HealthCheckItem.svelte b/src/app/components/HealthCheckItem.svelte index c1956444..01f3fa26 100644 --- a/src/app/components/HealthCheckItem.svelte +++ b/src/app/components/HealthCheckItem.svelte @@ -14,7 +14,10 @@ const apply = () => $healthChecks.apply(healthCheck) -
{healthCheck.description}
diff --git a/src/app/components/HomeHealthChecks.svelte b/src/app/components/HomeHealthChecks.svelte index f138a3a1..653f7c4b 100644 --- a/src/app/components/HomeHealthChecks.svelte +++ b/src/app/components/HomeHealthChecks.svelte @@ -31,7 +31,7 @@ {:else}
A cryptographic key pair has two parts: your public key identifies your
diff --git a/src/app/components/SignUp.svelte b/src/app/components/SignUp.svelte
index 5676c640..e66a7832 100644
--- a/src/app/components/SignUp.svelte
+++ b/src/app/components/SignUp.svelte
@@ -1,6 +1,7 @@
-
-