2025-12-03 21:56:50 +00:00
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
|
|
import { TokenStorage } from './tokenStorage';
|
|
|
|
|
|
|
|
|
|
// Mock dependencies
|
|
|
|
|
vi.mock('./tokenStorage');
|
|
|
|
|
|
|
|
|
|
const mockTokenStorage = vi.mocked(TokenStorage);
|
|
|
|
|
|
|
|
|
|
// Mock axios
|
|
|
|
|
const mockPost = vi.fn();
|
|
|
|
|
const mockAxiosInstance = {
|
|
|
|
|
post: mockPost,
|
|
|
|
|
get: vi.fn(),
|
|
|
|
|
put: vi.fn(),
|
|
|
|
|
delete: vi.fn(),
|
|
|
|
|
patch: vi.fn(),
|
|
|
|
|
interceptors: {
|
|
|
|
|
request: { use: vi.fn(), eject: vi.fn() },
|
|
|
|
|
response: { use: vi.fn(), eject: vi.fn() },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vi.mock('axios', () => ({
|
|
|
|
|
default: {
|
|
|
|
|
create: vi.fn(() => mockAxiosInstance),
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// Import after mocks are set up
|
|
|
|
|
import { refreshToken } from './tokenRefresh';
|
|
|
|
|
|
|
|
|
|
describe('tokenRefresh', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
vi.clearAllMocks();
|
|
|
|
|
mockPost.mockReset();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('refreshToken', () => {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
it('should refresh token successfully with direct format response', async () => {
|
|
|
|
|
// SECURITY: Action 5.1.1.2 - Refresh token is in httpOnly cookie,
|
|
|
|
|
// sent automatically via withCredentials. Body is empty {}.
|
2025-12-03 21:56:50 +00:00
|
|
|
mockPost.mockResolvedValue({
|
|
|
|
|
data: {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
access_token: 'new-access-token',
|
|
|
|
|
refresh_token: 'new-refresh-token',
|
2025-12-03 21:56:50 +00:00
|
|
|
expires_in: 900,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await refreshToken();
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
// Verify API call was made with empty body (cookies handle auth)
|
|
|
|
|
expect(mockPost).toHaveBeenCalledWith('/auth/refresh', {});
|
2025-12-03 21:56:50 +00:00
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
// SECURITY: setTokens is now a no-op (tokens in httpOnly cookies)
|
|
|
|
|
expect(mockTokenStorage.setTokens).toHaveBeenCalled();
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
// Verify clearTokens was not called on success
|
|
|
|
|
expect(mockTokenStorage.clearTokens).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
it('should refresh token successfully with wrapped format response', async () => {
|
|
|
|
|
mockPost.mockResolvedValue({
|
|
|
|
|
data: {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
access_token: 'new-access-token',
|
|
|
|
|
refresh_token: 'new-refresh-token',
|
|
|
|
|
expires_in: 900,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-12-03 21:56:50 +00:00
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
await refreshToken();
|
2025-12-03 21:56:50 +00:00
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
expect(mockPost).toHaveBeenCalledWith('/auth/refresh', {});
|
|
|
|
|
expect(mockTokenStorage.setTokens).toHaveBeenCalled();
|
|
|
|
|
expect(mockTokenStorage.clearTokens).not.toHaveBeenCalled();
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should clear tokens and throw error on API failure', async () => {
|
|
|
|
|
const apiError = new Error('API Error');
|
|
|
|
|
mockPost.mockRejectedValue(apiError);
|
|
|
|
|
|
|
|
|
|
await expect(refreshToken()).rejects.toThrow('API Error');
|
|
|
|
|
|
|
|
|
|
// Verify API call was made
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
expect(mockPost).toHaveBeenCalledWith('/auth/refresh', {});
|
2025-12-03 21:56:50 +00:00
|
|
|
|
|
|
|
|
// Verify tokens were cleared on error
|
|
|
|
|
expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1);
|
|
|
|
|
|
|
|
|
|
// Verify tokens were not updated
|
|
|
|
|
expect(mockTokenStorage.setTokens).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should clear tokens on 401 Unauthorized error', async () => {
|
|
|
|
|
const axiosError = {
|
|
|
|
|
response: {
|
|
|
|
|
status: 401,
|
|
|
|
|
data: { error: 'Invalid refresh token' },
|
|
|
|
|
},
|
|
|
|
|
isAxiosError: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mockPost.mockRejectedValue(axiosError);
|
|
|
|
|
|
|
|
|
|
await expect(refreshToken()).rejects.toEqual(axiosError);
|
|
|
|
|
|
|
|
|
|
// Verify tokens were cleared on 401 error
|
|
|
|
|
expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should clear tokens on network error', async () => {
|
|
|
|
|
const networkError = new Error('Network Error');
|
|
|
|
|
mockPost.mockRejectedValue(networkError);
|
|
|
|
|
|
|
|
|
|
await expect(refreshToken()).rejects.toThrow('Network Error');
|
|
|
|
|
|
|
|
|
|
// Verify tokens were cleared on error
|
|
|
|
|
expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1);
|
|
|
|
|
});
|
|
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
it('should throw on invalid response format', async () => {
|
2025-12-03 21:56:50 +00:00
|
|
|
mockPost.mockResolvedValue({
|
|
|
|
|
data: {
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
unexpected: 'format',
|
2025-12-03 21:56:50 +00:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
await expect(refreshToken()).rejects.toThrow(
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
'Invalid refresh response format',
|
2025-12-13 02:34:34 +00:00
|
|
|
);
|
2025-12-03 21:56:50 +00:00
|
|
|
|
chore(refactor/sumi-migration): commit pending changes — tests, stream server, dist_verification
- apps/web: test updates (Vitest/setup), playbackAnalyticsService, TrackGrid, serviceErrorHandler
- veza-common: logging, metrics, traits, validation, random
- veza-stream-server: audio pipeline, codecs, cache, monitoring, routes
- apps/web/dist_verification: refresh build assets (content-hashed filenames)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:39:18 +00:00
|
|
|
// Verify tokens were cleared on error
|
|
|
|
|
expect(mockTokenStorage.clearTokens).toHaveBeenCalledTimes(1);
|
2025-12-03 21:56:50 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|