@tramvai/module-http-client 6.63.1 → 6.65.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/lib/httpClient/headers.browser.js +1 -1
- package/lib/httpClient/headers.d.ts +1 -1
- package/lib/httpClient/headers.es.js +1 -1
- package/lib/httpClient/headers.js +1 -1
- package/lib/httpClient/httpClientFactory.browser.js +0 -1
- package/lib/httpClient/httpClientFactory.es.js +0 -1
- package/lib/httpClient/httpClientFactory.js +0 -1
- package/lib/httpClientModule.browser.d.ts +4 -0
- package/lib/httpClientModule.browser.js +46 -105
- package/lib/httpClientModule.d.ts +3 -3
- package/lib/httpClientModule.es.js +46 -105
- package/lib/httpClientModule.js +44 -103
- package/lib/shared.browser.js +108 -0
- package/lib/shared.d.ts +218 -0
- package/lib/shared.es.js +108 -0
- package/lib/shared.js +112 -0
- package/lib/test/unit/testApi.d.ts +5 -3
- package/package.json +17 -15
- package/tests.d.ts +5 -6
- package/tests.js +207 -169
package/tests.js
CHANGED
|
@@ -2,34 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var fetch = require('node-fetch');
|
|
6
5
|
var testHelpers = require('@tramvai/test-helpers');
|
|
7
6
|
var testMocks = require('@tramvai/test-mocks');
|
|
8
|
-
var dippy = require('@tinkoff/dippy');
|
|
9
7
|
var core = require('@tramvai/core');
|
|
10
8
|
var tokensHttpClient = require('@tramvai/tokens-http-client');
|
|
11
|
-
var tokensCommon = require('@tramvai/tokens-common');
|
|
12
|
-
var isNil = require('@tinkoff/utils/is/nil');
|
|
13
|
-
var compose = require('@tinkoff/utils/function/compose');
|
|
14
|
-
var tinkoffRequestHttpClientAdapter = require('@tramvai/tinkoff-request-http-client-adapter');
|
|
15
|
-
var identity = require('@tinkoff/utils/function/identity');
|
|
16
|
-
var flatten = require('@tinkoff/utils/array/flatten');
|
|
17
|
-
var pick = require('@tinkoff/utils/object/pick');
|
|
18
9
|
var tokensServer = require('@tramvai/tokens-server');
|
|
19
10
|
var find = require('@tinkoff/utils/array/find');
|
|
11
|
+
var flatten = require('@tinkoff/utils/array/flatten');
|
|
20
12
|
var httpClient = require('@tramvai/http-client');
|
|
13
|
+
var dippy = require('@tinkoff/dippy');
|
|
21
14
|
var papi = require('@tramvai/papi');
|
|
22
15
|
var tokensServerPrivate = require('@tramvai/tokens-server-private');
|
|
16
|
+
var identity = require('@tinkoff/utils/function/identity');
|
|
17
|
+
var pick = require('@tinkoff/utils/object/pick');
|
|
18
|
+
var tokensCommon = require('@tramvai/tokens-common');
|
|
19
|
+
var isNil = require('@tinkoff/utils/is/nil');
|
|
20
|
+
var compose = require('@tinkoff/utils/function/compose');
|
|
21
|
+
var tinkoffRequestHttpClientAdapter = require('@tramvai/tinkoff-request-http-client-adapter');
|
|
23
22
|
|
|
24
23
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
25
24
|
|
|
26
|
-
var
|
|
27
|
-
var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
|
|
28
|
-
var compose__default = /*#__PURE__*/_interopDefaultLegacy(compose);
|
|
29
|
-
var identity__default = /*#__PURE__*/_interopDefaultLegacy(identity);
|
|
25
|
+
var find__default = /*#__PURE__*/_interopDefaultLegacy(find);
|
|
30
26
|
var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
|
|
27
|
+
var identity__default = /*#__PURE__*/_interopDefaultLegacy(identity);
|
|
31
28
|
var pick__default = /*#__PURE__*/_interopDefaultLegacy(pick);
|
|
32
|
-
var
|
|
29
|
+
var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
|
|
30
|
+
var compose__default = /*#__PURE__*/_interopDefaultLegacy(compose);
|
|
33
31
|
|
|
34
32
|
const fillHeaderIp = ({ requestManager, }) => {
|
|
35
33
|
if (!requestManager) {
|
|
@@ -68,6 +66,57 @@ const comparePathWithPattern = (path, pattern) => new RegExp(`^${pattern.replace
|
|
|
68
66
|
|
|
69
67
|
const getPathParams = (path, pattern) => path.match(new RegExp(`^${pattern.replace(/:(\w+)/g, '(?<$1>[^\\/]+)')}$`))?.groups ?? {};
|
|
70
68
|
|
|
69
|
+
class PapiService extends httpClient.BaseHttpClient {
|
|
70
|
+
constructor({ papi, di }) {
|
|
71
|
+
super();
|
|
72
|
+
this.papi = flatten__default["default"](papi || []);
|
|
73
|
+
this.di = di;
|
|
74
|
+
}
|
|
75
|
+
async request({ path, query, body, headers, }) {
|
|
76
|
+
const pathWithLeadingSlash = path?.startsWith('/') ? path : `/${path}`;
|
|
77
|
+
const papiRoute = find__default["default"]((papi$1) => comparePathWithPattern(pathWithLeadingSlash, papi.getPapiParameters(papi$1).path), this.papi ?? []);
|
|
78
|
+
if (!papiRoute) {
|
|
79
|
+
throw new Error(`papi handler '${path}' not found`);
|
|
80
|
+
}
|
|
81
|
+
const req = {
|
|
82
|
+
headers: { ...headers, host: 'localhost' },
|
|
83
|
+
cookies: {},
|
|
84
|
+
query,
|
|
85
|
+
body,
|
|
86
|
+
params: getPathParams(pathWithLeadingSlash, papi.getPapiParameters(papiRoute).path),
|
|
87
|
+
};
|
|
88
|
+
const res = {};
|
|
89
|
+
const childDi = dippy.createChildContainer(this.di, [
|
|
90
|
+
{
|
|
91
|
+
provide: tokensServerPrivate.FASTIFY_REQUEST,
|
|
92
|
+
useValue: req,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
provide: tokensServerPrivate.FASTIFY_RESPONSE,
|
|
96
|
+
useValue: res,
|
|
97
|
+
},
|
|
98
|
+
]);
|
|
99
|
+
const papiExecutor = childDi.get(tokensServerPrivate.PAPI_EXECUTOR);
|
|
100
|
+
const payload = await papiExecutor(papiRoute);
|
|
101
|
+
return { payload, status: 200, headers: {} };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const PapiClientModule = /* @__PURE__ */ core.Module({
|
|
106
|
+
providers: [
|
|
107
|
+
core.provide({
|
|
108
|
+
provide: tokensHttpClient.PAPI_SERVICE,
|
|
109
|
+
scope: core.Scope.SINGLETON,
|
|
110
|
+
useClass: PapiService,
|
|
111
|
+
deps: {
|
|
112
|
+
di: core.DI_TOKEN,
|
|
113
|
+
papi: { token: tokensServer.SERVER_MODULE_PAPI_PUBLIC_ROUTE, optional: true },
|
|
114
|
+
},
|
|
115
|
+
}),
|
|
116
|
+
],
|
|
117
|
+
})(class PapiClientModule {
|
|
118
|
+
});
|
|
119
|
+
|
|
71
120
|
const createUserAgent = ({ appInfo, envManager, }) => {
|
|
72
121
|
const { appName } = appInfo;
|
|
73
122
|
const appVersion = envManager.get('APP_VERSION');
|
|
@@ -84,7 +133,7 @@ const createUserAgent = ({ appInfo, envManager, }) => {
|
|
|
84
133
|
};
|
|
85
134
|
|
|
86
135
|
/**
|
|
87
|
-
*
|
|
136
|
+
* nodejs sends "User-Agent: node" header
|
|
88
137
|
* on the server by default. For logging purpose, we are
|
|
89
138
|
* replacing "User-Agent" value with custom one, containing
|
|
90
139
|
* both application name and version.
|
|
@@ -128,7 +177,6 @@ const httpClientFactory = ({ logger, envManager, appInfo, requestManager, header
|
|
|
128
177
|
failureThreshold: 75,
|
|
129
178
|
minimumFailureCount: 10,
|
|
130
179
|
},
|
|
131
|
-
// TODO: remove any after [resolving](https://github.com/southpolesteve/node-abort-controller/issues/31)
|
|
132
180
|
signal: commandLineExecutionContext?.()?.abortSignal,
|
|
133
181
|
...environmentDependentOptions,
|
|
134
182
|
}, defaultOptions ? tinkoffRequestHttpClientAdapter.mergeOptions(defaultOptions, interceptors) : interceptors), options);
|
|
@@ -162,164 +210,156 @@ const httpClientFactory = ({ logger, envManager, appInfo, requestManager, header
|
|
|
162
210
|
};
|
|
163
211
|
};
|
|
164
212
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
cookies: {},
|
|
180
|
-
query,
|
|
181
|
-
body,
|
|
182
|
-
params: getPathParams(pathWithLeadingSlash, papi.getPapiParameters(papiRoute).path),
|
|
183
|
-
};
|
|
184
|
-
const res = {};
|
|
185
|
-
const childDi = dippy.createChildContainer(this.di, [
|
|
186
|
-
{
|
|
187
|
-
provide: tokensServerPrivate.FASTIFY_REQUEST,
|
|
188
|
-
useValue: req,
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
provide: tokensServerPrivate.FASTIFY_RESPONSE,
|
|
192
|
-
useValue: res,
|
|
213
|
+
const createCacheToken = dippy.createToken('httpClient createCache');
|
|
214
|
+
const providers = [
|
|
215
|
+
core.provide({
|
|
216
|
+
provide: tokensHttpClient.HTTP_CLIENT_FACTORY,
|
|
217
|
+
useFactory: httpClientFactory,
|
|
218
|
+
deps: {
|
|
219
|
+
logger: tokensCommon.LOGGER_TOKEN,
|
|
220
|
+
envManager: tokensCommon.ENV_MANAGER_TOKEN,
|
|
221
|
+
appInfo: core.APP_INFO_TOKEN,
|
|
222
|
+
createCache: createCacheToken,
|
|
223
|
+
makeRequestRegistry: 'makeRequestRegistry',
|
|
224
|
+
requestManager: {
|
|
225
|
+
token: tokensCommon.REQUEST_MANAGER_TOKEN,
|
|
226
|
+
optional: true,
|
|
193
227
|
},
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return { payload, status: 200, headers: {} };
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const PapiClientModule = /* @__PURE__ */ core.Module({
|
|
202
|
-
providers: [
|
|
203
|
-
core.provide({
|
|
204
|
-
provide: tokensHttpClient.PAPI_SERVICE,
|
|
205
|
-
scope: core.Scope.SINGLETON,
|
|
206
|
-
useClass: PapiService,
|
|
207
|
-
deps: {
|
|
208
|
-
di: core.DI_TOKEN,
|
|
209
|
-
papi: { token: tokensServer.SERVER_MODULE_PAPI_PUBLIC_ROUTE, optional: true },
|
|
228
|
+
headersList: {
|
|
229
|
+
token: tokensHttpClient.API_CLIENT_PASS_HEADERS,
|
|
230
|
+
optional: true,
|
|
210
231
|
},
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const createCacheToken = dippy.createToken('httpClient createCache');
|
|
217
|
-
const HttpClientModule = /* @__PURE__ */ core.Module({
|
|
218
|
-
imports: [PapiClientModule],
|
|
219
|
-
providers: [
|
|
220
|
-
core.provide({
|
|
221
|
-
provide: tokensHttpClient.HTTP_CLIENT_FACTORY,
|
|
222
|
-
useFactory: httpClientFactory,
|
|
223
|
-
deps: {
|
|
224
|
-
logger: tokensCommon.LOGGER_TOKEN,
|
|
225
|
-
envManager: tokensCommon.ENV_MANAGER_TOKEN,
|
|
226
|
-
appInfo: core.APP_INFO_TOKEN,
|
|
227
|
-
createCache: createCacheToken,
|
|
228
|
-
makeRequestRegistry: 'makeRequestRegistry',
|
|
229
|
-
requestManager: {
|
|
230
|
-
token: tokensCommon.REQUEST_MANAGER_TOKEN,
|
|
231
|
-
optional: true,
|
|
232
|
-
},
|
|
233
|
-
headersList: {
|
|
234
|
-
token: tokensHttpClient.API_CLIENT_PASS_HEADERS,
|
|
235
|
-
optional: true,
|
|
236
|
-
},
|
|
237
|
-
agent: {
|
|
238
|
-
token: tokensHttpClient.HTTP_CLIENT_AGENT,
|
|
239
|
-
optional: true,
|
|
240
|
-
},
|
|
241
|
-
disableCircuitBreaker: {
|
|
242
|
-
token: tokensHttpClient.DISABLE_CIRCUIT_BREAKER,
|
|
243
|
-
optional: true,
|
|
244
|
-
},
|
|
245
|
-
defaultOptions: {
|
|
246
|
-
token: tokensHttpClient.DEFAULT_HTTP_CLIENT_FACTORY_OPTIONS,
|
|
247
|
-
optional: true,
|
|
248
|
-
},
|
|
249
|
-
defaultInterceptors: {
|
|
250
|
-
token: tokensHttpClient.DEFAULT_HTTP_CLIENT_INTERCEPTORS,
|
|
251
|
-
optional: true,
|
|
252
|
-
},
|
|
253
|
-
commandLineExecutionContext: {
|
|
254
|
-
token: tokensCommon.COMMAND_LINE_EXECUTION_CONTEXT_TOKEN,
|
|
255
|
-
optional: true,
|
|
256
|
-
},
|
|
232
|
+
agent: {
|
|
233
|
+
token: tokensHttpClient.HTTP_CLIENT_AGENT,
|
|
234
|
+
optional: true,
|
|
257
235
|
},
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
useFactory: ({ factory }) => {
|
|
262
|
-
return factory({
|
|
263
|
-
name: 'http-client',
|
|
264
|
-
enableCircuitBreaker: false,
|
|
265
|
-
});
|
|
236
|
+
disableCircuitBreaker: {
|
|
237
|
+
token: tokensHttpClient.DISABLE_CIRCUIT_BREAKER,
|
|
238
|
+
optional: true,
|
|
266
239
|
},
|
|
267
|
-
|
|
268
|
-
|
|
240
|
+
defaultOptions: {
|
|
241
|
+
token: tokensHttpClient.DEFAULT_HTTP_CLIENT_FACTORY_OPTIONS,
|
|
242
|
+
optional: true,
|
|
269
243
|
},
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
useValue: [
|
|
274
|
-
{ key: 'HTTP_CLIENT_CACHE_DISABLED', optional: true, dehydrate: false },
|
|
275
|
-
{ key: 'HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED', optional: true, dehydrate: false },
|
|
276
|
-
],
|
|
277
|
-
}),
|
|
278
|
-
/**
|
|
279
|
-
* хранилище для экземпляров @tinkoff/request
|
|
280
|
-
*
|
|
281
|
-
* требуется хранить экземпляры в единственном виде,
|
|
282
|
-
* т.к. многие плагины @tinkoff/request после инициализации имеют состояние
|
|
283
|
-
* (cache, circuit breaker), и не будут корректно работать на сервере,
|
|
284
|
-
* если создавать новые экземпляры на Scope.REQUEST
|
|
285
|
-
*/
|
|
286
|
-
core.provide({
|
|
287
|
-
provide: 'makeRequestRegistry',
|
|
288
|
-
scope: core.Scope.SINGLETON,
|
|
289
|
-
useFactory: () => new Map(),
|
|
290
|
-
}),
|
|
291
|
-
/**
|
|
292
|
-
* `CREATE_CACHE_TOKEN` имеет проверку, если токен используется провайдером,
|
|
293
|
-
* который имеет Scope.SINGLETON, то инстанс кэша сохраняется в общее хранилище,
|
|
294
|
-
* и доступен для очистки через `/papi/clear-cache`.
|
|
295
|
-
* Scope.REQUEST игнорируется, т.к. это верная утечка памяти,
|
|
296
|
-
* инстансов кэши было бы неограниченное количество.
|
|
297
|
-
*
|
|
298
|
-
* HTTP клиенты создаются со Scope.REQUEST, но инстансы @tinkoff/request
|
|
299
|
-
* (и соответственно кэшей) создаются только один раз, благодаря `makeRequestRegistry`.
|
|
300
|
-
* это гарантирует отсутствие утечек памяти, поэтому мы обходим проверку
|
|
301
|
-
* на Scope.SINGLETON c помощью обертки `createCacheToken`
|
|
302
|
-
*/
|
|
303
|
-
core.provide({
|
|
304
|
-
provide: createCacheToken,
|
|
305
|
-
scope: core.Scope.SINGLETON,
|
|
306
|
-
useFactory: ({ createCache }) => {
|
|
307
|
-
return createCache;
|
|
244
|
+
defaultInterceptors: {
|
|
245
|
+
token: tokensHttpClient.DEFAULT_HTTP_CLIENT_INTERCEPTORS,
|
|
246
|
+
optional: true,
|
|
308
247
|
},
|
|
309
|
-
|
|
310
|
-
|
|
248
|
+
commandLineExecutionContext: {
|
|
249
|
+
token: tokensCommon.COMMAND_LINE_EXECUTION_CONTEXT_TOKEN,
|
|
250
|
+
optional: true,
|
|
311
251
|
},
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
})
|
|
252
|
+
},
|
|
253
|
+
}),
|
|
254
|
+
core.provide({
|
|
255
|
+
provide: tokensHttpClient.HTTP_CLIENT,
|
|
256
|
+
useFactory: ({ factory }) => {
|
|
257
|
+
return factory({
|
|
258
|
+
name: 'http-client',
|
|
259
|
+
enableCircuitBreaker: false,
|
|
260
|
+
});
|
|
261
|
+
},
|
|
262
|
+
deps: {
|
|
263
|
+
factory: tokensHttpClient.HTTP_CLIENT_FACTORY,
|
|
264
|
+
},
|
|
265
|
+
}),
|
|
266
|
+
core.provide({
|
|
267
|
+
provide: tokensCommon.ENV_USED_TOKEN,
|
|
268
|
+
useValue: [
|
|
269
|
+
{ key: 'HTTP_CLIENT_CACHE_DISABLED', optional: true, dehydrate: false },
|
|
270
|
+
{ key: 'HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED', optional: true, dehydrate: false },
|
|
271
|
+
],
|
|
272
|
+
}),
|
|
273
|
+
/**
|
|
274
|
+
* хранилище для экземпляров @tinkoff/request
|
|
275
|
+
*
|
|
276
|
+
* требуется хранить экземпляры в единственном виде,
|
|
277
|
+
* т.к. многие плагины @tinkoff/request после инициализации имеют состояние
|
|
278
|
+
* (cache, circuit breaker), и не будут корректно работать на сервере,
|
|
279
|
+
* если создавать новые экземпляры на Scope.REQUEST
|
|
280
|
+
*/
|
|
281
|
+
core.provide({
|
|
282
|
+
provide: 'makeRequestRegistry',
|
|
283
|
+
scope: core.Scope.SINGLETON,
|
|
284
|
+
useFactory: () => new Map(),
|
|
285
|
+
}),
|
|
286
|
+
/**
|
|
287
|
+
* `CREATE_CACHE_TOKEN` имеет проверку, если токен используется провайдером,
|
|
288
|
+
* который имеет Scope.SINGLETON, то инстанс кэша сохраняется в общее хранилище,
|
|
289
|
+
* и доступен для очистки через `/papi/clear-cache`.
|
|
290
|
+
* Scope.REQUEST игнорируется, т.к. это верная утечка памяти,
|
|
291
|
+
* инстансов кэши было бы неограниченное количество.
|
|
292
|
+
*
|
|
293
|
+
* HTTP клиенты создаются со Scope.REQUEST, но инстансы @tinkoff/request
|
|
294
|
+
* (и соответственно кэшей) создаются только один раз, благодаря `makeRequestRegistry`.
|
|
295
|
+
* это гарантирует отсутствие утечек памяти, поэтому мы обходим проверку
|
|
296
|
+
* на Scope.SINGLETON c помощью обертки `createCacheToken`
|
|
297
|
+
*/
|
|
298
|
+
core.provide({
|
|
299
|
+
provide: createCacheToken,
|
|
300
|
+
scope: core.Scope.SINGLETON,
|
|
301
|
+
useFactory: ({ createCache }) => {
|
|
302
|
+
return createCache;
|
|
303
|
+
},
|
|
304
|
+
deps: {
|
|
305
|
+
createCache: tokensCommon.CREATE_CACHE_TOKEN,
|
|
306
|
+
},
|
|
307
|
+
}),
|
|
308
|
+
core.provide({
|
|
309
|
+
provide: tokensHttpClient.API_CLIENT_PASS_HEADERS,
|
|
310
|
+
useValue: ['x-request-id'],
|
|
311
|
+
}),
|
|
312
|
+
];
|
|
313
|
+
|
|
314
|
+
const HttpClientModule = /* @__PURE__ */ core.declareModule({
|
|
315
|
+
name: 'HttpClientModule',
|
|
316
|
+
imports: [PapiClientModule],
|
|
317
|
+
providers: [
|
|
318
|
+
...providers,
|
|
319
|
+
// we can't separate this module to browser and server files through "browser"
|
|
320
|
+
// package.json field, because jest not supports this field resolving out of the box
|
|
321
|
+
// and many unit tests rely on jsdom environment and fails because of resolving to server version
|
|
322
|
+
// TODO: separate jest preset for jsdom unit tests with custom resolver to support "browser" field
|
|
323
|
+
// @see https://github.com/marko-js/jest/blob/main/src/preset/browser/jest-preset.ts
|
|
324
|
+
...(typeof window === 'undefined'
|
|
325
|
+
? [
|
|
326
|
+
core.provide({
|
|
327
|
+
provide: core.commandLineListTokens.init,
|
|
328
|
+
useFactory: ({ agent }) => {
|
|
329
|
+
return () => {
|
|
330
|
+
const { setGlobalDispatcher } = require('undici');
|
|
331
|
+
setGlobalDispatcher(agent.http);
|
|
332
|
+
};
|
|
333
|
+
},
|
|
334
|
+
deps: {
|
|
335
|
+
agent: tokensHttpClient.HTTP_CLIENT_AGENT,
|
|
336
|
+
},
|
|
337
|
+
}),
|
|
338
|
+
core.provide({
|
|
339
|
+
provide: tokensHttpClient.HTTP_CLIENT_AGENT,
|
|
340
|
+
useFactory: ({ options, interceptors }) => {
|
|
341
|
+
const { Agent } = require('undici');
|
|
342
|
+
const agent = new Agent(options).compose(...(interceptors ?? []));
|
|
343
|
+
return {
|
|
344
|
+
http: agent,
|
|
345
|
+
https: agent,
|
|
346
|
+
};
|
|
347
|
+
},
|
|
348
|
+
deps: {
|
|
349
|
+
options: tokensHttpClient.HTTP_CLIENT_AGENT_OPTIONS,
|
|
350
|
+
interceptors: core.optional(tokensHttpClient.HTTP_CLIENT_AGENT_INTERCEPTORS),
|
|
351
|
+
},
|
|
352
|
+
}),
|
|
353
|
+
core.provide({
|
|
354
|
+
provide: tokensHttpClient.HTTP_CLIENT_AGENT_OPTIONS,
|
|
355
|
+
useValue: {},
|
|
356
|
+
}),
|
|
357
|
+
]
|
|
358
|
+
: []),
|
|
317
359
|
],
|
|
318
|
-
})(class HttpClientModule {
|
|
319
360
|
});
|
|
320
361
|
|
|
321
|
-
jest.
|
|
322
|
-
const { Response } = jest.requireActual('node-fetch');
|
|
362
|
+
const fetch = jest.spyOn(require('undici'), 'fetch');
|
|
323
363
|
const testApi = (options) => {
|
|
324
364
|
const caches = [];
|
|
325
365
|
const { modules = [], providers = [], env } = options;
|
|
@@ -337,19 +377,17 @@ const testApi = (options) => {
|
|
|
337
377
|
],
|
|
338
378
|
providers: [...providers],
|
|
339
379
|
});
|
|
340
|
-
const fetchMock =
|
|
380
|
+
const fetchMock = fetch;
|
|
341
381
|
const clearCaches = () => {
|
|
342
382
|
caches.forEach((cache) => cache.clear());
|
|
343
383
|
};
|
|
344
384
|
return {
|
|
345
385
|
di,
|
|
346
386
|
fetchMock,
|
|
347
|
-
mockJsonResponse: async (body,
|
|
387
|
+
mockJsonResponse: async (body, { status, headers } = {}) => {
|
|
348
388
|
clearCaches();
|
|
349
|
-
const { headers = {} } = init;
|
|
350
389
|
fetchMock.mockImplementation(() => Promise.resolve(new Response(JSON.stringify(body), {
|
|
351
|
-
status: 200,
|
|
352
|
-
...init,
|
|
390
|
+
status: status ?? 200,
|
|
353
391
|
headers: {
|
|
354
392
|
'content-type': 'application/json',
|
|
355
393
|
...headers,
|