Override MSW handlers to support custom authentication workflows

- Added mock handlers for `login`, `register`, and `refresh` endpoints with realistic network delay.
- Implemented JWT token generation utilities to simulate authentication flows.
- Enhanced handler configurations for user data validation and session management.
This commit is contained in:
Felipe Cardoso
2025-11-24 20:23:15 +01:00
parent cda9810a7e
commit 3bf28aa121
2 changed files with 106 additions and 12 deletions

View File

@@ -12,8 +12,11 @@
*/
import { http, HttpResponse, delay } from 'msw';
import { generateMockToken } from '../utils/tokens';
import { validateCredentials, setCurrentUser, currentUser } from '../data/users';
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8000';
const NETWORK_DELAY = 300; // ms - simulate realistic network delay
/**
* Custom handler overrides
@@ -22,17 +25,80 @@ const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8
* Add custom implementations here as needed.
*/
export const overrideHandlers = [
// Example: Custom error simulation for testing
// http.post(`${API_BASE_URL}/api/v1/auth/login`, async ({ request }) => {
// // Simulate rate limiting 10% of the time
// if (Math.random() < 0.1) {
// return HttpResponse.json(
// { detail: 'Too many login attempts' },
// { status: 429 }
// );
// }
// // Otherwise, use generated handler (by not returning anything)
// }),
/**
* Login Override
* Custom handler to return proper JWT tokens and user data
*/
http.post(`${API_BASE_URL}/api/v1/auth/login`, async ({ request }) => {
await delay(NETWORK_DELAY);
// Add your custom handlers here...
const body = (await request.json()) as any;
const user = validateCredentials(body.email, body.password);
if (!user) {
return HttpResponse.json({ detail: 'Incorrect email or password' }, { status: 401 });
}
setCurrentUser(user);
return HttpResponse.json({
access_token: generateMockToken('access', user.id),
refresh_token: generateMockToken('refresh', user.id),
token_type: 'bearer',
expires_in: 900,
user: user,
});
}),
/**
* Register Override
* Custom handler to return proper JWT tokens and user data
*/
http.post(`${API_BASE_URL}/api/v1/auth/register`, async ({ request }) => {
await delay(NETWORK_DELAY);
const body = (await request.json()) as any;
const newUser = {
id: `new-user-${Date.now()}`,
email: body.email,
first_name: body.first_name,
last_name: body.last_name || null,
phone_number: body.phone_number || null,
is_active: true,
is_superuser: false,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
last_login: null,
organization_count: 0,
};
setCurrentUser(newUser);
return HttpResponse.json({
user: newUser,
access_token: generateMockToken('access', newUser.id),
refresh_token: generateMockToken('refresh', newUser.id),
token_type: 'bearer',
expires_in: 900,
});
}),
/**
* Refresh Token Override
* Custom handler to return proper JWT tokens
*/
http.post(`${API_BASE_URL}/api/v1/auth/refresh`, async ({ request }) => {
await delay(NETWORK_DELAY);
// Use current user's ID if available, otherwise generate a generic token
const userId = currentUser?.id || 'refreshed-user';
return HttpResponse.json({
access_token: generateMockToken('access', userId),
refresh_token: generateMockToken('refresh', userId),
token_type: 'bearer',
expires_in: 900,
});
}),
];

View File

@@ -0,0 +1,28 @@
/**
* MSW Token Generation Utilities
*
* Helper functions for generating mock JWT tokens in demo mode.
* Tokens follow proper JWT format to pass client-side validation.
*/
/**
* Generate a mock JWT-like token for demo mode
* Format: header.payload.signature (3 parts separated by dots)
*
* @param type - Token type ('access' or 'refresh')
* @param userId - User ID to include in the token payload
* @returns JWT-formatted token string
*/
export function generateMockToken(type: 'access' | 'refresh', userId: string): string {
const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
const payload = btoa(
JSON.stringify({
sub: userId,
type: type,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (type === 'access' ? 900 : 2592000),
})
);
const signature = btoa(`demo-${type}-${userId}-${Date.now()}`);
return `${header}.${payload}.${signature}`;
}