Bot
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { CoreApiClient, CoreApiClientError } from '../../src/adapters/notification/core-api-client';
|
||||
|
||||
describe('CoreApiClient', () => {
|
||||
const API_URL = 'http://core.local';
|
||||
const CLIENT_ID = 'cid';
|
||||
const CLIENT_SECRET = 'csec';
|
||||
|
||||
beforeEach(() => {
|
||||
(global as any).fetch = jest.fn();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('requests token successfully and caches it', async () => {
|
||||
// token endpoint response
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||
|
||||
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||
|
||||
const token = await client.getToken();
|
||||
expect(token).toBe('t1');
|
||||
|
||||
// second call should not call fetch again for token
|
||||
const token2 = await client.getToken();
|
||||
expect(token2).toBe('t1');
|
||||
expect(global.fetch).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('throws on invalid credentials (401)', async () => {
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 401, json: async () => ({}) });
|
||||
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||
await expect(client.getToken()).rejects.toThrow(CoreApiClientError);
|
||||
});
|
||||
|
||||
it('retries once on 401 during authenticatedRequest', async () => {
|
||||
// initial token fetch
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||
|
||||
// first API call returns 401
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 401, json: async () => ({}) });
|
||||
|
||||
// token refresh fetch returns new token
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't2', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||
|
||||
// retried API call returns 200
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ ok: true }) });
|
||||
|
||||
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||
|
||||
const res = await client.authenticatedRequest(`${API_URL}/api/v1/users`, { method: 'GET' });
|
||||
expect(res.status).toBe(200);
|
||||
expect(global.fetch).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
|
||||
it('does not retry on 403', async () => {
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 403, json: async () => ({}) });
|
||||
|
||||
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||
|
||||
const res = await client.authenticatedRequest(`${API_URL}/api/v1/forbidden`, { method: 'GET' });
|
||||
expect(res.status).toBe(403);
|
||||
// only token fetch + one API call
|
||||
expect(global.fetch).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('handles token refresh before expiry', async () => {
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't1', token_type: 'Bearer', expires_in: 2 } }) });
|
||||
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET });
|
||||
|
||||
const token1 = await client.getToken();
|
||||
expect(token1).toBe('t1');
|
||||
|
||||
// force expiry by manipulating internal state
|
||||
(client as any).tokenExpiry = Date.now() - 1000;
|
||||
|
||||
(global.fetch as jest.Mock).mockResolvedValueOnce({ status: 200, json: async () => ({ success: true, data: { access_token: 't2', token_type: 'Bearer', expires_in: 3600 } }) });
|
||||
|
||||
const token2 = await client.getToken();
|
||||
expect(token2).toBe('t2');
|
||||
});
|
||||
|
||||
it('handles network timeout', async () => {
|
||||
(global.fetch as jest.Mock).mockRejectedValueOnce(Object.assign(new Error('AbortError'), { name: 'AbortError' }));
|
||||
const client = new CoreApiClient({ apiUrl: API_URL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, timeoutMs: 1 });
|
||||
await expect(client.getToken()).rejects.toThrow(CoreApiClientError);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user