@growi/sdk-typescript 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/apiv1/index.d.ts +8 -5
- package/dist/apiv1/index.d.ts.map +1 -1
- package/dist/generated/v1/index.d.ts +14 -8
- package/dist/generated/v1/index.d.ts.map +1 -1
- package/dist/generated/v1/index.js +30 -6
- package/dist/generated/v1/index.js.map +1 -1
- package/dist/generated/v1/index.schemas.d.ts +132 -73
- package/dist/generated/v1/index.schemas.d.ts.map +1 -1
- package/dist/generated/v1/index.schemas.js +0 -4
- package/dist/generated/v1/index.schemas.js.map +1 -1
- package/dist/generated/v3/index.d.ts +1 -1
- package/dist/generated/v3/index.schemas.d.ts +45 -11
- package/dist/generated/v3/index.schemas.d.ts.map +1 -1
- package/dist/generated/v3/index.schemas.js.map +1 -1
- package/package.json +5 -3
- package/src/generated/v1/index.schemas.ts +153 -75
- package/src/generated/v1/index.ts +63 -20
- package/src/generated/v3/index.schemas.ts +51 -11
- package/src/generated/v3/index.ts +1 -1
- package/src/utils/axios-default-instance.test.ts +108 -0
- package/src/utils/v1/axios-instance.test.ts +250 -0
- package/src/utils/v3/axios-instance.test.ts +369 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { AxiosInstance } from 'axios';
|
|
2
|
+
/**
|
|
3
|
+
* Tests for axios-default-instance.ts
|
|
4
|
+
*
|
|
5
|
+
* This file manages the default Axios instance for GROWI SDK,
|
|
6
|
+
* providing functionality to configure base URL and authentication headers.
|
|
7
|
+
*/
|
|
8
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
9
|
+
import { AXIOS_DEFAULT } from './axios-default-instance.js';
|
|
10
|
+
|
|
11
|
+
describe('AXIOS_DEFAULT', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// Reset the instance before each test
|
|
14
|
+
AXIOS_DEFAULT.instance.defaults.baseURL = 'http://localhost';
|
|
15
|
+
AXIOS_DEFAULT.instance.defaults.headers.common.Authorization = undefined;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('setBaseURL', () => {
|
|
19
|
+
it('should update base URL when setting a valid URL', () => {
|
|
20
|
+
// Arrange
|
|
21
|
+
const newBaseURL = 'https://api.example.com';
|
|
22
|
+
|
|
23
|
+
// Act
|
|
24
|
+
AXIOS_DEFAULT.setBaseURL(newBaseURL);
|
|
25
|
+
|
|
26
|
+
// Assert
|
|
27
|
+
expect(AXIOS_DEFAULT.instance.defaults.baseURL).toBe(newBaseURL);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should set base URL to empty string when empty string is provided', () => {
|
|
31
|
+
// Arrange
|
|
32
|
+
const emptyURL = '';
|
|
33
|
+
|
|
34
|
+
// Act
|
|
35
|
+
AXIOS_DEFAULT.setBaseURL(emptyURL);
|
|
36
|
+
|
|
37
|
+
// Assert
|
|
38
|
+
expect(AXIOS_DEFAULT.instance.defaults.baseURL).toBe(emptyURL);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should use the last value when called multiple times', () => {
|
|
42
|
+
// Arrange
|
|
43
|
+
const firstURL = 'https://first.example.com';
|
|
44
|
+
const secondURL = 'https://second.example.com';
|
|
45
|
+
|
|
46
|
+
// Act
|
|
47
|
+
AXIOS_DEFAULT.setBaseURL(firstURL);
|
|
48
|
+
AXIOS_DEFAULT.setBaseURL(secondURL);
|
|
49
|
+
|
|
50
|
+
// Assert
|
|
51
|
+
expect(AXIOS_DEFAULT.instance.defaults.baseURL).toBe(secondURL);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('setAuthorizationHeader', () => {
|
|
56
|
+
it('should set authorization header in Bearer token format when valid token is provided', () => {
|
|
57
|
+
// Arrange
|
|
58
|
+
const token = 'test-token-123';
|
|
59
|
+
const expectedHeader = `Bearer ${token}`;
|
|
60
|
+
|
|
61
|
+
// Act
|
|
62
|
+
AXIOS_DEFAULT.setAuthorizationHeader(token);
|
|
63
|
+
|
|
64
|
+
// Assert
|
|
65
|
+
expect(AXIOS_DEFAULT.instance.defaults.headers.common.Authorization).toBe(expectedHeader);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should set Bearer header with empty string when empty token is provided', () => {
|
|
69
|
+
// Arrange
|
|
70
|
+
const emptyToken = '';
|
|
71
|
+
const expectedHeader = 'Bearer ';
|
|
72
|
+
|
|
73
|
+
// Act
|
|
74
|
+
AXIOS_DEFAULT.setAuthorizationHeader(emptyToken);
|
|
75
|
+
|
|
76
|
+
// Assert
|
|
77
|
+
expect(AXIOS_DEFAULT.instance.defaults.headers.common.Authorization).toBe(expectedHeader);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should use the last token when called multiple times', () => {
|
|
81
|
+
// Arrange
|
|
82
|
+
const firstToken = 'first-token';
|
|
83
|
+
const secondToken = 'second-token';
|
|
84
|
+
const expectedHeader = `Bearer ${secondToken}`;
|
|
85
|
+
|
|
86
|
+
// Act
|
|
87
|
+
AXIOS_DEFAULT.setAuthorizationHeader(firstToken);
|
|
88
|
+
AXIOS_DEFAULT.setAuthorizationHeader(secondToken);
|
|
89
|
+
|
|
90
|
+
// Assert
|
|
91
|
+
expect(AXIOS_DEFAULT.instance.defaults.headers.common.Authorization).toBe(expectedHeader);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('instance', () => {
|
|
96
|
+
it('should have default base URL set to localhost', () => {
|
|
97
|
+
// Assert
|
|
98
|
+
expect(AXIOS_DEFAULT.instance.defaults.baseURL).toBe('http://localhost');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should have Axios instance properly created', () => {
|
|
102
|
+
// Assert
|
|
103
|
+
expect(AXIOS_DEFAULT.instance).toBeDefined();
|
|
104
|
+
expect(typeof AXIOS_DEFAULT.instance).toBe('function');
|
|
105
|
+
expect(AXIOS_DEFAULT.instance.defaults).toBeDefined();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
|
+
import Axios from 'axios';
|
|
3
|
+
/**
|
|
4
|
+
* Tests for v1/axios-instance.ts
|
|
5
|
+
*
|
|
6
|
+
* This file provides custom Axios instance creation functionality for GROWI API v1,
|
|
7
|
+
* including automatic base URL configuration, cancellation capability, and request configuration merging.
|
|
8
|
+
*/
|
|
9
|
+
import { type MockedFunction, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
10
|
+
import { AXIOS_DEFAULT } from '../axios-default-instance.js';
|
|
11
|
+
import { customInstance } from './axios-instance.js';
|
|
12
|
+
|
|
13
|
+
// Mock Axios
|
|
14
|
+
vi.mock('axios');
|
|
15
|
+
vi.mock('../axios-default-instance.js');
|
|
16
|
+
|
|
17
|
+
const mockedAxios = vi.mocked(Axios);
|
|
18
|
+
const mockedAXIOS_DEFAULT = vi.mocked(AXIOS_DEFAULT);
|
|
19
|
+
|
|
20
|
+
// Type for the promise returned by customInstance with cancel functionality
|
|
21
|
+
type CancellablePromise<T> = Promise<T> & {
|
|
22
|
+
cancel: () => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe('v1 customInstance', () => {
|
|
26
|
+
let mockCancelTokenSource: {
|
|
27
|
+
token: string;
|
|
28
|
+
cancel: MockedFunction<() => void>;
|
|
29
|
+
};
|
|
30
|
+
let mockAxiosInstance: MockedFunction<(config: AxiosRequestConfig) => Promise<AxiosResponse<unknown>>>;
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
vi.clearAllMocks();
|
|
34
|
+
|
|
35
|
+
// Mock for CancelTokenSource
|
|
36
|
+
mockCancelTokenSource = {
|
|
37
|
+
token: 'mock-cancel-token',
|
|
38
|
+
cancel: vi.fn(),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Mock for Axios.CancelToken.source
|
|
42
|
+
mockedAxios.CancelToken = {
|
|
43
|
+
source: vi.fn().mockReturnValue(mockCancelTokenSource),
|
|
44
|
+
} as unknown as typeof Axios.CancelToken;
|
|
45
|
+
|
|
46
|
+
// Mock for Axios instance
|
|
47
|
+
mockAxiosInstance = vi.fn().mockResolvedValue({
|
|
48
|
+
data: { result: 'success' },
|
|
49
|
+
status: 200,
|
|
50
|
+
statusText: 'OK',
|
|
51
|
+
headers: {},
|
|
52
|
+
config: {},
|
|
53
|
+
} as AxiosResponse<{ result: string }>);
|
|
54
|
+
|
|
55
|
+
// Mock for AXIOS_DEFAULT
|
|
56
|
+
mockedAXIOS_DEFAULT.instance = mockAxiosInstance as unknown as typeof AXIOS_DEFAULT.instance;
|
|
57
|
+
Object.defineProperty(mockedAXIOS_DEFAULT.instance, 'defaults', {
|
|
58
|
+
value: {
|
|
59
|
+
baseURL: 'http://localhost',
|
|
60
|
+
headers: {
|
|
61
|
+
common: {},
|
|
62
|
+
delete: {},
|
|
63
|
+
get: {},
|
|
64
|
+
head: {},
|
|
65
|
+
post: {},
|
|
66
|
+
put: {},
|
|
67
|
+
patch: {},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
writable: true,
|
|
71
|
+
configurable: true,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
afterEach(() => {
|
|
76
|
+
vi.resetAllMocks();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('Base URL configuration', () => {
|
|
80
|
+
it('should append _api suffix to default base URL', async () => {
|
|
81
|
+
// Arrange
|
|
82
|
+
const config: AxiosRequestConfig = { method: 'GET', url: '/test' };
|
|
83
|
+
|
|
84
|
+
// Act
|
|
85
|
+
await customInstance(config);
|
|
86
|
+
|
|
87
|
+
// Assert
|
|
88
|
+
expect(mockAxiosInstance).toHaveBeenCalledWith(
|
|
89
|
+
expect.objectContaining({
|
|
90
|
+
baseURL: 'http://localhost/_api',
|
|
91
|
+
cancelToken: 'mock-cancel-token',
|
|
92
|
+
}),
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should prioritize baseURL specified in options', async () => {
|
|
97
|
+
// Arrange
|
|
98
|
+
const config: AxiosRequestConfig = { method: 'GET', url: '/test' };
|
|
99
|
+
const options: AxiosRequestConfig = { baseURL: 'https://custom.example.com' };
|
|
100
|
+
|
|
101
|
+
// Act
|
|
102
|
+
await customInstance(config, options);
|
|
103
|
+
|
|
104
|
+
// Assert
|
|
105
|
+
expect(mockAxiosInstance).toHaveBeenCalledWith(
|
|
106
|
+
expect.objectContaining({
|
|
107
|
+
baseURL: 'https://custom.example.com/_api',
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should use baseURL specified in config when provided', async () => {
|
|
113
|
+
// Arrange
|
|
114
|
+
const config: AxiosRequestConfig = {
|
|
115
|
+
method: 'GET',
|
|
116
|
+
url: '/test',
|
|
117
|
+
baseURL: 'https://config.example.com',
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Act
|
|
121
|
+
await customInstance(config);
|
|
122
|
+
|
|
123
|
+
// Assert
|
|
124
|
+
expect(mockAxiosInstance).toHaveBeenCalledWith(
|
|
125
|
+
expect.objectContaining({
|
|
126
|
+
baseURL: 'https://config.example.com/_api',
|
|
127
|
+
}),
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('Configuration merging', () => {
|
|
133
|
+
it('should correctly merge config and options', async () => {
|
|
134
|
+
// Arrange
|
|
135
|
+
const config: AxiosRequestConfig = {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
url: '/test',
|
|
138
|
+
data: { name: 'test' },
|
|
139
|
+
};
|
|
140
|
+
const options: AxiosRequestConfig = {
|
|
141
|
+
headers: { 'Custom-Header': 'value' },
|
|
142
|
+
timeout: 5000,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Act
|
|
146
|
+
await customInstance(config, options);
|
|
147
|
+
|
|
148
|
+
// Assert
|
|
149
|
+
expect(mockAxiosInstance).toHaveBeenCalledWith(
|
|
150
|
+
expect.objectContaining({
|
|
151
|
+
method: 'POST',
|
|
152
|
+
url: '/test',
|
|
153
|
+
data: { name: 'test' },
|
|
154
|
+
headers: { 'Custom-Header': 'value' },
|
|
155
|
+
timeout: 5000,
|
|
156
|
+
baseURL: 'http://localhost/_api',
|
|
157
|
+
cancelToken: 'mock-cancel-token',
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should override config values with options values', async () => {
|
|
163
|
+
// Arrange
|
|
164
|
+
const config: AxiosRequestConfig = {
|
|
165
|
+
method: 'GET',
|
|
166
|
+
timeout: 1000,
|
|
167
|
+
};
|
|
168
|
+
const options: AxiosRequestConfig = {
|
|
169
|
+
timeout: 3000,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Act
|
|
173
|
+
await customInstance(config, options);
|
|
174
|
+
|
|
175
|
+
// Assert
|
|
176
|
+
expect(mockAxiosInstance).toHaveBeenCalledWith(
|
|
177
|
+
expect.objectContaining({
|
|
178
|
+
timeout: 3000,
|
|
179
|
+
}),
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('Response processing', () => {
|
|
185
|
+
it('should return the data property from response', async () => {
|
|
186
|
+
// Arrange
|
|
187
|
+
const expectedData = { users: [{ id: 1, name: 'John' }] };
|
|
188
|
+
mockAxiosInstance.mockResolvedValue({
|
|
189
|
+
data: expectedData,
|
|
190
|
+
status: 200,
|
|
191
|
+
statusText: 'OK',
|
|
192
|
+
headers: {},
|
|
193
|
+
config: {},
|
|
194
|
+
} as AxiosResponse<{ users: Array<{ id: number; name: string }> }>);
|
|
195
|
+
|
|
196
|
+
const config: AxiosRequestConfig = { method: 'GET', url: '/users' };
|
|
197
|
+
|
|
198
|
+
// Act
|
|
199
|
+
const result = await customInstance(config);
|
|
200
|
+
|
|
201
|
+
// Assert
|
|
202
|
+
expect(result).toEqual(expectedData);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe('Cancellation functionality', () => {
|
|
207
|
+
it('should add cancel function to returned Promise', async () => {
|
|
208
|
+
// Arrange
|
|
209
|
+
const config: AxiosRequestConfig = { method: 'GET', url: '/test' };
|
|
210
|
+
|
|
211
|
+
// Act
|
|
212
|
+
const promise = customInstance(config) as CancellablePromise<unknown>;
|
|
213
|
+
|
|
214
|
+
// Assert
|
|
215
|
+
expect(promise).toHaveProperty('cancel');
|
|
216
|
+
expect(typeof promise.cancel).toBe('function');
|
|
217
|
+
|
|
218
|
+
// cleanup
|
|
219
|
+
await promise;
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should call CancelTokenSource cancel when cancel function is invoked', async () => {
|
|
223
|
+
// Arrange
|
|
224
|
+
const config: AxiosRequestConfig = { method: 'GET', url: '/test' };
|
|
225
|
+
|
|
226
|
+
// Act
|
|
227
|
+
const promise = customInstance(config) as CancellablePromise<unknown>;
|
|
228
|
+
promise.cancel();
|
|
229
|
+
|
|
230
|
+
// Assert
|
|
231
|
+
expect(mockCancelTokenSource.cancel).toHaveBeenCalledWith('Query cancelled');
|
|
232
|
+
|
|
233
|
+
// cleanup
|
|
234
|
+
await promise;
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe('Error handling', () => {
|
|
239
|
+
it('should reject Promise when Axios error occurs', async () => {
|
|
240
|
+
// Arrange
|
|
241
|
+
const error = new Error('Network error');
|
|
242
|
+
mockAxiosInstance.mockRejectedValue(error);
|
|
243
|
+
|
|
244
|
+
const config: AxiosRequestConfig = { method: 'GET', url: '/test' };
|
|
245
|
+
|
|
246
|
+
// Act & Assert
|
|
247
|
+
await expect(customInstance(config)).rejects.toThrow('Network error');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|