| 1 | import assert from "node:assert/strict"; |
| 2 | import { readFileSync } from "node:fs"; |
| 3 | import test from "node:test"; |
| 4 | |
| 5 | const verifyPage = readFileSync(new URL("../app/verify-email/page.tsx", import.meta.url), "utf8"); |
| 6 | const workspace = readFileSync(new URL("../app/components/investment-workspace.tsx", import.meta.url), "utf8"); |
| 7 | const resetPage = readFileSync(new URL("../app/reset-password/page.tsx", import.meta.url), "utf8"); |
| 8 | |
| 9 | test("verification success is an exclusive public confirmation with a scheduled sign-in redirect", () => { |
| 10 | const success = verifyPage.match(/if \(state === "SUCCESS"\)[\s\S]*?\n }\n\n if \(state === "INVALID"\)/)?.[0] ?? ""; |
| 11 | assert.match(success, /Email verified successfully\./); |
| 12 | assert.match(success, /Redirecting you to sign in\.\.\./); |
| 13 | assert.match(success, /Sign in now/); |
| 14 | assert.match(verifyPage, /window\.setTimeout\(\(\) => router\.push\("\/"\), 1500\)/); |
| 15 | assert.doesNotMatch(success, /Resend verification email|Check your email|Verify email/); |
| 16 | }); |
| 17 | |
| 18 | test("invalid verification links expose only recovery actions", () => { |
| 19 | const invalid = verifyPage.match(/if \(state === "INVALID"\)[\s\S]*?\n }\n\n return/ )?.[0] ?? ""; |
| 20 | assert.match(invalid, /Verification link expired/); |
| 21 | assert.match(invalid, /This verification link is invalid or expired\./); |
| 22 | assert.match(invalid, /Resend verification email/); |
| 23 | assert.doesNotMatch(invalid, /Email verified successfully\./); |
| 24 | }); |
| 25 | |
| 26 | test("public verification route does not mount the authenticated workspace", () => { |
| 27 | assert.match(verifyPage, /authApi\.verifyEmail\(token\)/); |
| 28 | assert.doesNotMatch(verifyPage, /InvestmentWorkspace|portfolioApi|Your session expired/); |
| 29 | }); |
| 30 | |
| 31 | test("pending registration keeps resend available without normal-mode manual token entry", () => { |
| 32 | assert.match(workspace, /Check your email and open the verification link\./); |
| 33 | assert.match(workspace, /Resend verification email/); |
| 34 | assert.match(workspace, /frontendConfig\.authDevLoginEnabled \? <input name="token"/); |
| 35 | }); |
| 36 | |
| 37 | test("logout clears authenticated state and returns to the canonical login route", () => { |
| 38 | const logout = workspace.match(/function logout\(\) \{[\s\S]*?\n }\n\n if \(authLoading\)/)?.[0] ?? ""; |
| 39 | assert.match(logout, /removeItem\("aip\.accessToken"\)/); |
| 40 | assert.match(logout, /removeItem\("aip\.user"\)/); |
| 41 | assert.match(logout, /window\.history\.replaceState\(\{\}, "", "\/"\)/); |
| 42 | assert.match(logout, /setError\(null\)/); |
| 43 | assert.match(logout, /setAccessToken\(null\)/); |
| 44 | assert.match(logout, /setAuthenticatedUser\(null\)/); |
| 45 | }); |
| 46 | |
| 47 | test("registration surfaces the safe active-account guidance and permits pending re-registration", () => { |
| 48 | assert.match(workspace, /submit\(form\)\.catch\(\(err\) => setMessage\(getApiFailure\(err\)\.message\)\)/); |
| 49 | assert.match(workspace, /We sent a verification link to your email address\./); |
| 50 | }); |
| 51 | |
| 52 | test("public sign-in exposes an enumeration-safe resend-verification recovery", () => { |
| 53 | assert.match(workspace, /setMode\("RESEND"\)/); |
| 54 | assert.match(workspace, /authApi\.resendVerification\(email\)/); |
| 55 | assert.match(workspace, /If this account is awaiting verification, a new verification email has been sent\./); |
| 56 | assert.doesNotMatch(workspace.match(/mode === "RESEND"[\s\S]*?return;/)?.[0] ?? "", /token/); |
| 57 | }); |
| 58 | |
| 59 | test("public password fields use inline accessible eye controls", () => { |
| 60 | assert.match(workspace, /className="password-input"/); |
| 61 | assert.match(workspace, /className="password-toggle"/); |
| 62 | assert.match(workspace, /aria-label=\{visible \? "Hide password" : "Show password"\}/); |
| 63 | assert.match(workspace, /name="confirmPassword"/); |
| 64 | assert.doesNotMatch(workspace, /Show or hide password/); |
| 65 | assert.match(resetPage, /className="password-toggle"/); |
| 66 | assert.match(resetPage, /new URLSearchParams\(window\.location\.search\)\.get\("token"\)/); |
| 67 | assert.doesNotMatch(resetPage, /token\}\s*<\//); |
| 68 | }); |
| 69 | |
| 70 | test("public auth cannot mount workspace requests with only a stale token", () => { |
| 71 | assert.match(workspace, /if \(accessToken && authenticatedUser\) \{\s*void loadPortfolios\(\)/); |
| 72 | assert.match(workspace, /if \(accessToken && authenticatedUser\) \{\s*void loadBrokers\(\)/); |
| 73 | assert.match(workspace, /setError\(null\)/); |
| 74 | }); |