Enhance auth flows and improve e2e test reliability
- Remove redundant `'use client'` directives in auth pages to streamline code. - Refine Playwright config: adjust worker limits and add video recording for failed tests. - Improve session management in e2e tests with isolated state clearing, console log collection, and detailed failure attachments. - Update API client: better handle auth routes, ensure safe token refresh, and prevent unnecessary redirects.
This commit is contained in:
@@ -95,17 +95,18 @@ async function refreshAccessToken(): Promise<string> {
|
||||
console.error('[API Client] Token refresh failed:', error);
|
||||
}
|
||||
|
||||
// Clear auth and redirect to login
|
||||
// Clear auth state
|
||||
const authStore = await getAuthStore();
|
||||
await authStore.clearAuth();
|
||||
|
||||
// Redirect to login if we're in browser
|
||||
// Only redirect to login when not already on an auth route
|
||||
if (typeof window !== 'undefined') {
|
||||
const currentPath = window.location.pathname;
|
||||
const returnUrl = currentPath !== '/login' && currentPath !== '/register'
|
||||
? `?returnUrl=${encodeURIComponent(currentPath)}`
|
||||
: '';
|
||||
window.location.href = `/login${returnUrl}`;
|
||||
const onAuthRoute = currentPath === '/login' || currentPath === '/register' || currentPath.startsWith('/password-reset');
|
||||
if (!onAuthRoute) {
|
||||
const returnUrl = currentPath ? `?returnUrl=${encodeURIComponent(currentPath)}` : '';
|
||||
window.location.href = `/login${returnUrl}`;
|
||||
}
|
||||
}
|
||||
|
||||
throw error;
|
||||
@@ -129,8 +130,12 @@ client.instance.interceptors.request.use(
|
||||
const authStore = await getAuthStore();
|
||||
const { accessToken } = authStore;
|
||||
|
||||
// Add Authorization header if token exists
|
||||
if (accessToken && requestConfig.headers) {
|
||||
// Do not attach Authorization header for auth endpoints
|
||||
const url = requestConfig.url || '';
|
||||
const isAuthEndpoint = url.includes('/auth/login') || url.includes('/auth/register') || url.includes('/auth/refresh') || url.includes('/auth/password') || url.includes('/password');
|
||||
|
||||
// Add Authorization header if token exists and not hitting auth endpoints
|
||||
if (accessToken && requestConfig.headers && !isAuthEndpoint) {
|
||||
requestConfig.headers.Authorization = `Bearer ${accessToken}`;
|
||||
}
|
||||
|
||||
@@ -170,13 +175,27 @@ client.instance.interceptors.response.use(
|
||||
|
||||
// Handle 401 Unauthorized - Token expired
|
||||
if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
|
||||
const url = originalRequest.url || '';
|
||||
const isAuthEndpoint = url.includes('/auth/login') || url.includes('/auth/register') || url.includes('/auth/password') || url.includes('/password');
|
||||
|
||||
// If the 401 is from auth endpoints, do not attempt refresh
|
||||
if (isAuthEndpoint) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
// If refresh endpoint itself fails with 401, clear auth and reject
|
||||
if (originalRequest.url?.includes('/auth/refresh')) {
|
||||
if (url.includes('/auth/refresh')) {
|
||||
const authStore = await getAuthStore();
|
||||
await authStore.clearAuth();
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
// Ensure we have a refresh token before attempting refresh
|
||||
const authStore = await getAuthStore();
|
||||
if (!authStore.refreshToken) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
originalRequest._retry = true;
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user