@webex/http-core 2.59.2 → 2.59.3-next.1

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.
Files changed (43) hide show
  1. package/.eslintrc.js +6 -6
  2. package/README.md +64 -64
  3. package/babel.config.js +3 -3
  4. package/dist/http-error-subtypes.js +57 -57
  5. package/dist/http-error-subtypes.js.map +1 -1
  6. package/dist/http-error.js +25 -25
  7. package/dist/http-error.js.map +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/interceptors/http-status.js +13 -13
  10. package/dist/interceptors/http-status.js.map +1 -1
  11. package/dist/lib/detect.js +6 -6
  12. package/dist/lib/detect.js.map +1 -1
  13. package/dist/lib/interceptor.js +34 -34
  14. package/dist/lib/interceptor.js.map +1 -1
  15. package/dist/lib/xhr.js +2 -2
  16. package/dist/lib/xhr.js.map +1 -1
  17. package/dist/progress-event.js +6 -6
  18. package/dist/progress-event.js.map +1 -1
  19. package/dist/request/index.js +11 -11
  20. package/dist/request/index.js.map +1 -1
  21. package/dist/request/request.js +14 -14
  22. package/dist/request/request.js.map +1 -1
  23. package/dist/request/request.shim.js +65 -65
  24. package/dist/request/request.shim.js.map +1 -1
  25. package/jest.config.js +3 -3
  26. package/package.json +18 -17
  27. package/process +1 -1
  28. package/src/http-error-subtypes.js +187 -187
  29. package/src/http-error.js +147 -147
  30. package/src/index.js +58 -58
  31. package/src/interceptors/http-status.js +63 -63
  32. package/src/lib/detect.js +33 -33
  33. package/src/lib/interceptor.js +95 -95
  34. package/src/lib/xhr.js +258 -258
  35. package/src/progress-event.js +37 -37
  36. package/src/request/index.js +62 -62
  37. package/src/request/request.js +109 -109
  38. package/src/request/request.shim.js +304 -304
  39. package/test/integration/spec/http-error.js +188 -188
  40. package/test/integration/spec/interceptor.js +71 -71
  41. package/test/integration/spec/progress-event.js +83 -83
  42. package/test/integration/spec/request.js +310 -310
  43. package/test/unit/spec/interceptors/http-status.js +49 -49
@@ -1,310 +1,310 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {inBrowser} from '@webex/common';
6
- import {assert} from '@webex/test-helper-chai';
7
- import file from '@webex/test-helper-file';
8
- import {HttpError, request} from '@webex/http-core';
9
- import makeLocalUrl from '@webex/test-helper-make-local-url';
10
- import sinon from 'sinon';
11
- import {flaky, nodeOnly} from '@webex/test-helper-mocha';
12
-
13
- describe('http-core', function () {
14
- this.timeout(30000);
15
- describe('request()', () => {
16
- describe('GET', () => {
17
- it('retrieves html', () =>
18
- request({uri: makeLocalUrl('/')}).then((res) => {
19
- assert.statusCode(res, 200);
20
- assert.isString(res.body);
21
- }));
22
-
23
- it('attaches the request options object to every response', () =>
24
- request(makeLocalUrl('/')).then((res) => {
25
- assert.property(res, 'options');
26
- assert.property(res.options, 'uri');
27
- assert.equal(res.options.uri, makeLocalUrl('/'));
28
- }));
29
-
30
- it('accepts `uri` as a separate parameter from `options`', () =>
31
- request(makeLocalUrl('/')).then((res) => {
32
- assert.statusCode(res, 200);
33
- assert.isString(res.body);
34
- }));
35
-
36
- it('normalizes `options.url` as `options.uri`', () =>
37
- request({url: makeLocalUrl('/')}).then((res) => {
38
- assert.statusCode(res, 200);
39
- assert.isString(res.body);
40
- }));
41
-
42
- it('retrieves JSON', () =>
43
- request({uri: makeLocalUrl('/json/get')}).then((res) => {
44
- assert.statusCode(res, 200);
45
- assert.isObject(res.body);
46
- assert.deepEqual(res.body, {isObject: true});
47
- }));
48
-
49
- it('emits download progress events', () => {
50
- const options = {uri: makeLocalUrl('/sample-image-small-one.png')};
51
- const promise = request(options);
52
- const spy = sinon.spy();
53
-
54
- options.download.on('progress', spy);
55
-
56
- return promise.then(() => {
57
- assert.called(spy);
58
- });
59
- });
60
-
61
- describe('with responseType="buffer"', () => {
62
- it('retrieves a file as a buffer', () =>
63
- request({
64
- uri: makeLocalUrl('/sample-image-small-one.png'),
65
- responseType: 'buffer',
66
- }).then((res) => {
67
- assert.isBufferLike(res.body);
68
- }));
69
- });
70
-
71
- describe('with responseType="blob"', () => {
72
- it('retrieves a file as a file', () =>
73
- request({
74
- uri: makeLocalUrl('/sample-image-small-one.png'),
75
- responseType: 'blob',
76
- }).then((res) => {
77
- assert.isBlobLike(res.body);
78
- }));
79
- });
80
-
81
- it('makes CORS compatible calls', () =>
82
- request({
83
- uri: 'https://ds.ciscospark.com/v1/region/',
84
- }).then((res) => {
85
- assert.notEqual(res.statusCode, 0);
86
- }));
87
-
88
- it('fails with a subtyped error', () =>
89
- assert
90
- .isRejected(
91
- request({
92
- uri: makeLocalUrl('/not-a-route'),
93
- })
94
- )
95
- .then((err) => {
96
- assert.instanceOf(err, HttpError);
97
- assert.instanceOf(err, HttpError.BadRequest);
98
- }));
99
-
100
- // This is somewhat difficult to test in web browser, but network errors in
101
- // browser look like network errors in browsers, so testing it isn`t that
102
- // critical. That said, moving the error-reformatting logic out of the
103
- // environment-specific implementations may make this easier to stub.
104
- nodeOnly(it)('makes network errors look mostly like HTTP errors', () =>
105
- assert.isRejected(request('https://localhost:0/not-a-route')).then((err) => {
106
- assert.instanceOf(err, HttpError.NetworkOrCORSError);
107
- })
108
- );
109
-
110
- it('passes cookies', () =>
111
- request({
112
- uri: makeLocalUrl('/cookies/set'),
113
- jar: true,
114
- })
115
- .then(() =>
116
- request({
117
- uri: makeLocalUrl('/cookies/expect'),
118
- jar: true,
119
- })
120
- )
121
- .then((res) => {
122
- assert.statusCode(res, 200);
123
- }));
124
-
125
- // this test fails in Safari 8+
126
- nodeOnly(it)('passes cookies to endpoints on other origins', () => {
127
- const p1 = request({
128
- uri: `http://localhost:${process.env.CORS_PORT}/cookies/set`,
129
- jar: true,
130
- })
131
- .then(() =>
132
- request({
133
- uri: `http://localhost:${process.env.CORS_PORT}/cookies/expect`,
134
- jar: true,
135
- })
136
- )
137
- .then((res) => {
138
- assert.statusCode(res, 200);
139
- });
140
-
141
- const p2 = request({
142
- uri: `http://localhost:${process.env.CORS_PORT}/cookies/set`,
143
- withCredentials: true,
144
- })
145
- .then(() =>
146
- request({
147
- uri: `http://localhost:${process.env.CORS_PORT}/cookies/expect`,
148
- withCredentials: true,
149
- })
150
- )
151
- .then((res) => {
152
- assert.statusCode(res, 200);
153
- });
154
-
155
- return Promise.all([p1, p2]);
156
- });
157
-
158
- it('makes Basic Auth authenticated requests', () => {
159
- const p1 = request({
160
- uri: makeLocalUrl('/requires-basic-auth'),
161
- auth: {
162
- pass: 'basicpass',
163
- user: 'basicuser',
164
- },
165
- }).then((res) => {
166
- assert.statusCode(res, 200);
167
- });
168
-
169
- const p2 = request({
170
- uri: makeLocalUrl('/requires-basic-auth'),
171
- auth: {
172
- password: 'basicpass',
173
- username: 'basicuser',
174
- },
175
- }).then((res) => {
176
- assert.statusCode(res, 200);
177
- });
178
-
179
- return Promise.all([p1, p2]);
180
- });
181
-
182
- it('makes Bearer Auth authenticated requests', () =>
183
- request({
184
- uri: makeLocalUrl('/requires-bearer-auth'),
185
- auth: {
186
- bearer: 'bearertoken',
187
- },
188
- }).then((res) => {
189
- assert.statusCode(res, 200);
190
- }));
191
-
192
- it('encodes querystring parameters', () => {
193
- // treat all types as strings because that`s how querystrings get parsed
194
- // on the server
195
- const qs = {
196
- string: 'this is a string',
197
- object: {
198
- string: 'this is a another string',
199
- boolean: 'true',
200
- integer: '5',
201
- },
202
- };
203
-
204
- return request({
205
- uri: makeLocalUrl('/return-qs-as-object'),
206
- qs,
207
- }).then((res) => {
208
- assert.deepEqual(res.body, qs);
209
- });
210
- });
211
- });
212
-
213
- flaky(it, process.env.SKIP_FLAKY_TESTS)('submits files as multipart form data', () => {
214
- file.fetch('sample-powerpoint-two-page.ppt').then((f) =>
215
- request({
216
- method: 'POST',
217
- uri: makeLocalUrl('/files/metadata'),
218
- formData: {
219
- files: [f],
220
- },
221
- json: true,
222
- }).then((res) => {
223
- // This asserts that the server received the file and was able to
224
- // decode its filename.
225
- assert.equal(res.body[0].originalname, f.name);
226
- })
227
- );
228
- });
229
-
230
- ['PUT', 'PATCH', 'POST'].forEach((method) => {
231
- describe(method, () => {
232
- it('submits json', () => {
233
- const payload = {
234
- string: 'this is a string',
235
- object: {
236
- string: 'this is a another string',
237
- boolean: 'true',
238
- integer: '5',
239
- },
240
- };
241
-
242
- return request({
243
- method,
244
- uri: makeLocalUrl('/json/set'),
245
- body: payload,
246
- }).then((res) => {
247
- assert.statusCode(res, 200);
248
- assert.deepEqual(res.body, payload);
249
- });
250
- });
251
-
252
- it('submits urlencoded form data', () =>
253
- // treat all types as strings because that`s how querystrings get parsed
254
- // on the server
255
- request({
256
- method,
257
- uri: makeLocalUrl('/form/reflect'),
258
- form: {
259
- a: 1,
260
- b: 2,
261
- },
262
- }).then((res) => {
263
- assert.statusCode(res, 200);
264
- assert.deepEqual(res.body, {
265
- a: '1',
266
- b: '2',
267
- });
268
- }));
269
-
270
- it('submits files', () =>
271
- file.fetch('/sample-image-small-one.png').then((f) =>
272
- request({
273
- method,
274
- uri: makeLocalUrl('/files/reflect'),
275
- body: f,
276
- json: false,
277
- // Note: setting response type so the `reflect()ed` response is in
278
- // a form we can use, this is not needed for normal file uploads.
279
- responseType: 'blob',
280
- }).then((res) => {
281
- assert.equal(res.body.type, f.type);
282
-
283
- return file.isMatchingFile(res.body, f).then((result) => assert.isTrue(result));
284
- })
285
- ));
286
-
287
- (inBrowser ? it : it.skip)('emits upload progress events', () =>
288
- file.fetch('/sample-image-small-one.png').then((f) => {
289
- const options = {
290
- method,
291
- uri: makeLocalUrl('/files/reflect'),
292
- body: f,
293
- json: false,
294
- };
295
-
296
- const promise = request(options);
297
-
298
- const spy = sinon.spy();
299
-
300
- options.upload.on('progress', spy);
301
-
302
- return promise.then(() => {
303
- assert.called(spy);
304
- });
305
- })
306
- );
307
- });
308
- });
309
- });
310
- });
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {inBrowser} from '@webex/common';
6
+ import {assert} from '@webex/test-helper-chai';
7
+ import file from '@webex/test-helper-file';
8
+ import {HttpError, request} from '@webex/http-core';
9
+ import makeLocalUrl from '@webex/test-helper-make-local-url';
10
+ import sinon from 'sinon';
11
+ import {flaky, nodeOnly} from '@webex/test-helper-mocha';
12
+
13
+ describe('http-core', function () {
14
+ this.timeout(30000);
15
+ describe('request()', () => {
16
+ describe('GET', () => {
17
+ it('retrieves html', () =>
18
+ request({uri: makeLocalUrl('/')}).then((res) => {
19
+ assert.statusCode(res, 200);
20
+ assert.isString(res.body);
21
+ }));
22
+
23
+ it('attaches the request options object to every response', () =>
24
+ request(makeLocalUrl('/')).then((res) => {
25
+ assert.property(res, 'options');
26
+ assert.property(res.options, 'uri');
27
+ assert.equal(res.options.uri, makeLocalUrl('/'));
28
+ }));
29
+
30
+ it('accepts `uri` as a separate parameter from `options`', () =>
31
+ request(makeLocalUrl('/')).then((res) => {
32
+ assert.statusCode(res, 200);
33
+ assert.isString(res.body);
34
+ }));
35
+
36
+ it('normalizes `options.url` as `options.uri`', () =>
37
+ request({url: makeLocalUrl('/')}).then((res) => {
38
+ assert.statusCode(res, 200);
39
+ assert.isString(res.body);
40
+ }));
41
+
42
+ it('retrieves JSON', () =>
43
+ request({uri: makeLocalUrl('/json/get')}).then((res) => {
44
+ assert.statusCode(res, 200);
45
+ assert.isObject(res.body);
46
+ assert.deepEqual(res.body, {isObject: true});
47
+ }));
48
+
49
+ it('emits download progress events', () => {
50
+ const options = {uri: makeLocalUrl('/sample-image-small-one.png')};
51
+ const promise = request(options);
52
+ const spy = sinon.spy();
53
+
54
+ options.download.on('progress', spy);
55
+
56
+ return promise.then(() => {
57
+ assert.called(spy);
58
+ });
59
+ });
60
+
61
+ describe('with responseType="buffer"', () => {
62
+ it('retrieves a file as a buffer', () =>
63
+ request({
64
+ uri: makeLocalUrl('/sample-image-small-one.png'),
65
+ responseType: 'buffer',
66
+ }).then((res) => {
67
+ assert.isBufferLike(res.body);
68
+ }));
69
+ });
70
+
71
+ describe('with responseType="blob"', () => {
72
+ it('retrieves a file as a file', () =>
73
+ request({
74
+ uri: makeLocalUrl('/sample-image-small-one.png'),
75
+ responseType: 'blob',
76
+ }).then((res) => {
77
+ assert.isBlobLike(res.body);
78
+ }));
79
+ });
80
+
81
+ it('makes CORS compatible calls', () =>
82
+ request({
83
+ uri: 'https://ds.ciscospark.com/v1/region/',
84
+ }).then((res) => {
85
+ assert.notEqual(res.statusCode, 0);
86
+ }));
87
+
88
+ it('fails with a subtyped error', () =>
89
+ assert
90
+ .isRejected(
91
+ request({
92
+ uri: makeLocalUrl('/not-a-route'),
93
+ })
94
+ )
95
+ .then((err) => {
96
+ assert.instanceOf(err, HttpError);
97
+ assert.instanceOf(err, HttpError.BadRequest);
98
+ }));
99
+
100
+ // This is somewhat difficult to test in web browser, but network errors in
101
+ // browser look like network errors in browsers, so testing it isn`t that
102
+ // critical. That said, moving the error-reformatting logic out of the
103
+ // environment-specific implementations may make this easier to stub.
104
+ nodeOnly(it)('makes network errors look mostly like HTTP errors', () =>
105
+ assert.isRejected(request('https://localhost:0/not-a-route')).then((err) => {
106
+ assert.instanceOf(err, HttpError.NetworkOrCORSError);
107
+ })
108
+ );
109
+
110
+ it('passes cookies', () =>
111
+ request({
112
+ uri: makeLocalUrl('/cookies/set'),
113
+ jar: true,
114
+ })
115
+ .then(() =>
116
+ request({
117
+ uri: makeLocalUrl('/cookies/expect'),
118
+ jar: true,
119
+ })
120
+ )
121
+ .then((res) => {
122
+ assert.statusCode(res, 200);
123
+ }));
124
+
125
+ // this test fails in Safari 8+
126
+ nodeOnly(it)('passes cookies to endpoints on other origins', () => {
127
+ const p1 = request({
128
+ uri: `http://localhost:${process.env.CORS_PORT}/cookies/set`,
129
+ jar: true,
130
+ })
131
+ .then(() =>
132
+ request({
133
+ uri: `http://localhost:${process.env.CORS_PORT}/cookies/expect`,
134
+ jar: true,
135
+ })
136
+ )
137
+ .then((res) => {
138
+ assert.statusCode(res, 200);
139
+ });
140
+
141
+ const p2 = request({
142
+ uri: `http://localhost:${process.env.CORS_PORT}/cookies/set`,
143
+ withCredentials: true,
144
+ })
145
+ .then(() =>
146
+ request({
147
+ uri: `http://localhost:${process.env.CORS_PORT}/cookies/expect`,
148
+ withCredentials: true,
149
+ })
150
+ )
151
+ .then((res) => {
152
+ assert.statusCode(res, 200);
153
+ });
154
+
155
+ return Promise.all([p1, p2]);
156
+ });
157
+
158
+ it('makes Basic Auth authenticated requests', () => {
159
+ const p1 = request({
160
+ uri: makeLocalUrl('/requires-basic-auth'),
161
+ auth: {
162
+ pass: 'basicpass',
163
+ user: 'basicuser',
164
+ },
165
+ }).then((res) => {
166
+ assert.statusCode(res, 200);
167
+ });
168
+
169
+ const p2 = request({
170
+ uri: makeLocalUrl('/requires-basic-auth'),
171
+ auth: {
172
+ password: 'basicpass',
173
+ username: 'basicuser',
174
+ },
175
+ }).then((res) => {
176
+ assert.statusCode(res, 200);
177
+ });
178
+
179
+ return Promise.all([p1, p2]);
180
+ });
181
+
182
+ it('makes Bearer Auth authenticated requests', () =>
183
+ request({
184
+ uri: makeLocalUrl('/requires-bearer-auth'),
185
+ auth: {
186
+ bearer: 'bearertoken',
187
+ },
188
+ }).then((res) => {
189
+ assert.statusCode(res, 200);
190
+ }));
191
+
192
+ it('encodes querystring parameters', () => {
193
+ // treat all types as strings because that`s how querystrings get parsed
194
+ // on the server
195
+ const qs = {
196
+ string: 'this is a string',
197
+ object: {
198
+ string: 'this is a another string',
199
+ boolean: 'true',
200
+ integer: '5',
201
+ },
202
+ };
203
+
204
+ return request({
205
+ uri: makeLocalUrl('/return-qs-as-object'),
206
+ qs,
207
+ }).then((res) => {
208
+ assert.deepEqual(res.body, qs);
209
+ });
210
+ });
211
+ });
212
+
213
+ flaky(it, process.env.SKIP_FLAKY_TESTS)('submits files as multipart form data', () => {
214
+ file.fetch('sample-powerpoint-two-page.ppt').then((f) =>
215
+ request({
216
+ method: 'POST',
217
+ uri: makeLocalUrl('/files/metadata'),
218
+ formData: {
219
+ files: [f],
220
+ },
221
+ json: true,
222
+ }).then((res) => {
223
+ // This asserts that the server received the file and was able to
224
+ // decode its filename.
225
+ assert.equal(res.body[0].originalname, f.name);
226
+ })
227
+ );
228
+ });
229
+
230
+ ['PUT', 'PATCH', 'POST'].forEach((method) => {
231
+ describe(method, () => {
232
+ it('submits json', () => {
233
+ const payload = {
234
+ string: 'this is a string',
235
+ object: {
236
+ string: 'this is a another string',
237
+ boolean: 'true',
238
+ integer: '5',
239
+ },
240
+ };
241
+
242
+ return request({
243
+ method,
244
+ uri: makeLocalUrl('/json/set'),
245
+ body: payload,
246
+ }).then((res) => {
247
+ assert.statusCode(res, 200);
248
+ assert.deepEqual(res.body, payload);
249
+ });
250
+ });
251
+
252
+ it('submits urlencoded form data', () =>
253
+ // treat all types as strings because that`s how querystrings get parsed
254
+ // on the server
255
+ request({
256
+ method,
257
+ uri: makeLocalUrl('/form/reflect'),
258
+ form: {
259
+ a: 1,
260
+ b: 2,
261
+ },
262
+ }).then((res) => {
263
+ assert.statusCode(res, 200);
264
+ assert.deepEqual(res.body, {
265
+ a: '1',
266
+ b: '2',
267
+ });
268
+ }));
269
+
270
+ it('submits files', () =>
271
+ file.fetch('/sample-image-small-one.png').then((f) =>
272
+ request({
273
+ method,
274
+ uri: makeLocalUrl('/files/reflect'),
275
+ body: f,
276
+ json: false,
277
+ // Note: setting response type so the `reflect()ed` response is in
278
+ // a form we can use, this is not needed for normal file uploads.
279
+ responseType: 'blob',
280
+ }).then((res) => {
281
+ assert.equal(res.body.type, f.type);
282
+
283
+ return file.isMatchingFile(res.body, f).then((result) => assert.isTrue(result));
284
+ })
285
+ ));
286
+
287
+ (inBrowser ? it : it.skip)('emits upload progress events', () =>
288
+ file.fetch('/sample-image-small-one.png').then((f) => {
289
+ const options = {
290
+ method,
291
+ uri: makeLocalUrl('/files/reflect'),
292
+ body: f,
293
+ json: false,
294
+ };
295
+
296
+ const promise = request(options);
297
+
298
+ const spy = sinon.spy();
299
+
300
+ options.upload.on('progress', spy);
301
+
302
+ return promise.then(() => {
303
+ assert.called(spy);
304
+ });
305
+ })
306
+ );
307
+ });
308
+ });
309
+ });
310
+ });