Skip to content

Commit 7e69544

Browse files
committed
increase test coverage
1 parent 3a93341 commit 7e69544

2 files changed

Lines changed: 98 additions & 1 deletion

File tree

packages/sdk/src/platform-sdk.test.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { describe, it, expect, beforeEach, vi } from 'vitest';
22
import { http, HttpResponse } from 'msw';
33
import { PlatformSDKHttp } from './platform-sdk.js';
4-
import { AuthenticationError } from './errors.js';
4+
import { APIError, AuthenticationError, UnexpectedError } from './errors.js';
55
import { setMockScenario, server } from './test-utils/http-mocks.js';
66
import { ItemState, ItemTerminationReason } from './generated/api.js';
7+
import { PublicApi } from './generated/index.js';
78

89
describe('PlatformSDK', () => {
910
let sdk: PlatformSDKHttp;
@@ -601,4 +602,50 @@ describe('PlatformSDK', () => {
601602
);
602603
expect(callCount).toBe(1);
603604
});
605+
606+
it('should throw APIError with 422 status when validation error occurs', async () => {
607+
mockTokenProvider.mockResolvedValue('mocked-token');
608+
setMockScenario('validationError');
609+
610+
await expect(sdk.listApplications()).rejects.toThrow(APIError);
611+
await expect(sdk.listApplications()).rejects.toThrow('Validation error:');
612+
});
613+
614+
it('should throw APIError with 403 status when access is forbidden', async () => {
615+
mockTokenProvider.mockResolvedValue('mocked-token');
616+
617+
server.use(
618+
http.get('*/v1/applications', () => {
619+
return HttpResponse.json({ detail: 'Forbidden' }, { status: 403 });
620+
})
621+
);
622+
623+
await expect(sdk.listApplications()).rejects.toThrow(APIError);
624+
await expect(sdk.listApplications()).rejects.toThrow('Access forbidden:');
625+
});
626+
627+
it('should throw APIError with 410 status when resource is gone', async () => {
628+
mockTokenProvider.mockResolvedValue('mocked-token');
629+
630+
server.use(
631+
http.get('*/v1/runs/:runId', () => {
632+
return HttpResponse.json({ detail: 'Gone' }, { status: 410 });
633+
})
634+
);
635+
636+
await expect(sdk.getRun('test-run-id')).rejects.toThrow(APIError);
637+
await expect(sdk.getRun('test-run-id')).rejects.toThrow('Resource gone:');
638+
});
639+
640+
it('should throw UnexpectedError for non-axios errors', async () => {
641+
mockTokenProvider.mockResolvedValue('mocked-token');
642+
643+
vi.spyOn(PublicApi.prototype, 'listApplicationsV1ApplicationsGet').mockRejectedValueOnce(
644+
new RangeError('unexpected internal failure')
645+
);
646+
647+
const error = await sdk.listApplications().catch((e) => e);
648+
expect(error).toBeInstanceOf(UnexpectedError);
649+
expect(error.message).toContain('Unexpected error:');
650+
});
604651
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
import axios, { AxiosHeaders } from 'axios';
3+
import { downloadWithRetry } from './downloadWithRetry.js';
4+
5+
describe('downloadWithRetry', () => {
6+
it('should retry non-axios errors and succeed on second attempt', async () => {
7+
let callCount = 0;
8+
const nonAxiosError = new Error('transient non-axios error');
9+
const mockFn = vi.fn().mockImplementation(async () => {
10+
callCount++;
11+
if (callCount === 1) {
12+
throw nonAxiosError;
13+
}
14+
return {
15+
data: new ArrayBuffer(4),
16+
status: 200,
17+
statusText: 'OK',
18+
headers: new AxiosHeaders(),
19+
config: { headers: new AxiosHeaders() },
20+
};
21+
});
22+
23+
const result = await downloadWithRetry(mockFn);
24+
expect(result.status).toBe(200);
25+
expect(callCount).toBe(2);
26+
}, 10_000);
27+
28+
it('should retry axios error with no response (network error) and succeed on second attempt', async () => {
29+
let callCount = 0;
30+
const networkError = new axios.AxiosError('Network Error', 'ERR_NETWORK');
31+
// networkError.response is undefined — triggers the `?? 0` fallback
32+
const mockFn = vi.fn().mockImplementation(async () => {
33+
callCount++;
34+
if (callCount === 1) {
35+
throw networkError;
36+
}
37+
return {
38+
data: new ArrayBuffer(4),
39+
status: 200,
40+
statusText: 'OK',
41+
headers: new AxiosHeaders(),
42+
config: { headers: new AxiosHeaders() },
43+
};
44+
});
45+
46+
const result = await downloadWithRetry(mockFn);
47+
expect(result.status).toBe(200);
48+
expect(callCount).toBe(2);
49+
}, 10_000);
50+
});

0 commit comments

Comments
 (0)