diff --git a/src/web/src/features/auth/api/authApi.ts b/src/web/src/features/auth/api/authApi.ts index 81be6c1..0b7fe43 100644 --- a/src/web/src/features/auth/api/authApi.ts +++ b/src/web/src/features/auth/api/authApi.ts @@ -12,6 +12,22 @@ export interface LoginResponseDto { } } +export interface RefreshRequest { + accessToken: string + refreshToken: string +} + +export interface RefreshResponse { + accessToken: string + refreshToken: string + expiresIn: number +} + +export interface LogoutResponse { + success: boolean + mensaje: string +} + export async function login(username: string, password: string): Promise { const response = await axiosClient.post('/api/v1/auth/login', { username, @@ -19,3 +35,13 @@ export async function login(username: string, password: string): Promise { + const response = await axiosClient.post('/api/v1/auth/refresh', payload) + return response.data +} + +export async function logout(): Promise { + const response = await axiosClient.post('/api/v1/auth/logout', {}) + return response.data +} diff --git a/src/web/src/tests/features/auth/authApi.test.ts b/src/web/src/tests/features/auth/authApi.test.ts index cc650c9..fb4780c 100644 --- a/src/web/src/tests/features/auth/authApi.test.ts +++ b/src/web/src/tests/features/auth/authApi.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest' import { http, HttpResponse } from 'msw' import { setupServer } from 'msw/node' -import { login } from '../../../features/auth/api/authApi' +import { login, refresh, logout } from '../../../features/auth/api/authApi' const API_URL = 'http://localhost:5000' @@ -17,6 +17,17 @@ const mockLoginResponse = { }, } +const mockRefreshResponse = { + accessToken: 'eyJhbGciOiJSUzI1NiJ9.new-payload.new-sig', + refreshToken: 'new-opaque-refresh-token-xyz', + expiresIn: 3600, +} + +const mockLogoutResponse = { + success: true, + mensaje: 'Sesion cerrada correctamente', +} + const server = setupServer( http.post(`${API_URL}/api/v1/auth/login`, async ({ request }) => { const body = await request.json() as { username: string; password: string } @@ -25,6 +36,18 @@ const server = setupServer( } return HttpResponse.json({ error: 'Credenciales inválidas' }, { status: 401 }) }), + + http.post(`${API_URL}/api/v1/auth/refresh`, async ({ request }) => { + const body = await request.json() as { accessToken: string; refreshToken: string } + if (body.accessToken && body.refreshToken) { + return HttpResponse.json(mockRefreshResponse, { status: 200 }) + } + return HttpResponse.json({ error: 'invalid_token' }, { status: 401 }) + }), + + http.post(`${API_URL}/api/v1/auth/logout`, async () => { + return HttpResponse.json(mockLogoutResponse, { status: 200 }) + }), ) beforeAll(() => server.listen({ onUnhandledRequest: 'error' })) @@ -45,3 +68,60 @@ describe('login()', () => { await expect(login('admin', 'wrongpassword')).rejects.toThrow() }) }) + +describe('refresh()', () => { + it('refresh_callsCorrectEndpoint_withPayload', async () => { + let capturedBody: unknown = null + server.use( + http.post(`${API_URL}/api/v1/auth/refresh`, async ({ request }) => { + capturedBody = await request.json() + return HttpResponse.json(mockRefreshResponse, { status: 200 }) + }), + ) + + const payload = { + accessToken: 'old-access-token', + refreshToken: 'old-refresh-token', + } + const result = await refresh(payload) + + expect(result.accessToken).toBe(mockRefreshResponse.accessToken) + expect(result.refreshToken).toBe(mockRefreshResponse.refreshToken) + expect(result.expiresIn).toBe(3600) + expect(capturedBody).toEqual(payload) + }) + + it('throws on invalid refresh token (401)', async () => { + server.use( + http.post(`${API_URL}/api/v1/auth/refresh`, () => { + return HttpResponse.json({ error: 'invalid_token' }, { status: 401 }) + }), + ) + + await expect( + refresh({ accessToken: 'bad-access', refreshToken: 'bad-refresh' }), + ).rejects.toThrow() + }) +}) + +describe('logout()', () => { + it('logout_callsCorrectEndpoint', async () => { + let requestUrl: string | null = null + let requestMethod: string | null = null + + server.use( + http.post(`${API_URL}/api/v1/auth/logout`, ({ request }) => { + requestUrl = request.url + requestMethod = request.method + return HttpResponse.json(mockLogoutResponse, { status: 200 }) + }), + ) + + const result = await logout() + + expect(result.success).toBe(true) + expect(result.mensaje).toBe('Sesion cerrada correctamente') + expect(requestUrl).toContain('/api/v1/auth/logout') + expect(requestMethod).toBe('POST') + }) +})