feat(auth): enhance registration and login processes with detailed logging and error handling#78
Conversation
…gging and error handling
WalkthroughThis update introduces extensive logging and error handling improvements across authentication and user-related backend services. It also adds new and expanded integration and unit tests for user registration and wallet creation, including atomic transaction scenarios. Several helper utilities and mock modules are introduced to facilitate testing, and minor formatting and response structure adjustments are made in existing tests. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant AuthController
participant UserService
participant WalletService
participant EmailNotifier
participant Logger
participant DB
Client->>AuthController: POST /register
AuthController->>Logger: Log validation steps
AuthController->>UserService: registerUser()
UserService->>Logger: Log registration start
UserService->>DB: Begin transaction
UserService->>DB: Create user
UserService->>WalletService: createWalletInTransaction()
WalletService->>Logger: Log wallet creation
WalletService->>DB: Create wallet
WalletService->>Logger: Log wallet creation success/failure
UserService->>DB: Commit/Rollback transaction
UserService->>Logger: Log registration success/failure
UserService-->>AuthController: Result
AuthController->>Logger: Log response
AuthController->>EmailNotifier: Send activation email
EmailNotifier->>Logger: Log email send attempt/result
AuthController-->>Client: Registration response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🔭 Outside diff range comments (2)
backend/test-wallet-service.js (1)
1-43: Move to proper test infrastructure and use standard testing patterns.This verification script should be relocated to the tests directory and converted to use the project's testing framework instead of console.log statements. Consider integrating with the existing test suites in
backend/tests/directory.-// Simple test to verify the WalletService implementation -const { PrismaClient } = require("@prisma/client"); - -// Mock the WalletService to test the method signature -class WalletService { - static async createWallet(userId, walletAddress) { - console.log("Original createWallet method called"); - return { id: "wallet-1", userId, walletAddress, isVerified: false }; - } - - static async createWalletInTransaction(tx, userId, walletAddress) { - console.log("New createWalletInTransaction method called"); - // Simulate transaction-aware wallet creation - return { id: "wallet-2", userId, walletAddress, isVerified: false }; - } -}Move this to
backend/tests/__mocks__/WalletService.tsand integrate with the existing test infrastructure that already includes comprehensive wallet service testing.backend/test-error-handling.js (1)
1-106: Comprehensive error testing - integrate with proper test framework.This file provides excellent coverage of error handling scenarios including unique constraints, connection errors, validation errors, and email notification failures. However, it should be moved to the tests directory and integrated with the existing test framework.
Consider integrating these error scenarios into the existing test suites in
backend/tests/integration/andbackend/tests/unit/directories that already cover similar error handling patterns. The mock logger approach is valuable and could be reused across the test suite.The error scenarios tested here align well with the error handling implemented in the service layer changes.
♻️ Duplicate comments (1)
backend/tests/integration/user.service.atomic.integration.test.ts (1)
249-298: Consider removing duplicate test or differentiating test scenariosThis test appears to duplicate the "Transaction Rollback on User Creation Failure" test (lines 137-191). Consider either removing this test or modifying it to test a different error handling scenario.
🧹 Nitpick comments (9)
backend/tests/unit/user.service.atomic.unit.test.ts (2)
1-3: Remove basic placeholder testThis basic arithmetic test doesn't belong in a unit test file for UserService atomic operations.
-test("should pass basic test", () => { - expect(1 + 1).toBe(2); -}); -
13-13: Use the wallet address utility for consistencyReplace the hardcoded wallet address with the utility function to maintain consistency with other tests.
- walletAddress: "GCKFBEIYTKP6RCZNVPH73XL7XFWTEOYVTZMHSTGJ5THPGWWTNP5TPBUJ", + walletAddress: generateUniqueWalletAddress(),Don't forget to import the utility:
import { generateUniqueWalletAddress } from '../helpers/testUtils';backend/tests/integration/user.service.atomic.integration.test.ts (5)
7-8: Consider using a singleton pattern or test-specific Prisma instanceCreating a Prisma client at the module level can lead to connection pool issues when running tests in parallel. Consider using a singleton pattern or creating the client within
beforeAll.-// Create a Prisma client for testing -const prisma = new PrismaClient(); +let prisma: PrismaClient;Then initialize in
beforeAll:beforeAll(async () => { + prisma = new PrismaClient(); // Ensure database connection is working await prisma.$connect(); });
30-35: Extract hardcoded wallet addresses to constantsThe hardcoded wallet addresses should be extracted to constants at the top of the file for better maintainability.
+const TEST_WALLET_ADDRESSES = { + WALLET_1: "GCKFBEIYTKP6RCZNVPH73XL7XFWTEOYVTZMHSTGJ5THPGWWTNP5TPBUJ", + WALLET_2: "GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOKY3B2WSQHG4W37", +}; + describe("UserService - Atomic Registration Integration Tests", () => {Then use in cleanup:
- in: [ - "GCKFBEIYTKP6RCZNVPH73XL7XFWTEOYVTZMHSTGJ5THPGWWTNP5TPBUJ", - "GDQP2KPQGKIHYJGXNUIYOMHARUARCA7DJT5FO2FFOOKY3B2WSQHG4W37", - ], + in: Object.values(TEST_WALLET_ADDRESSES),
37-39: Consider logging cleanup errors instead of silently ignoring themSilently ignoring cleanup errors could hide database issues. Consider at least logging them for debugging purposes.
} catch (error) { - // Ignore cleanup errors + // Log cleanup errors for debugging but don't fail the test + console.warn('Cleanup error in beforeEach:', error); }Also applies to: 46-48, 81-83
172-177: Combine duplicate assertions for cleaner test codeThe duplicate
expectstatements can be combined into a single assertion that checks both the error type and message.- await expect(UserService.registerUser(duplicateUserData)).rejects.toThrow( - InternalError - ); - await expect(UserService.registerUser(duplicateUserData)).rejects.toThrow( - "Email address is already registered" - ); + await expect(UserService.registerUser(duplicateUserData)).rejects.toThrow( + new InternalError("Email address is already registered") + );Also applies to: 227-232
379-385: Use Jest's expect instead of manual fail()Replace the manual
fail()call with Jest'sexpect().rejectspattern for consistency.- // Attempt registration (should fail) - try { - await UserService.registerUser(failingUserData); - fail("Expected registration to fail due to duplicate wallet address"); - } catch (error) { - // Expected to fail - } + // Attempt registration (should fail) + await expect( + UserService.registerUser(failingUserData) + ).rejects.toThrow(InternalError);backend/tests/integration/auth.registration.integration.test.ts (2)
17-18: Remove unnecessary wrapper functionThe
generateValidWalletAddressfunction is just an alias forgenerateUniqueWalletAddress. Use the imported function directly.-// Helper function to generate valid Stellar wallet addresses (use the shared helper) -const generateValidWalletAddress = generateUniqueWalletAddress;Then update all usages to use
generateUniqueWalletAddressdirectly.
329-331: Improve type safety by avoidingas anyassertionThe type assertion bypasses TypeScript's type safety. Consider proper type narrowing instead.
- if (successfulResponses.length > 0) { - const successResponse = successfulResponses[0] as any; - createdUserIds.push(successResponse.value.body.data.user.id); + if (successfulResponses.length > 0 && successfulResponses[0].status === 'fulfilled') { + const successResponse = successfulResponses[0]; + createdUserIds.push(successResponse.value.body.data.user.id);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
backend/prisma/migrations/migration_lock.toml(1 hunks)backend/src/controllers/auth.controller.ts(2 hunks)backend/src/services/user.service.ts(3 hunks)backend/src/services/wallet.service.ts(5 hunks)backend/test-error-handling.js(1 hunks)backend/test-wallet-service.js(1 hunks)backend/tests/__mocks__/nodemailer.ts(1 hunks)backend/tests/e2e/auth.test.ts(6 hunks)backend/tests/helpers/testUtils.ts(1 hunks)backend/tests/integration/auth.registration.integration.test.ts(1 hunks)backend/tests/integration/user.service.atomic.integration.test.ts(1 hunks)backend/tests/unit/user.service.atomic.unit.test.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
backend/src/services/wallet.service.ts (1)
backend/src/core/api/ApiError.ts (1)
InternalError(71-75)
backend/tests/e2e/auth.test.ts (1)
backend/tests/helpers/testUtils.ts (1)
generateUniqueWalletAddress(6-9)
backend/tests/integration/user.service.atomic.integration.test.ts (1)
backend/src/core/api/ApiError.ts (1)
InternalError(71-75)
backend/src/services/user.service.ts (1)
backend/src/core/api/ApiError.ts (1)
InternalError(71-75)
🔇 Additional comments (21)
backend/prisma/migrations/migration_lock.toml (1)
4-4: LGTM: Good formatting practiceAdding a trailing newline is a standard best practice for text files and improves consistency across the codebase.
backend/tests/__mocks__/nodemailer.ts (1)
1-7: LGTM: Well-structured nodemailer mockThe mock implementation correctly simulates the nodemailer API with appropriate Jest functions. The fixed
messageIdreturn value ensures deterministic test behavior, and the export structure supports both named and default imports.backend/tests/helpers/testUtils.ts (1)
1-16: LGTM: Excellent utility functions for test data generationThe implementation is well-designed with:
- Proper use of Stellar SDK for generating valid addresses
- Clear, documented functions that promote test data uniqueness
- Clean array generation pattern for multiple addresses
- Good JSDoc documentation
These utilities will improve test reliability by ensuring unique wallet addresses across test runs.
backend/tests/e2e/auth.test.ts (3)
14-14: LGTM: Proper import of test utilityGood addition of the test utility import to support unique wallet address generation.
78-78: LGTM: Improved test data uniquenessUsing
generateUniqueWalletAddress()instead of static addresses significantly improves test isolation and reliability by ensuring each test run uses fresh, unique wallet addresses.Also applies to: 116-116, 146-146
102-103: API response format matchesdata.userstructure
Theauth.controller.tsendpoints wrap user payloads under a{ user: userResponse }object (and includetokenfor login), so the E2E assertions againstresponse.body.data.user(and the absence ofpassword) are correct. No changes required.
Controllers:
- Registration:
new SuccessResponse(..., { user: userResponse })- Login:
new SuccessResponse(..., { user: userResponse, token })Tests:
backend/tests/e2e/auth.test.tslines 102–103 verifydata.userand omitpasswordas intended.backend/src/services/wallet.service.ts (4)
1-1: LGTM: Import statements correctly added.The logger import is necessary for the enhanced logging functionality throughout the service.
Also applies to: 3-3
22-58: Excellent transactional wallet creation implementation.The method correctly accepts a Prisma transaction client and implements comprehensive logging with structured metadata. The error handling properly re-throws errors to trigger transaction rollback, which is essential for maintaining data consistency.
71-71: LGTM: Comprehensive logging added for wallet challenge operations.The logging provides good observability with appropriate levels (info for operations, error for failures) and includes structured metadata for debugging.
Also applies to: 91-104
136-136: Excellent error handling and logging improvements.The specific handling for "Record to update not found" errors provides better user experience, while the comprehensive logging with structured metadata improves debugging capabilities.
Also applies to: 144-164
backend/src/services/user.service.ts (4)
3-4: LGTM: Necessary imports for enhanced functionality.The WalletService import enables atomic user and wallet creation, while the logger import supports the comprehensive logging enhancements.
19-50: Excellent atomic registration implementation with comprehensive logging.The integration with
WalletService.createWalletInTransactionensures atomic user and wallet creation, while the detailed logging provides excellent traceability throughout the registration process.
55-110: Outstanding comprehensive error handling implementation.The error categorization is thorough, covering unique constraint violations, connection issues, and validation errors. Each error type has appropriate logging levels and user-friendly messages, while detailed error information is logged for debugging purposes.
114-143: LGTM: Consistent error handling and logging enhancements.The email activation method follows the same excellent pattern as the registration method, with comprehensive logging and specific error handling for non-existent users.
backend/src/controllers/auth.controller.ts (4)
1-12: LGTM: Complete import statements for enhanced functionality.All necessary imports are present including the logger for comprehensive logging throughout the authentication flow.
17-119: Excellent registration implementation with atomic transaction handling.The nested try-catch pattern for email notifications is particularly well-designed - it ensures registration success isn't affected by email delivery failures while still logging email errors for monitoring. The comprehensive logging provides excellent traceability throughout the registration flow.
125-161: LGTM: Comprehensive logging for email verification flow.The logging provides excellent traceability for verification attempts, token validation, and error scenarios while maintaining the existing functionality.
166-205: LGTM: Comprehensive login flow logging with audit trail.The detailed logging for different failure scenarios (non-existent user, unverified email, invalid credentials) provides excellent audit capabilities while maintaining security best practices.
backend/tests/integration/auth.registration.integration.test.ts (3)
126-288: Well-structured integration tests for registration flowExcellent test coverage for the registration flow including:
- API response validation
- Database state verification
- Email notification checks
- Referential integrity validation
- Bulk registration scenarios
519-572: Excellent error handling test for email service failuresGreat test coverage for the scenario where email service fails but registration should still succeed. The test properly verifies:
- Registration completes successfully
- User and wallet are created
- Email attempt is made
- Error is logged appropriately
This aligns well with the PR objective of enhancing error handling.
575-813: Comprehensive transaction rollback and data consistency testsExcellent coverage of transaction rollback scenarios including:
- Prevention of orphaned users and wallets
- Database consistency after failures
- Multiple concurrent failure attempts
These tests effectively validate the atomic nature of the registration process.
| describe("UserService - Atomic Registration Unit Tests", () => { | ||
| test("should successfully create user and wallet atomically", () => { | ||
| // This test verifies the atomic registration concept | ||
| const userData = { | ||
| email: "test@example.com", | ||
| hashedPassword: "hashedPassword123", | ||
| firstName: "John", | ||
| lastName: "Doe", | ||
| walletAddress: "GCKFBEIYTKP6RCZNVPH73XL7XFWTEOYVTZMHSTGJ5THPGWWTNP5TPBUJ", | ||
| }; | ||
|
|
||
| // Verify that the test data is properly structured for atomic operations | ||
| expect(userData.email).toBe("test@example.com"); | ||
| expect(userData.walletAddress).toBe( | ||
| "GCKFBEIYTKP6RCZNVPH73XL7XFWTEOYVTZMHSTGJ5THPGWWTNP5TPBUJ" | ||
| ); | ||
|
|
||
| // This test conceptually verifies that atomic registration should: | ||
| // 1. Create user and wallet in a single transaction | ||
| // 2. Ensure both operations succeed or both fail | ||
| // 3. Log appropriate success messages | ||
| expect(true).toBe(true); | ||
| }); | ||
|
|
||
| test("should rollback transaction when user creation fails due to duplicate email", () => { | ||
| // This test verifies the concept of transaction rollback on duplicate email | ||
| const duplicateEmailScenario = { | ||
| shouldRollback: true, | ||
| errorType: "duplicate_email", | ||
| expectedMessage: "Email address is already registered", | ||
| shouldLogError: true, | ||
| shouldLogWarning: true, | ||
| }; | ||
|
|
||
| expect(duplicateEmailScenario.shouldRollback).toBe(true); | ||
| expect(duplicateEmailScenario.errorType).toBe("duplicate_email"); | ||
| expect(duplicateEmailScenario.expectedMessage).toBe( | ||
| "Email address is already registered" | ||
| ); | ||
| expect(duplicateEmailScenario.shouldLogError).toBe(true); | ||
| expect(duplicateEmailScenario.shouldLogWarning).toBe(true); | ||
| }); | ||
|
|
||
| test("should rollback transaction when user creation fails due to database connection error", () => { | ||
| // This test verifies the concept of transaction rollback on connection error | ||
| const connectionErrorScenario = { | ||
| shouldRollback: true, | ||
| errorType: "connection_error", | ||
| expectedMessage: | ||
| "Service temporarily unavailable. Please try again later", | ||
| shouldLogError: true, | ||
| }; | ||
|
|
||
| expect(connectionErrorScenario.shouldRollback).toBe(true); | ||
| expect(connectionErrorScenario.errorType).toBe("connection_error"); | ||
| expect(connectionErrorScenario.expectedMessage).toBe( | ||
| "Service temporarily unavailable. Please try again later" | ||
| ); | ||
| expect(connectionErrorScenario.shouldLogError).toBe(true); | ||
| }); | ||
|
|
||
| test("should rollback transaction when user creation fails due to validation error", () => { | ||
| // This test verifies the concept of transaction rollback on validation error | ||
| const validationErrorScenario = { | ||
| shouldRollback: true, | ||
| errorType: "validation_error", | ||
| expectedMessage: "Invalid registration data provided", | ||
| shouldLogWarning: true, | ||
| }; | ||
|
|
||
| expect(validationErrorScenario.shouldRollback).toBe(true); | ||
| expect(validationErrorScenario.errorType).toBe("validation_error"); | ||
| expect(validationErrorScenario.expectedMessage).toBe( | ||
| "Invalid registration data provided" | ||
| ); | ||
| expect(validationErrorScenario.shouldLogWarning).toBe(true); | ||
| }); | ||
|
|
||
| test("should rollback user creation when wallet creation fails due to duplicate wallet address", () => { | ||
| // This test verifies the concept of transaction rollback on duplicate wallet | ||
| const duplicateWalletScenario = { | ||
| shouldRollbackUserCreation: true, | ||
| errorType: "duplicate_wallet", | ||
| expectedMessage: "Wallet address is already registered", | ||
| shouldLogError: true, | ||
| shouldLogWarning: true, | ||
| }; | ||
|
|
||
| expect(duplicateWalletScenario.shouldRollbackUserCreation).toBe(true); | ||
| expect(duplicateWalletScenario.errorType).toBe("duplicate_wallet"); | ||
| expect(duplicateWalletScenario.expectedMessage).toBe( | ||
| "Wallet address is already registered" | ||
| ); | ||
| expect(duplicateWalletScenario.shouldLogError).toBe(true); | ||
| expect(duplicateWalletScenario.shouldLogWarning).toBe(true); | ||
| }); | ||
|
|
||
| test("should rollback user creation when wallet creation fails due to internal error", () => { | ||
| // This test verifies the concept of transaction rollback on internal error | ||
| const internalErrorScenario = { | ||
| shouldRollbackUserCreation: true, | ||
| errorType: "internal_error", | ||
| expectedMessage: "Registration failed. Please try again", | ||
| shouldLogError: true, | ||
| }; | ||
|
|
||
| expect(internalErrorScenario.shouldRollbackUserCreation).toBe(true); | ||
| expect(internalErrorScenario.errorType).toBe("internal_error"); | ||
| expect(internalErrorScenario.expectedMessage).toBe( | ||
| "Registration failed. Please try again" | ||
| ); | ||
| expect(internalErrorScenario.shouldLogError).toBe(true); | ||
| }); | ||
|
|
||
| test("should log detailed error information for debugging", () => { | ||
| // This test verifies the concept of detailed error logging | ||
| const errorLoggingRequirements = { | ||
| shouldLogErrorMessage: true, | ||
| shouldLogStackTrace: true, | ||
| shouldLogUserData: true, | ||
| shouldUseErrorLogLevel: true, | ||
| shouldNotExposeInternalDetails: true, | ||
| }; | ||
|
|
||
| expect(errorLoggingRequirements.shouldLogErrorMessage).toBe(true); | ||
| expect(errorLoggingRequirements.shouldLogStackTrace).toBe(true); | ||
| expect(errorLoggingRequirements.shouldLogUserData).toBe(true); | ||
| expect(errorLoggingRequirements.shouldUseErrorLogLevel).toBe(true); | ||
| expect(errorLoggingRequirements.shouldNotExposeInternalDetails).toBe(true); | ||
| }); | ||
|
|
||
| test("should handle non-Error objects gracefully in logging", () => { | ||
| // This test verifies the concept of graceful error handling | ||
| const gracefulHandlingRequirements = { | ||
| shouldHandleNonErrorObjects: true, | ||
| shouldConvertToString: true, | ||
| shouldNotCrash: true, | ||
| shouldSetStackToUndefined: true, | ||
| }; | ||
|
|
||
| expect(gracefulHandlingRequirements.shouldHandleNonErrorObjects).toBe(true); | ||
| expect(gracefulHandlingRequirements.shouldConvertToString).toBe(true); | ||
| expect(gracefulHandlingRequirements.shouldNotCrash).toBe(true); | ||
| expect(gracefulHandlingRequirements.shouldSetStackToUndefined).toBe(true); | ||
| }); | ||
|
|
||
| test("should provide user-friendly error messages without exposing internal details", () => { | ||
| // This test verifies the concept of user-friendly error messages | ||
| const userFriendlyErrorRequirements = { | ||
| shouldHideInternalDetails: true, | ||
| shouldProvideGenericMessage: true, | ||
| shouldLogInternalDetailsForDebugging: true, | ||
| shouldThrowInternalError: true, | ||
| }; | ||
|
|
||
| expect(userFriendlyErrorRequirements.shouldHideInternalDetails).toBe(true); | ||
| expect(userFriendlyErrorRequirements.shouldProvideGenericMessage).toBe( | ||
| true | ||
| ); | ||
| expect( | ||
| userFriendlyErrorRequirements.shouldLogInternalDetailsForDebugging | ||
| ).toBe(true); | ||
| expect(userFriendlyErrorRequirements.shouldThrowInternalError).toBe(true); | ||
| }); | ||
|
|
||
| test("should log successful registration steps", () => { | ||
| // This test verifies the concept of logging successful operations | ||
| const successLoggingRequirements = { | ||
| shouldLogStartRegistration: true, | ||
| shouldLogUserCreation: true, | ||
| shouldLogWalletCreation: true, | ||
| shouldLogCompletionSuccess: true, | ||
| shouldUseInfoLogLevel: true, | ||
| shouldUseDebugLogLevel: true, | ||
| }; | ||
|
|
||
| expect(successLoggingRequirements.shouldLogStartRegistration).toBe(true); | ||
| expect(successLoggingRequirements.shouldLogUserCreation).toBe(true); | ||
| expect(successLoggingRequirements.shouldLogWalletCreation).toBe(true); | ||
| expect(successLoggingRequirements.shouldLogCompletionSuccess).toBe(true); | ||
| expect(successLoggingRequirements.shouldUseInfoLogLevel).toBe(true); | ||
| expect(successLoggingRequirements.shouldUseDebugLogLevel).toBe(true); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Replace conceptual tests with actual unit tests
These are conceptual tests that verify static data rather than testing actual UserService functionality. For effective unit testing of atomic registration, you need tests that:
- Mock dependencies (database, email service, etc.)
- Test actual method calls and their behavior
- Verify error handling with real error scenarios
- Test transaction rollback behavior
Consider implementing real unit tests like:
import UserService from '../../src/services/user.service';
import { PrismaClient } from '@prisma/client';
import { generateUniqueWalletAddress } from '../helpers/testUtils';
// Mock Prisma
jest.mock('@prisma/client');
const mockPrisma = {
$transaction: jest.fn(),
user: { create: jest.fn() },
wallet: { create: jest.fn() }
};
describe('UserService - Atomic Registration Unit Tests', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should create user and wallet atomically', async () => {
const userData = {
email: 'test@example.com',
hashedPassword: 'hashedPassword123',
firstName: 'John',
lastName: 'Doe',
walletAddress: generateUniqueWalletAddress(),
};
mockPrisma.$transaction.mockResolvedValue([mockUser, mockWallet]);
const result = await UserService.registerUser(userData);
expect(mockPrisma.$transaction).toHaveBeenCalledTimes(1);
expect(result).toBeDefined();
});
// Add more real unit tests...
});🤖 Prompt for AI Agents
In backend/tests/unit/user.service.atomic.unit.test.ts from lines 5 to 188, the
current tests are conceptual and only verify static data instead of actual
UserService functionality. Replace these with real unit tests that mock
dependencies like the database and test actual method calls, including success
and error scenarios. Use Jest to mock Prisma client methods such as
$transaction, user.create, and wallet.create, then write tests that call
UserService.registerUser with realistic data, verify transaction behavior, and
assert proper error handling and rollback. Ensure to clear mocks before each
test and cover both successful and failure cases for atomic registration.
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Chores