Skip to content

Differentiate deleted account login errors#232

Merged
auerbachb merged 6 commits into
mainfrom
cursor/login-deleted-account-message-71ed
Apr 25, 2026
Merged

Differentiate deleted account login errors#232
auerbachb merged 6 commits into
mainfrom
cursor/login-deleted-account-message-71ed

Conversation

@auerbachb
Copy link
Copy Markdown
Owner

@auerbachb auerbachb commented Apr 25, 2026

Summary

  • Choose option 2: preserve invalid-credentials responses for unknown emails and wrong passwords, while returning a deleted-account-specific message for emails recorded in a deletion log.
  • Add an account_deletion_log table and transactional deletion logging before hard-deleting users.
  • Address PR review findings by equalizing login timing for unknown non-deleted emails, centralizing the deleted-account message, adding accessible auth error announcements, and hardening login/deletion tests.

Walkthrough

deleted_account_login_error_unclipped_demo.mp4
Deleted account login error

Testing

  • npx tsc --noEmit
  • npm run test:unit
  • npx playwright test e2e/auth/login.spec.ts --project=mobile-chromium-narrow --grep "login shows deleted account errors"
  • npm run build
  • Manual browser walkthrough confirmed the deleted-account message wraps without clipping.
  • GitHub PR checks passed after prior review-fix commits; latest test-refactor push is re-running them.
  • coderabbit review --prompt-only could not run because the coderabbit executable is unavailable in this environment.

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Persistent account-deletion logging with deterministic email-hash lookup; login now returns a distinct deleted-account message (HTTP 410) when applicable.
  • Style

    • Improved authentication error display accessibility and text layout (assertive live alert, wrapping, width constraints, centered).
  • Tests

    • New unit and end-to-end tests covering deleted-account detection, login responses, and account-deletion workflows.

Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
still-point Ready Ready Preview, Comment Apr 25, 2026 2:15am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

📝 Walkthrough

Walkthrough

Adds account-deletion tracking (DB table + schema), email-hash helpers, transactional deletion that logs hashed emails, login route detection returning HTTP 410 for deleted accounts, unit and e2e tests, and an accessibility/layout update for auth error display.

Changes

Cohort / File(s) Summary
Database Schema & Migration
drizzle/account_deletion_log_incremental.sql, src/db/schema.ts
Adds account_deletion_log table with UUID PK, user_id, 64-char email_hash, deleted_at, and indexes; exports accountDeletionLog.
Account Deletion Logic & Tests
src/lib/accountDeletion.ts, src/lib/accountDeletion.test.ts
Adds getAccountDeletionEmailHash() and wasAccountDeleted(); refactors deleteUserAccount() to transactionally insert hashed-email log then delete user; unit tests verify hashing, query shape, transaction ordering.
Login Endpoint & Tests
src/app/api/auth/login/route.ts, src/app/api/auth/login/route.test.ts, e2e/auth/login.spec.ts
Login POST concurrently checks deletion log; if no user row but deletion record exists, returns 410 with DELETED_ACCOUNT_MESSAGE; adds unit and Playwright e2e tests covering deleted-account flows.
Auth UI
src/components/AuthScreen.tsx
Error container updated for accessibility (role="alert", aria-live="assertive", aria-atomic="true") and layout (lineHeight, overflowWrap, maxWidth: "28ch", width: "100%", centered).
Package Config / Test tooling
package.json
Adds test:unit npm script and Vitest devDependency for unit testing.
Auth Errors
src/lib/authErrors.ts
Adds exported DELETED_ACCOUNT_MESSAGE constant used for 410 responses and UI messaging.

Sequence Diagram

sequenceDiagram
    actor User
    participant Client as Client
    participant LoginAPI as Login Endpoint
    participant DB as Database
    participant DeletionLog as Deletion Log

    User->>Client: Enter email & password
    Client->>LoginAPI: POST /api/auth/login
    LoginAPI->>DB: Query users by email
    alt User Found
        DB-->>LoginAPI: user record
        LoginAPI->>LoginAPI: verifyPassword(...)
        alt Password Valid
            LoginAPI-->>Client: 200 OK + token
        else Password Invalid
            LoginAPI-->>Client: 401 Invalid credentials
        end
    else User Not Found
        DB-->>LoginAPI: no record
        LoginAPI->>DeletionLog: wasAccountDeleted(email)
        DeletionLog->>DeletionLog: compute SHA-256 hash & query account_deletion_log
        alt Deletion Record Found
            DeletionLog-->>LoginAPI: true
            LoginAPI-->>Client: 410 DELETED_ACCOUNT_MESSAGE
        else No Deletion Record
            DeletionLog-->>LoginAPI: false
            LoginAPI-->>Client: 401 Invalid credentials
        end
    end
    Client->>User: Display message (accessible alert)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Poem

🐇 A tiny log beneath the ground,
Where hashed addresses softly sound,
When old accounts at last depart,
A 410 speaks from the heart,
Hop on—build new starts all around!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Differentiate deleted account login errors' clearly and concisely summarizes the main change: implementing distinct error handling for deleted accounts during login, which is the central objective across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/login-deleted-account-message-71ed

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
@cursor cursor Bot marked this pull request as ready for review April 25, 2026 00:51
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 35b11a9. Configure here.

if (!user) {
if (await wasAccountDeleted(email)) {
return NextResponse.json({ error: DELETED_ACCOUNT_MESSAGE }, { status: 410 });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deletion check enables email enumeration via timing

Medium Severity

When a user is not found, wasAccountDeleted performs an additional database query before responding, while an incorrect-password attempt does not. This timing difference allows an attacker to distinguish "never existed" from "exists but wrong password" via response time, undermining the uniform "Invalid credentials" response intended to prevent email enumeration. The wasAccountDeleted call also distinguishes deleted accounts from truly unknown ones via the 410 status, which is intentional per the PR, but the timing side-channel on the non-deleted unknown path is likely unintentional.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 35b11a9. Configure here.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
src/lib/accountDeletion.test.ts (1)

76-89: Strengthen this test by asserting insert happens before delete.

You already verify both calls occur; adding call-order assertions would enforce the transactional sequencing requirement explicitly.

🧪 Suggested assertion add-on
   expect(txInsert).toHaveBeenCalled();
   expect(txInsertValues).toHaveBeenCalledWith({
     userId: "user-1",
     emailHash: getAccountDeletionEmailHash("Deleted@Example.com"),
   });
   expect(txDelete).toHaveBeenCalled();
   expect(txDeleteWhere).toHaveBeenCalled();
+  const insertCallOrder = txInsertValues.mock.invocationCallOrder[0];
+  const deleteCallOrder = txDeleteWhere.mock.invocationCallOrder[0];
+  expect(insertCallOrder).toBeLessThan(deleteCallOrder);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/accountDeletion.test.ts` around lines 76 - 89, Add assertions that
the insert occurs before the delete by checking the mocks' invocation order:
after importing deleteUserAccount and calling it, assert that
txInsert.mock.invocationCallOrder[0] (or txInsertValues if you prefer) is less
than txDelete.mock.invocationCallOrder[0] (and/or txDeleteWhere) to enforce
sequencing; reference the test's deleteUserAccount and
getAccountDeletionEmailHash, and the mocks txInsert, txInsertValues, txDelete,
and txDeleteWhere when adding these order checks.
src/components/AuthScreen.tsx (1)

152-164: Expose auth errors as a live region for screen readers.

This block is visually improved, but adding role="alert" + aria-live would make API error updates announced immediately.

♿ Suggested tweak
-        {error && (
-          <div style={{
+        {error && (
+          <div
+            role="alert"
+            aria-live="polite"
+            style={{
             fontFamily: "var(--font-jetbrains), 'JetBrains Mono', monospace",
             fontSize: "11px", color: "var(--accent-danger)",
             textAlign: "center",
             lineHeight: 1.5,
             overflowWrap: "break-word",
             width: "100%",
             maxWidth: "28ch",
             margin: "0 auto",
-          }}>
+          }}
+          >
             {error}
           </div>
         )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/AuthScreen.tsx` around lines 152 - 164, The error display in
the AuthScreen component should be made accessible to screen readers by turning
the error container into a live region: update the error <div> used in
AuthScreen to include role="alert" and aria-live="assertive" (and optionally
aria-atomic="true") so that API error messages are announced immediately when
the {error} state changes; locate the error rendering block in AuthScreen and
add these attributes to the div wrapping {error}.
src/app/api/auth/login/route.ts (1)

8-8: Consider centralizing the deleted-account message string.

This literal is now contract-like across route/unit/E2E paths; moving it to a shared auth-error constant would reduce drift risk.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/api/auth/login/route.ts` at line 8, The literal
DELETED_ACCOUNT_MESSAGE in route.ts should be moved to a shared auth error
constants module (e.g., export const DELETED_ACCOUNT_MESSAGE in a new or
existing auth-errors/auth-constants file) and then replaced with an import in
src/app/api/auth/login/route.ts and any unit/E2E tests or other routes that rely
on the same message; update code references to use the exported symbol
DELETED_ACCOUNT_MESSAGE and adjust imports in tests and route handlers so all
places consume the single canonical constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/app/api/auth/login/route.ts`:
- Line 8: The literal DELETED_ACCOUNT_MESSAGE in route.ts should be moved to a
shared auth error constants module (e.g., export const DELETED_ACCOUNT_MESSAGE
in a new or existing auth-errors/auth-constants file) and then replaced with an
import in src/app/api/auth/login/route.ts and any unit/E2E tests or other routes
that rely on the same message; update code references to use the exported symbol
DELETED_ACCOUNT_MESSAGE and adjust imports in tests and route handlers so all
places consume the single canonical constant.

In `@src/components/AuthScreen.tsx`:
- Around line 152-164: The error display in the AuthScreen component should be
made accessible to screen readers by turning the error container into a live
region: update the error <div> used in AuthScreen to include role="alert" and
aria-live="assertive" (and optionally aria-atomic="true") so that API error
messages are announced immediately when the {error} state changes; locate the
error rendering block in AuthScreen and add these attributes to the div wrapping
{error}.

In `@src/lib/accountDeletion.test.ts`:
- Around line 76-89: Add assertions that the insert occurs before the delete by
checking the mocks' invocation order: after importing deleteUserAccount and
calling it, assert that txInsert.mock.invocationCallOrder[0] (or txInsertValues
if you prefer) is less than txDelete.mock.invocationCallOrder[0] (and/or
txDeleteWhere) to enforce sequencing; reference the test's deleteUserAccount and
getAccountDeletionEmailHash, and the mocks txInsert, txInsertValues, txDelete,
and txDeleteWhere when adding these order checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b6facee7-a0d2-4cf4-a097-55c36992e1d6

📥 Commits

Reviewing files that changed from the base of the PR and between 9a42f11 and 35b11a9.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • drizzle/account_deletion_log_incremental.sql
  • e2e/auth/login.spec.ts
  • package.json
  • src/app/api/auth/login/route.test.ts
  • src/app/api/auth/login/route.ts
  • src/components/AuthScreen.tsx
  • src/db/schema.ts
  • src/lib/accountDeletion.test.ts
  • src/lib/accountDeletion.ts

Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
src/lib/accountDeletion.test.ts (2)

76-92: Consider asserting delete predicate target user ID.

You already check operation order; adding a predicate assertion would guard against accidental broad deletes.

Suggested assertion addition
     expect(txDelete).toHaveBeenCalled();
-    expect(txDeleteWhere).toHaveBeenCalled();
+    expect(txDeleteWhere).toHaveBeenCalledWith({
+      left: "userId",
+      right: "user-1",
+    });
     expect(txInsertValues.mock.invocationCallOrder[0]).toBeLessThan(
       txDeleteWhere.mock.invocationCallOrder[0],
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/accountDeletion.test.ts` around lines 76 - 92, Add an assertion that
the delete predicate targets the intended user id to prevent accidental broad
deletes: after calling deleteUserAccount in the test, assert that txDeleteWhere
was called with a predicate (or args) that includes/filters for "user-1" (use
the same shape your code uses for predicates in txDeleteWhere) and keep the
existing order check; reference deleteUserAccount, txDeleteWhere, txInsertValues
and getAccountDeletionEmailHash to locate where to add the new expectation.

65-74: Tighten lookup assertions to reduce false positives.

This test should also assert the query targets the deletion-log table and applies limit(1).

Suggested test hardening
   await expect(wasAccountDeleted(" Deleted@Example.com ")).resolves.toBe(true);
+  expect(selectFrom).toHaveBeenCalledWith(
+    expect.objectContaining({ emailHash: "emailHash" }),
+  );
+  expect(selectLimit).toHaveBeenCalledWith(1);
   expect(selectWhere).toHaveBeenCalledWith({
     left: "emailHash",
     right: getAccountDeletionEmailHash("Deleted@Example.com"),
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/accountDeletion.test.ts` around lines 65 - 74, The test "finds
deletion log entries by normalized email hash" needs stronger assertions: after
calling wasAccountDeleted(" Deleted@Example.com "), assert that selectWhere was
invoked with the deletion log table (e.g., include table: "deletion-log"
alongside left: "emailHash" and right:
getAccountDeletionEmailHash("Deleted@Example.com")), and assert that the query
applied a limit of 1 by checking selectLimit was called with 1 (or that limit(1)
was applied). Update the assertions around selectWhere and selectLimit in this
test to include those checks using the existing getAccountDeletionEmailHash and
wasAccountDeleted references.
src/app/api/auth/login/route.test.ts (1)

54-104: Add explicit “no auth side effects” assertions for failure responses.

Recommend asserting createToken and setAuthCookie are not called in these error-path tests.

Suggested assertions
   await expect(response.json()).resolves.toEqual({ error: "Invalid credentials" });
   expect(response.status).toBe(401);
   expect(wasAccountDeleted).toHaveBeenCalledWith("missing@example.com");
   expect(verifyPassword).toHaveBeenCalledWith("password123", expect.stringMatching(/^\$2b\$12\$/));
+  expect(createToken).not.toHaveBeenCalled();
+  expect(setAuthCookie).not.toHaveBeenCalled();
@@
   await expect(response.json()).resolves.toEqual({
     error: DELETED_ACCOUNT_MESSAGE,
   });
   expect(response.status).toBe(410);
   expect(wasAccountDeleted).toHaveBeenCalledWith("deleted@example.com");
+  expect(createToken).not.toHaveBeenCalled();
+  expect(setAuthCookie).not.toHaveBeenCalled();
@@
   await expect(response.json()).resolves.toEqual({ error: "Invalid credentials" });
   expect(response.status).toBe(401);
   expect(wasAccountDeleted).toHaveBeenCalledWith("user@example.com");
   expect(verifyPassword).toHaveBeenCalledWith("bad-password", "hash");
+  expect(createToken).not.toHaveBeenCalled();
+  expect(setAuthCookie).not.toHaveBeenCalled();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/api/auth/login/route.test.ts` around lines 54 - 104, Add explicit
assertions in the error-path tests to ensure no authentication side effects
occur: in the three tests (the "keeps invalid credentials for unknown emails
without a deletion log", "returns a deleted-account message when the deletion
log matches", and "does not expose account existence when a password is wrong"
tests) assert that the mocked createToken and setAuthCookie functions were not
called (e.g., expect(createToken).not.toHaveBeenCalled() and
expect(setAuthCookie).not.toHaveBeenCalled()). Place these assertions after the
existing response assertions so they run for POST from "./route" and use the
existing mocked names createToken and setAuthCookie.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/app/api/auth/login/route.test.ts`:
- Around line 54-104: Add explicit assertions in the error-path tests to ensure
no authentication side effects occur: in the three tests (the "keeps invalid
credentials for unknown emails without a deletion log", "returns a
deleted-account message when the deletion log matches", and "does not expose
account existence when a password is wrong" tests) assert that the mocked
createToken and setAuthCookie functions were not called (e.g.,
expect(createToken).not.toHaveBeenCalled() and
expect(setAuthCookie).not.toHaveBeenCalled()). Place these assertions after the
existing response assertions so they run for POST from "./route" and use the
existing mocked names createToken and setAuthCookie.

In `@src/lib/accountDeletion.test.ts`:
- Around line 76-92: Add an assertion that the delete predicate targets the
intended user id to prevent accidental broad deletes: after calling
deleteUserAccount in the test, assert that txDeleteWhere was called with a
predicate (or args) that includes/filters for "user-1" (use the same shape your
code uses for predicates in txDeleteWhere) and keep the existing order check;
reference deleteUserAccount, txDeleteWhere, txInsertValues and
getAccountDeletionEmailHash to locate where to add the new expectation.
- Around line 65-74: The test "finds deletion log entries by normalized email
hash" needs stronger assertions: after calling wasAccountDeleted("
Deleted@Example.com "), assert that selectWhere was invoked with the deletion
log table (e.g., include table: "deletion-log" alongside left: "emailHash" and
right: getAccountDeletionEmailHash("Deleted@Example.com")), and assert that the
query applied a limit of 1 by checking selectLimit was called with 1 (or that
limit(1) was applied). Update the assertions around selectWhere and selectLimit
in this test to include those checks using the existing
getAccountDeletionEmailHash and wasAccountDeleted references.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2eb343dd-cd46-41e2-8991-033d62f933f1

📥 Commits

Reviewing files that changed from the base of the PR and between 35b11a9 and aedbbae.

📒 Files selected for processing (6)
  • e2e/auth/login.spec.ts
  • src/app/api/auth/login/route.test.ts
  • src/app/api/auth/login/route.ts
  • src/components/AuthScreen.tsx
  • src/lib/accountDeletion.test.ts
  • src/lib/authErrors.ts
✅ Files skipped from review due to trivial changes (1)
  • src/lib/authErrors.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • e2e/auth/login.spec.ts
  • src/app/api/auth/login/route.ts
  • src/components/AuthScreen.tsx

Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/lib/accountDeletion.test.ts (2)

4-21: Consider extracting the repeated select-chain mock builder.

Line 4 through Line 21 repeat near-identical query-chain scaffolding for db and tx. A small factory would reduce maintenance cost when query shape evolves.

♻️ Suggested refactor
-const selectLimit = vi.fn();
-const selectWhere = vi.fn(() => ({ limit: selectLimit }));
-const selectFrom = vi.fn(() => ({ where: selectWhere }));
-const dbSelect = vi.fn(() => ({ from: selectFrom }));
-const txSelectLimit = vi.fn();
-const txSelectWhere = vi.fn(() => ({ limit: txSelectLimit }));
-const txSelectFrom = vi.fn(() => ({ where: txSelectWhere }));
-const txSelect = vi.fn(() => ({ from: txSelectFrom }));
+const makeSelectChain = () => {
+  const limit = vi.fn();
+  const where = vi.fn(() => ({ limit }));
+  const from = vi.fn(() => ({ where }));
+  const select = vi.fn(() => ({ from }));
+  return { select, from, where, limit };
+};
+
+const dbChain = makeSelectChain();
+const txChain = makeSelectChain();
+
+const dbSelect = dbChain.select;
+const selectFrom = dbChain.from;
+const selectWhere = dbChain.where;
+const selectLimit = dbChain.limit;
+
+const txSelect = txChain.select;
+const txSelectFrom = txChain.from;
+const txSelectWhere = txChain.where;
+const txSelectLimit = txChain.limit;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/accountDeletion.test.ts` around lines 4 - 21, The test repeats an
identical query-chain mock for db and tx (selectLimit, selectWhere, selectFrom,
dbSelect and txSelect, txSelectFrom, txSelectWhere, etc.); extract a small
factory function (e.g., makeSelectChain or createQueryChainMock) that returns
the chain objects and their jest/vi spies for limit/where/from and use it to
build both dbSelect and txSelect as well as any insert/delete chains (txInsert,
txDelete) to remove duplication and keep the test DRY.

80-99: Good sequencing check; add one failure-path transaction test.

Line 80 through Line 99 correctly verifies insert-before-delete ordering. Consider adding one test where txInsertValues (or txDeleteWhere) rejects, to ensure errors propagate and are not swallowed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/accountDeletion.test.ts` around lines 80 - 99, Add a new test in
src/lib/accountDeletion.test.ts that simulates a failure in the transaction path
(e.g., have txInsertValues.mockRejectedValueOnce(new Error("boom")) or
txDeleteWhere.mockRejectedValueOnce(...)) and assert that
deleteUserAccount("user-1") rejects with that error and that the other
transaction call (txDelete or txInsert respectively) is not invoked after the
failing step; reference the existing helpers/exports deleteUserAccount,
getAccountDeletionEmailHash, txInsertValues, txInsert, txDeleteWhere and
txDelete to locate where to hook the mocks and assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/accountDeletion.test.ts`:
- Around line 4-21: The test repeats an identical query-chain mock for db and tx
(selectLimit, selectWhere, selectFrom, dbSelect and txSelect, txSelectFrom,
txSelectWhere, etc.); extract a small factory function (e.g., makeSelectChain or
createQueryChainMock) that returns the chain objects and their jest/vi spies for
limit/where/from and use it to build both dbSelect and txSelect as well as any
insert/delete chains (txInsert, txDelete) to remove duplication and keep the
test DRY.
- Around line 80-99: Add a new test in src/lib/accountDeletion.test.ts that
simulates a failure in the transaction path (e.g., have
txInsertValues.mockRejectedValueOnce(new Error("boom")) or
txDeleteWhere.mockRejectedValueOnce(...)) and assert that
deleteUserAccount("user-1") rejects with that error and that the other
transaction call (txDelete or txInsert respectively) is not invoked after the
failing step; reference the existing helpers/exports deleteUserAccount,
getAccountDeletionEmailHash, txInsertValues, txInsert, txDeleteWhere and
txDelete to locate where to hook the mocks and assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cb5849b3-a484-44d5-9c04-dd9151773932

📥 Commits

Reviewing files that changed from the base of the PR and between aedbbae and 88c60d3.

📒 Files selected for processing (2)
  • src/app/api/auth/login/route.test.ts
  • src/lib/accountDeletion.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/api/auth/login/route.test.ts

Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants