143 lines
3.9 KiB
TypeScript
143 lines
3.9 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||
|
|
import { api, tokenManager } from '../src/lib/api';
|
||
|
|
|
||
|
|
// Mock localStorage for Node.js test environment
|
||
|
|
const localStorageMock = (() => {
|
||
|
|
let store: Record<string, string> = {};
|
||
|
|
return {
|
||
|
|
getItem: (key: string) => store[key] || null,
|
||
|
|
setItem: (key: string, value: string) => { store[key] = value; },
|
||
|
|
removeItem: (key: string) => { delete store[key]; },
|
||
|
|
clear: () => { store = {}; },
|
||
|
|
};
|
||
|
|
})();
|
||
|
|
|
||
|
|
Object.defineProperty(global, 'localStorage', {
|
||
|
|
value: localStorageMock,
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('Session API', () => {
|
||
|
|
let fetchMock: ReturnType<typeof vi.fn>;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
fetchMock = vi.fn();
|
||
|
|
global.fetch = fetchMock;
|
||
|
|
localStorage.clear();
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
vi.restoreAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('refreshSession', () => {
|
||
|
|
it('calls the correct endpoint and updates token expiry', async () => {
|
||
|
|
const mockResponse = {
|
||
|
|
success: true,
|
||
|
|
code: 200,
|
||
|
|
message: 'Session refreshed',
|
||
|
|
data: { expires_at: '2026-04-26T18:30:00Z' },
|
||
|
|
};
|
||
|
|
|
||
|
|
fetchMock.mockResolvedValueOnce({
|
||
|
|
json: () => Promise.resolve(mockResponse),
|
||
|
|
});
|
||
|
|
|
||
|
|
// Set a token first
|
||
|
|
tokenManager.setToken('test-token', '2026-04-26T17:00:00Z');
|
||
|
|
|
||
|
|
const result = await api.auth.refreshSession();
|
||
|
|
|
||
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
||
|
|
expect.stringContaining('/auth/sessions/refresh'),
|
||
|
|
expect.objectContaining({
|
||
|
|
method: 'POST',
|
||
|
|
headers: expect.objectContaining({
|
||
|
|
Authorization: 'Bearer test-token',
|
||
|
|
}),
|
||
|
|
})
|
||
|
|
);
|
||
|
|
expect(result.expires_at).toBe('2026-04-26T18:30:00Z');
|
||
|
|
expect(tokenManager.getExpiry()).toBe('2026-04-26T18:30:00Z');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('listSessions', () => {
|
||
|
|
it('calls the correct endpoint', async () => {
|
||
|
|
const mockResponse = {
|
||
|
|
success: true,
|
||
|
|
code: 200,
|
||
|
|
message: 'Sessions listed',
|
||
|
|
data: {
|
||
|
|
sessions: [
|
||
|
|
{
|
||
|
|
id: 'sess-1',
|
||
|
|
created_at: '2026-04-26T10:00:00Z',
|
||
|
|
expires_at: '2026-04-26T18:00:00Z',
|
||
|
|
last_used_at: '2026-04-26T17:00:00Z',
|
||
|
|
ip_address: '127.0.0.1',
|
||
|
|
user_agent: 'Mozilla/5.0',
|
||
|
|
is_current: true,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
};
|
||
|
|
|
||
|
|
fetchMock.mockResolvedValueOnce({
|
||
|
|
json: () => Promise.resolve(mockResponse),
|
||
|
|
});
|
||
|
|
|
||
|
|
tokenManager.setToken('test-token');
|
||
|
|
|
||
|
|
const result = await api.auth.listSessions();
|
||
|
|
|
||
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
||
|
|
expect.stringContaining('/auth/sessions'),
|
||
|
|
expect.objectContaining({
|
||
|
|
credentials: 'include',
|
||
|
|
})
|
||
|
|
);
|
||
|
|
expect(result.sessions).toHaveLength(1);
|
||
|
|
expect(result.sessions[0].id).toBe('sess-1');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('revokeSession', () => {
|
||
|
|
it('encodes session ID and calls the correct endpoint', async () => {
|
||
|
|
const mockResponse = {
|
||
|
|
success: true,
|
||
|
|
code: 200,
|
||
|
|
message: 'Session revoked',
|
||
|
|
data: {},
|
||
|
|
};
|
||
|
|
|
||
|
|
fetchMock.mockResolvedValueOnce({
|
||
|
|
json: () => Promise.resolve(mockResponse),
|
||
|
|
});
|
||
|
|
|
||
|
|
tokenManager.setToken('test-token');
|
||
|
|
|
||
|
|
await api.auth.revokeSession('sess-abc/123');
|
||
|
|
|
||
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
||
|
|
expect.stringContaining('/auth/sessions/sess-abc%2F123'),
|
||
|
|
expect.objectContaining({
|
||
|
|
method: 'DELETE',
|
||
|
|
})
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('tokenManager', () => {
|
||
|
|
it('updateExpiry sets the expiry in localStorage', () => {
|
||
|
|
tokenManager.setToken('test-token');
|
||
|
|
tokenManager.updateExpiry('2026-04-26T20:00:00Z');
|
||
|
|
expect(tokenManager.getExpiry()).toBe('2026-04-26T20:00:00Z');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('getExpiry returns null when no expiry is set', () => {
|
||
|
|
localStorage.clear();
|
||
|
|
expect(tokenManager.getExpiry()).toBeNull();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|