particle-api-js 9.4.1 → 10.1.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/.circleci/config.yml +7 -5
- package/CHANGELOG.md +11 -0
- package/{test/EventStream-e2e-browser.html → EventStream-e2e-browser.html} +0 -1
- package/{test/EventStream-e2e-node.js → EventStream-e2e-node.js} +2 -3
- package/README.md +2 -2
- package/RELEASE.md +1 -1
- package/dist/particle.min.js +1 -399
- package/dist/particle.min.js.map +1 -1
- package/docs/api.md +5223 -115
- package/fs.js +2 -0
- package/karma.conf.js +18 -6
- package/package.json +23 -26
- package/src/Agent.js +407 -0
- package/src/Client.js +170 -0
- package/src/Defaults.js +7 -0
- package/src/EventStream.js +263 -0
- package/src/Library.js +33 -0
- package/src/Particle.js +2644 -0
- package/test/Agent.integration.js +5 -4
- package/test/Agent.spec.js +174 -291
- package/test/Client.spec.js +7 -7
- package/test/Defaults.spec.js +2 -2
- package/test/EventStream.spec.js +6 -4
- package/test/FakeAgent.js +2 -2
- package/test/Library.spec.js +2 -2
- package/test/Particle.integration.js +7 -7
- package/test/Particle.spec.js +332 -18
- package/test/fixtures/index.js +4 -18
- package/test/support/FixtureHttpServer.js +5 -3
- package/test/test-setup.js +5 -5
- package/tsconfig.json +14 -0
- package/webpack.config.js +45 -0
- package/.babelrc +0 -4
- package/lib/Agent.js +0 -516
- package/lib/Agent.js.map +0 -1
- package/lib/Client.js +0 -312
- package/lib/Client.js.map +0 -1
- package/lib/Defaults.js +0 -14
- package/lib/Defaults.js.map +0 -1
- package/lib/EventStream.js +0 -335
- package/lib/EventStream.js.map +0 -1
- package/lib/Library.js +0 -67
- package/lib/Library.js.map +0 -1
- package/lib/Particle.js +0 -3248
- package/lib/Particle.js.map +0 -1
- package/lib/superagent-binary-parser.js +0 -20
- package/lib/superagent-binary-parser.js.map +0 -1
- package/test/Client.integration.js +0 -69
- package/test/fixtures/tarball.tar.gz +0 -0
- package/test/fixtures/test-library-publish-0.0.1.tar.gz +0 -0
- package/test/fixtures/test-library-publish-0.0.2.tar.gz +0 -0
|
@@ -21,13 +21,14 @@
|
|
|
21
21
|
* Tests for real the Agent class using an external service.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const { expect } = require('./test-setup');
|
|
25
|
+
const Agent = require('../src/Agent');
|
|
27
26
|
|
|
28
27
|
describe('Agent', () => {
|
|
29
28
|
if (!process.env.SKIP_AGENT_TEST){
|
|
30
|
-
it('can fetch a webpage', ()
|
|
29
|
+
it('can fetch a webpage', function cb() {
|
|
30
|
+
this.retries(5);
|
|
31
|
+
this.timeout(6000);
|
|
31
32
|
const agent = new Agent();
|
|
32
33
|
const query = { a: '1', b: '2' };
|
|
33
34
|
const result = agent.get({ uri: 'http://httpbin.org/get', query });
|
package/test/Agent.spec.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const { sinon, expect } = require('./test-setup');
|
|
2
|
+
const Agent = require('../src/Agent.js');
|
|
3
3
|
|
|
4
4
|
describe('Agent', () => {
|
|
5
5
|
beforeEach(() => {
|
|
@@ -15,14 +15,6 @@ describe('Agent', () => {
|
|
|
15
15
|
expect(agent.setBaseUrl.firstCall.args).to.have.lengthOf(1);
|
|
16
16
|
expect(agent.setBaseUrl.firstCall.args[0]).to.eql(baseUrl);
|
|
17
17
|
});
|
|
18
|
-
|
|
19
|
-
it('creates a prefix function instance property from the supplied baseUrl (via setBaseUrl)', () => {
|
|
20
|
-
const agent = new Agent();
|
|
21
|
-
expect(agent.prefix).to.be.a('Function');
|
|
22
|
-
// Note: validating specific .prefix function behavior seems hard without proxyquire
|
|
23
|
-
// and this test seems sufficient
|
|
24
|
-
// and redundant with the 'build request uses prefix if provided' test below
|
|
25
|
-
});
|
|
26
18
|
});
|
|
27
19
|
|
|
28
20
|
describe('sanitize files', () => {
|
|
@@ -107,25 +99,37 @@ describe('Agent', () => {
|
|
|
107
99
|
});
|
|
108
100
|
|
|
109
101
|
it('authorize no auth is unchanged', () => {
|
|
110
|
-
expect(agent.
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('authorize with credentials', () => {
|
|
114
|
-
const authfn = sinon.spy();
|
|
115
|
-
const req = { auth: authfn };
|
|
116
|
-
const auth = { username: 'me', password: 'pwd' };
|
|
117
|
-
expect(agent._authorizationHeader(req, auth)).to.be.equal(req);
|
|
118
|
-
expect(authfn).to.have.been.calledWith('me', 'pwd');
|
|
102
|
+
expect(agent._getAuthorizationHeader(undefined)).to.eql({});
|
|
119
103
|
});
|
|
120
104
|
|
|
121
105
|
it('authorize with bearer', () => {
|
|
122
106
|
const auth = '123';
|
|
123
107
|
const bearer = 'Bearer 123';
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
expect(agent._authorizationHeader(req, auth)).to.be.equal(req);
|
|
127
|
-
expect(setfn).to.have.been.calledWith({ Authorization: bearer });
|
|
108
|
+
const headers = agent._getAuthorizationHeader(auth);
|
|
109
|
+
expect(headers).to.eql({ Authorization: bearer });
|
|
128
110
|
});
|
|
111
|
+
|
|
112
|
+
if (typeof window !== 'undefined') {
|
|
113
|
+
it('supports auth with user/pass in browsers', () => {
|
|
114
|
+
const auth = {
|
|
115
|
+
username: 'test@particle.io',
|
|
116
|
+
password: 'super_secret'
|
|
117
|
+
};
|
|
118
|
+
const basic = 'Basic dGVzdEBwYXJ0aWNsZS5pbzpzdXBlcl9zZWNyZXQ=';
|
|
119
|
+
const headers = agent._getAuthorizationHeader(auth);
|
|
120
|
+
expect(headers).to.eql({ Authorization: basic });
|
|
121
|
+
});
|
|
122
|
+
} else {
|
|
123
|
+
it('supports auth with user/pass in node', () => {
|
|
124
|
+
const auth = {
|
|
125
|
+
username: 'test@particle.io',
|
|
126
|
+
password: 'super_secret'
|
|
127
|
+
};
|
|
128
|
+
const basic = 'Basic dGVzdEBwYXJ0aWNsZS5pbzpzdXBlcl9zZWNyZXQ=';
|
|
129
|
+
const headers = agent._getAuthorizationHeader(auth);
|
|
130
|
+
expect(headers).to.eql({ Authorization: basic });
|
|
131
|
+
});
|
|
132
|
+
}
|
|
129
133
|
});
|
|
130
134
|
|
|
131
135
|
describe('request', () => {
|
|
@@ -133,8 +137,9 @@ describe('Agent', () => {
|
|
|
133
137
|
|
|
134
138
|
beforeEach(() => {
|
|
135
139
|
agent = new Agent();
|
|
136
|
-
agent.
|
|
137
|
-
agent.
|
|
140
|
+
agent._promiseResponse = sinon.stub();
|
|
141
|
+
agent._promiseResponse.resolves('fake-response');
|
|
142
|
+
agent._buildRequest = sinon.stub();
|
|
138
143
|
agent._sanitizeFiles = sinon.stub();
|
|
139
144
|
});
|
|
140
145
|
|
|
@@ -148,37 +153,16 @@ describe('Agent', () => {
|
|
|
148
153
|
.then((res) => {
|
|
149
154
|
expect(res).to.be.equal('fake-response');
|
|
150
155
|
expect(agent._sanitizeFiles).calledOnce.calledWith(sinon.match.same(files));
|
|
151
|
-
expect(agent._request).calledOnce.calledWith({
|
|
152
|
-
uri: 'abc',
|
|
153
|
-
method: 'post',
|
|
154
|
-
auth: undefined,
|
|
155
|
-
headers: undefined,
|
|
156
|
-
query: 'all',
|
|
157
|
-
data: '123',
|
|
158
|
-
files: sanitizedFiles,
|
|
159
|
-
context: undefined,
|
|
160
|
-
raw: false,
|
|
161
|
-
form
|
|
162
|
-
});
|
|
163
156
|
});
|
|
164
157
|
});
|
|
165
158
|
|
|
166
159
|
it('uses default arguments for request', () => {
|
|
160
|
+
const args = ['abc', { args: '123' }];
|
|
161
|
+
agent._buildRequest.returns(args);
|
|
167
162
|
return agent.request({ uri: 'abc', method:'post' })
|
|
168
163
|
.then((res) => {
|
|
169
164
|
expect(res).to.be.equal('fake-response');
|
|
170
|
-
expect(agent.
|
|
171
|
-
uri: 'abc',
|
|
172
|
-
method:'post',
|
|
173
|
-
auth: undefined,
|
|
174
|
-
headers: undefined,
|
|
175
|
-
data: undefined,
|
|
176
|
-
files: undefined,
|
|
177
|
-
form: undefined,
|
|
178
|
-
query: undefined,
|
|
179
|
-
context: undefined,
|
|
180
|
-
raw: false
|
|
181
|
-
});
|
|
165
|
+
expect(agent._promiseResponse).calledOnce.calledWith(args);
|
|
182
166
|
});
|
|
183
167
|
});
|
|
184
168
|
|
|
@@ -200,7 +184,7 @@ describe('Agent', () => {
|
|
|
200
184
|
agent._promiseResponse = sinon.stub();
|
|
201
185
|
agent._promiseResponse.resolves('fake-response');
|
|
202
186
|
|
|
203
|
-
return agent.
|
|
187
|
+
return agent.request(options).then((res) => {
|
|
204
188
|
expect(res).to.be.equal('fake-response');
|
|
205
189
|
expect(agent._buildRequest).calledOnce;
|
|
206
190
|
expect(agent._buildRequest).calledWith(options);
|
|
@@ -209,22 +193,65 @@ describe('Agent', () => {
|
|
|
209
193
|
});
|
|
210
194
|
});
|
|
211
195
|
|
|
212
|
-
it('builds a promise to call
|
|
196
|
+
it('builds a promise to call _promiseResponse', () => {
|
|
213
197
|
const agent = new Agent();
|
|
214
198
|
const req = sinon.stub();
|
|
215
|
-
const response =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
199
|
+
const response = {
|
|
200
|
+
ok: true,
|
|
201
|
+
status: 200,
|
|
202
|
+
json: () => Promise.resolve('response')
|
|
203
|
+
};
|
|
204
|
+
req.resolves(response);
|
|
205
|
+
const promise = agent._promiseResponse([], false, req);
|
|
221
206
|
expect(promise).has.property('then');
|
|
222
|
-
return promise.then((
|
|
223
|
-
expect(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
207
|
+
return promise.then((resp) => {
|
|
208
|
+
expect(resp).to.be.eql({
|
|
209
|
+
body: 'response',
|
|
210
|
+
statusCode: 200
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('can handle error responses', () => {
|
|
216
|
+
const failResponseData = [
|
|
217
|
+
{
|
|
218
|
+
name: 'error text includes body error description',
|
|
219
|
+
response: {
|
|
220
|
+
status: 404,
|
|
221
|
+
statusText: 'file not found',
|
|
222
|
+
text: () => Promise.resolve('{"error_description": "file not found"}')
|
|
223
|
+
},
|
|
224
|
+
errorDescription: 'HTTP error 404 from 123.url - file not found'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'error text with no body description',
|
|
228
|
+
response: {
|
|
229
|
+
status: 404,
|
|
230
|
+
text: () => Promise.resolve(''),
|
|
231
|
+
},
|
|
232
|
+
errorDescription: 'HTTP error 404 from 123.url'
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: 'error text with no status',
|
|
236
|
+
response: {},
|
|
237
|
+
errorDescription: 'Network error from 123.url'
|
|
238
|
+
}
|
|
239
|
+
];
|
|
240
|
+
const agent = new Agent();
|
|
241
|
+
const req = sinon.stub();
|
|
242
|
+
const requests = failResponseData.map((failData) => {
|
|
243
|
+
const response = Object.assign({
|
|
244
|
+
ok: false
|
|
245
|
+
}, failData.response);
|
|
246
|
+
req.resolves(response);
|
|
247
|
+
const promise = agent._promiseResponse(['123.url'] , false, req);
|
|
248
|
+
return promise.catch((resp) => {
|
|
249
|
+
expect(resp.statusCode).to.eql(failData.response.status);
|
|
250
|
+
expect(resp.errorDescription).to.eql(failData.errorDescription);
|
|
251
|
+
expect(resp.shortErrorDescription).to.eql(failData.response.statusText);
|
|
252
|
+
});
|
|
227
253
|
});
|
|
254
|
+
return Promise.all(requests);
|
|
228
255
|
});
|
|
229
256
|
});
|
|
230
257
|
|
|
@@ -232,136 +259,80 @@ describe('Agent', () => {
|
|
|
232
259
|
let agent;
|
|
233
260
|
|
|
234
261
|
beforeEach(() => {
|
|
235
|
-
agent = new Agent();
|
|
262
|
+
agent = new Agent('abc');
|
|
236
263
|
});
|
|
237
264
|
|
|
238
|
-
it('uses
|
|
239
|
-
agent.
|
|
240
|
-
|
|
241
|
-
const req = sinon.stub();
|
|
242
|
-
req.returns({ use: use });
|
|
243
|
-
const result = agent._buildRequest({ uri: 'uri', method: 'get', makerequest: req });
|
|
244
|
-
expect(result).to.be.ok;
|
|
245
|
-
expect(req).to.be.calledWith('get', 'uri');
|
|
246
|
-
expect(use).to.be.calledWith('abc');
|
|
265
|
+
it('uses a baseURL if provided', () => {
|
|
266
|
+
const [uri] = agent._buildRequest({ uri: '/uri', method: 'get' });
|
|
267
|
+
expect(uri).to.equal('abc/uri');
|
|
247
268
|
});
|
|
248
269
|
|
|
249
|
-
it('
|
|
250
|
-
agent.
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
req.returns({ use: use });
|
|
254
|
-
const result = agent._buildRequest({ uri: 'uri', method: 'get', makerequest: req });
|
|
255
|
-
expect(result).to.be.ok;
|
|
256
|
-
expect(req).to.be.calledWith('get', 'uri');
|
|
257
|
-
expect(use).to.not.have.been.called;
|
|
270
|
+
it('uses the provided uri if no baseURL is provided', () => {
|
|
271
|
+
agent.setBaseUrl(undefined);
|
|
272
|
+
const [uri] = agent._buildRequest({ uri: 'uri', method: 'get' });
|
|
273
|
+
expect(uri).to.equal('uri');
|
|
258
274
|
});
|
|
259
275
|
|
|
260
|
-
it('
|
|
261
|
-
|
|
262
|
-
agent.
|
|
263
|
-
|
|
264
|
-
const context = { foo: {} };
|
|
265
|
-
const req = sinon.stub().returns(request);
|
|
266
|
-
agent._buildRequest({ uri: 'uri', method: 'get', context, makerequest: req });
|
|
267
|
-
expect(agent._applyContext).to.be.calledWith(sinon.match.same(request), sinon.match.same(context));
|
|
276
|
+
it('generates context headers when one is provided', () => {
|
|
277
|
+
const context = { tool: { name: 'spanner' } };
|
|
278
|
+
const [, opts] = agent._buildRequest({ uri: '/uri', method: 'get', context });
|
|
279
|
+
expect(opts.headers).to.have.property('X-Particle-Tool', 'spanner');
|
|
268
280
|
});
|
|
269
281
|
|
|
270
|
-
it('
|
|
271
|
-
|
|
272
|
-
agent.
|
|
273
|
-
|
|
274
|
-
const req = sinon.stub().returns(request);
|
|
275
|
-
agent._buildRequest({ uri: 'uri', method: 'get', makerequest: req });
|
|
276
|
-
expect(agent._applyContext).to.not.be.called;
|
|
282
|
+
it('generates auth headers when an auth token is provided', () => {
|
|
283
|
+
const auth = 'abcd-1235';
|
|
284
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get', auth });
|
|
285
|
+
expect(opts.headers).to.have.property('Authorization', `Bearer ${auth}`);
|
|
277
286
|
});
|
|
278
287
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
agent.
|
|
282
|
-
|
|
283
|
-
const req = sinon.stub();
|
|
284
|
-
req.returns(request);
|
|
285
|
-
const authorize = sinon.stub();
|
|
286
|
-
agent._authorizationHeader = authorize;
|
|
287
|
-
agent._buildRequest({ uri: 'uri', method: 'get', auth: '123', makerequest: req });
|
|
288
|
-
expect(authorize).to.be.calledWith(sinon.match.same(request), '123');
|
|
288
|
+
it('adds new query params with the given query object', () => {
|
|
289
|
+
const query = { foo: 1, bar: 2 };
|
|
290
|
+
const [uri] = agent._buildRequest({ uri: '/uri', method: 'get', query });
|
|
291
|
+
expect(uri).to.equal('abc/uri?foo=1&bar=2');
|
|
289
292
|
});
|
|
290
293
|
|
|
291
|
-
it('
|
|
292
|
-
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
req.returns({ query: query, authorize: sinon.stub() });
|
|
296
|
-
agent._buildRequest({ uri: 'uri', method: 'get', query: '123', makerequest: req });
|
|
297
|
-
expect(query).to.be.calledWith('123');
|
|
294
|
+
it('adds query params without colliding with existing ones', () => {
|
|
295
|
+
const query = { foo: 1, bar: 2 };
|
|
296
|
+
const [uri] = agent._buildRequest({ uri: '/uri?test=true', method: 'get', query });
|
|
297
|
+
expect(uri).to.equal('abc/uri?test=true&foo=1&bar=2');
|
|
298
298
|
});
|
|
299
299
|
|
|
300
|
-
it('
|
|
301
|
-
agent.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
req.returns({ query: query, _authorizationHeader: sinon.stub() });
|
|
305
|
-
agent._buildRequest({ uri: 'uri', method: 'get', makerequest: req });
|
|
306
|
-
expect(query).to.be.not.been.called;
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
it('should invoke send when data given', () => {
|
|
310
|
-
agent.prefix = undefined;
|
|
311
|
-
const req = sinon.stub();
|
|
312
|
-
const send = sinon.stub();
|
|
313
|
-
req.returns({ send: send });
|
|
314
|
-
agent._buildRequest({ uri: 'uri', method: 'get', data: 'abcd', makerequest: req });
|
|
315
|
-
expect(send).to.be.calledWith('abcd');
|
|
300
|
+
it('adds the provided data as a JSON request body', () => {
|
|
301
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get', data: { a: 'abcd' } });
|
|
302
|
+
expect(opts.body).to.eql('{"a":"abcd"}');
|
|
303
|
+
expect(opts.headers).to.have.property('Content-Type', 'application/json');
|
|
316
304
|
});
|
|
317
305
|
|
|
318
306
|
it('should setup form send when form data is given', () => {
|
|
319
|
-
agent.
|
|
320
|
-
|
|
321
|
-
const send = sinon.stub();
|
|
322
|
-
const type = sinon.stub();
|
|
323
|
-
req.returns({ send: send, type: type });
|
|
324
|
-
agent._buildRequest({ uri: 'uri', method: 'get', form: 'abcd', makerequest: req });
|
|
325
|
-
expect(send).to.be.calledWith('abcd');
|
|
326
|
-
expect(type).to.be.calledWith('form');
|
|
307
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get', form: { a: 'abcd' } });
|
|
308
|
+
expect(opts.body).to.eql('a=abcd');
|
|
327
309
|
});
|
|
328
310
|
|
|
329
311
|
it('should attach files', () => {
|
|
330
|
-
agent.prefix = undefined;
|
|
331
|
-
const req = sinon.stub();
|
|
332
|
-
const attach = sinon.stub();
|
|
333
|
-
req.returns({ attach: attach });
|
|
334
312
|
const files = {
|
|
335
|
-
file: { data: 'filedata', path: 'filepath' },
|
|
336
|
-
file2: { data: 'file2data', path: 'file2path' }
|
|
313
|
+
file: { data: makeFile('filedata'), path: 'filepath' },
|
|
314
|
+
file2: { data: makeFile('file2data'), path: 'file2path' }
|
|
337
315
|
};
|
|
338
|
-
agent._buildRequest({ uri: 'uri', method: 'get', files
|
|
339
|
-
expect(
|
|
340
|
-
expect(
|
|
341
|
-
expect(
|
|
316
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get', files });
|
|
317
|
+
expect(opts.body.toString()).to.equal('[object FormData]');
|
|
318
|
+
expect(extractFilename(opts.body, 'file', 0)).to.eql('filepath');
|
|
319
|
+
expect(extractFilename(opts.body, 'file2', 3)).to.eql('file2path');
|
|
320
|
+
expect(opts.headers).to.not.have.property('Content-Type');
|
|
342
321
|
});
|
|
343
322
|
|
|
344
323
|
it('should attach files and form data', () => {
|
|
345
|
-
agent.prefix = undefined;
|
|
346
|
-
const req = sinon.stub();
|
|
347
|
-
const attach = sinon.stub();
|
|
348
|
-
const field = sinon.stub();
|
|
349
|
-
req.returns({
|
|
350
|
-
attach: attach,
|
|
351
|
-
field: field
|
|
352
|
-
});
|
|
353
324
|
const files = {
|
|
354
|
-
file: { data: 'filedata', path: 'filepath' },
|
|
355
|
-
file2: { data: 'file2data', path: 'file2path' }
|
|
325
|
+
file: { data: makeFile('filedata'), path: 'filepath' },
|
|
326
|
+
file2: { data: makeFile('file2data'), path: 'file2path' }
|
|
356
327
|
};
|
|
357
328
|
const form = { form1: 'value1', form2: 'value2' };
|
|
358
|
-
agent._buildRequest({ uri: 'uri', method: 'get', files
|
|
359
|
-
expect(
|
|
360
|
-
expect(
|
|
361
|
-
expect(
|
|
362
|
-
expect(
|
|
363
|
-
expect(
|
|
364
|
-
expect(
|
|
329
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get', files, form });
|
|
330
|
+
expect(opts.body.toString()).to.equal('[object FormData]');
|
|
331
|
+
expect(extractFilename(opts.body, 'file', 0)).to.eql('filepath');
|
|
332
|
+
expect(extractFilename(opts.body, 'file2', 3)).to.eql('file2path');
|
|
333
|
+
expect(extractFormName(opts.body, 'form1', 6, true)).to.eql('value1');
|
|
334
|
+
expect(extractFormName(opts.body, 'form2', 9, true)).to.eql('value2');
|
|
335
|
+
expect(opts.headers).to.not.have.property('Content-Type');
|
|
365
336
|
});
|
|
366
337
|
|
|
367
338
|
it('should handle nested dirs', () => {
|
|
@@ -369,9 +340,14 @@ describe('Agent', () => {
|
|
|
369
340
|
file: { data: makeFile('filedata'), path: 'filepath.ino' },
|
|
370
341
|
file2: { data: makeFile('file2data'), path: 'dir/file2path.cpp' }
|
|
371
342
|
};
|
|
372
|
-
const
|
|
373
|
-
expect(extractFilename(
|
|
374
|
-
expect(extractFilename(
|
|
343
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get', files });
|
|
344
|
+
expect(extractFilename(opts.body, 'file', 0)).to.eql('filepath.ino');
|
|
345
|
+
expect(extractFilename(opts.body, 'file2', 3)).to.eql('dir/file2path.cpp');
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('sets the user agent to particle-api-js', () => {
|
|
349
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get' });
|
|
350
|
+
expect(opts.headers).to.have.property('User-Agent').that.match(/^particle-api-js/);
|
|
375
351
|
});
|
|
376
352
|
|
|
377
353
|
if (!inBrowser()){
|
|
@@ -379,8 +355,8 @@ describe('Agent', () => {
|
|
|
379
355
|
const files = {
|
|
380
356
|
file: { data: makeFile('filedata'), path: 'dir\\windowsfilepath.cpp' }
|
|
381
357
|
};
|
|
382
|
-
const
|
|
383
|
-
expect(extractFilename(
|
|
358
|
+
const [, opts] = agent._buildRequest({ uri: 'uri', method: 'get', files });
|
|
359
|
+
expect(extractFilename(opts.body, 'file', 0)).to.eql('dir/windowsfilepath.cpp');
|
|
384
360
|
});
|
|
385
361
|
}
|
|
386
362
|
|
|
@@ -403,93 +379,13 @@ describe('Agent', () => {
|
|
|
403
379
|
return /filename="([^"]*)"/.exec(formData._streams[fieldIndex])[1];
|
|
404
380
|
}
|
|
405
381
|
}
|
|
406
|
-
});
|
|
407
382
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const request = {
|
|
415
|
-
end: function end(callback){
|
|
416
|
-
callback(undefined, response);
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
const end = sinon.spy(request, 'end');
|
|
420
|
-
|
|
421
|
-
const agent = new Agent();
|
|
422
|
-
const result = agent._sendRequest(request, fulfill, reject);
|
|
423
|
-
expect(result).to.be.undefined;
|
|
424
|
-
expect(end).to.be.calledOnce;
|
|
425
|
-
|
|
426
|
-
expect(fulfill).to.be.calledOnce;
|
|
427
|
-
// not called with response directly but with an object that is equivalent
|
|
428
|
-
expect(fulfill).to.be.calledWith(response);
|
|
429
|
-
expect(reject).to.not.be.called;
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
const failResponseData = [
|
|
433
|
-
{
|
|
434
|
-
name: 'error text includes body error description',
|
|
435
|
-
response: {
|
|
436
|
-
body: {
|
|
437
|
-
error_description: 'file not found'
|
|
438
|
-
}
|
|
439
|
-
},
|
|
440
|
-
error: { status: 404 },
|
|
441
|
-
errorDescription: 'HTTP error 404 from 123.url - file not found'
|
|
442
|
-
},
|
|
443
|
-
|
|
444
|
-
{
|
|
445
|
-
name: 'error text with no body description',
|
|
446
|
-
response: { body: {} },
|
|
447
|
-
error: { status: 404 },
|
|
448
|
-
errorDescription: 'HTTP error 404 from 123.url'
|
|
449
|
-
},
|
|
450
|
-
|
|
451
|
-
{
|
|
452
|
-
name: 'error text with no body',
|
|
453
|
-
response: { },
|
|
454
|
-
error: { status: 404 },
|
|
455
|
-
errorDescription: 'HTTP error 404 from 123.url'
|
|
456
|
-
},
|
|
457
|
-
|
|
458
|
-
{
|
|
459
|
-
name: 'error text with no response',
|
|
460
|
-
error: { status: 404 },
|
|
461
|
-
errorDescription: 'HTTP error 404 from 123.url' },
|
|
462
|
-
|
|
463
|
-
{
|
|
464
|
-
name: 'error text with no status',
|
|
465
|
-
error: {},
|
|
466
|
-
errorDescription: 'Network error from 123.url'
|
|
383
|
+
function extractFormName(formData, fieldName, fieldIndex){
|
|
384
|
+
if (inBrowser()){
|
|
385
|
+
return formData.get(fieldName);
|
|
386
|
+
} else {
|
|
387
|
+
return formData._streams[fieldIndex + 1];
|
|
467
388
|
}
|
|
468
|
-
];
|
|
469
|
-
for (let failData of failResponseData){
|
|
470
|
-
it(`can retrieve an error response - ${failData.name}`, () => {
|
|
471
|
-
const fulfill = sinon.stub();
|
|
472
|
-
const reject = sinon.stub();
|
|
473
|
-
|
|
474
|
-
const request = {
|
|
475
|
-
url: '123.url', end: function end(callback){
|
|
476
|
-
callback(failData.error, failData.response);
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
const end = sinon.spy(request, 'end');
|
|
480
|
-
|
|
481
|
-
const agent = new Agent();
|
|
482
|
-
const result = agent._sendRequest(request, fulfill, reject);
|
|
483
|
-
expect(result).to.be.undefined;
|
|
484
|
-
expect(end).to.be.calledOnce;
|
|
485
|
-
expect(fulfill).to.not.be.called;
|
|
486
|
-
expect(reject).to.be.calledWithMatch({
|
|
487
|
-
statusCode: failData.error.status,
|
|
488
|
-
errorDescription: failData.errorDescription,
|
|
489
|
-
error:failData.error,
|
|
490
|
-
body:failData.response ? failData.response.body : undefined
|
|
491
|
-
});
|
|
492
|
-
});
|
|
493
389
|
}
|
|
494
390
|
});
|
|
495
391
|
|
|
@@ -514,57 +410,46 @@ describe('Agent', () => {
|
|
|
514
410
|
});
|
|
515
411
|
});
|
|
516
412
|
|
|
517
|
-
describe('
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
beforeEach(() => {
|
|
521
|
-
req = { set: sinon.stub() };
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
it('applies the tool context when defined', () => {
|
|
413
|
+
describe('_getContextHeaders', () => {
|
|
414
|
+
it('generates the tool context when defined', () => {
|
|
525
415
|
const context = { tool: { name: 'spanner' } };
|
|
526
|
-
agent.
|
|
527
|
-
expect(
|
|
528
|
-
expect(req.set).to.have.been.calledWith('X-Particle-Tool', 'spanner');
|
|
416
|
+
const subject = agent._getContextHeaders(context);
|
|
417
|
+
expect(subject).to.have.property('X-Particle-Tool', 'spanner');
|
|
529
418
|
});
|
|
530
419
|
|
|
531
|
-
it('does not
|
|
420
|
+
it('does not add the tool context header when not defined',() => {
|
|
532
421
|
const context = { tool: { name2: 'spanner' } };
|
|
533
|
-
agent.
|
|
534
|
-
expect(
|
|
422
|
+
const subject = agent._getContextHeaders(context);
|
|
423
|
+
expect(subject).to.not.have.property('X-Particle-Tool');
|
|
535
424
|
});
|
|
536
425
|
|
|
537
|
-
it('
|
|
426
|
+
it('generates the project context header when defined',() => {
|
|
538
427
|
const context = { project: { name: 'blinky' } };
|
|
539
|
-
agent.
|
|
540
|
-
expect(
|
|
541
|
-
expect(req.set).to.have.been.calledWith('X-Particle-Project', 'blinky');
|
|
428
|
+
const subject = agent._getContextHeaders(context);
|
|
429
|
+
expect(subject).to.have.property('X-Particle-Project', 'blinky');
|
|
542
430
|
});
|
|
543
431
|
|
|
544
|
-
it('does not
|
|
432
|
+
it('does not generate the project context header when not defined',() => {
|
|
545
433
|
const context = { project: { name2: 'blinky' } };
|
|
546
|
-
agent.
|
|
547
|
-
expect(
|
|
434
|
+
const subject = agent._getContextHeaders(context);
|
|
435
|
+
expect(subject).to.not.have.property('X-Particle-Project');
|
|
548
436
|
});
|
|
549
437
|
});
|
|
550
438
|
|
|
551
|
-
describe('
|
|
439
|
+
describe('_getToolContext', () => {
|
|
552
440
|
it('does not add a header when the tool name is not defined', () => {
|
|
553
|
-
const req = { set: sinon.stub() };
|
|
554
441
|
const tool = { noname: 'cli' };
|
|
555
|
-
agent.
|
|
556
|
-
expect(
|
|
442
|
+
const subject = agent._getToolContext(tool);
|
|
443
|
+
expect(subject).to.eql({});
|
|
557
444
|
});
|
|
558
445
|
|
|
559
446
|
it('adds a header when the tool is defined', () => {
|
|
560
|
-
const req = { set: sinon.stub() };
|
|
561
447
|
const tool = { name: 'cli' };
|
|
562
|
-
agent.
|
|
563
|
-
expect(
|
|
448
|
+
const subject = agent._getToolContext(tool);
|
|
449
|
+
expect(subject).to.eql({ 'X-Particle-Tool': 'cli' });
|
|
564
450
|
});
|
|
565
451
|
|
|
566
452
|
it('adds a header when the tool and components is defined', () => {
|
|
567
|
-
const req = { set: sinon.stub() };
|
|
568
453
|
const tool = {
|
|
569
454
|
name: 'cli',
|
|
570
455
|
version: '1.2.3',
|
|
@@ -573,24 +458,22 @@ describe('Agent', () => {
|
|
|
573
458
|
{ name: 'foo', version: '0.0.1' }
|
|
574
459
|
]
|
|
575
460
|
};
|
|
576
|
-
agent.
|
|
577
|
-
expect(
|
|
461
|
+
const subject = agent._getToolContext(tool);
|
|
462
|
+
expect(subject).to.eql({ 'X-Particle-Tool': 'cli@1.2.3, bar@a.b.c, foo@0.0.1' });
|
|
578
463
|
});
|
|
579
464
|
});
|
|
580
465
|
|
|
581
466
|
describe('_addProjectContext', () => {
|
|
582
467
|
it('adds a header when the project is defined', () => {
|
|
583
|
-
const req = { set: sinon.stub() };
|
|
584
468
|
const project = { name: 'blinky' };
|
|
585
|
-
agent.
|
|
586
|
-
expect(
|
|
469
|
+
const subject = agent._getProjectContext(project);
|
|
470
|
+
expect(subject).to.have.property('X-Particle-Project', 'blinky');
|
|
587
471
|
});
|
|
588
472
|
|
|
589
473
|
it('does not set the header when the project has no name', () => {
|
|
590
|
-
const req = { set: sinon.stub() };
|
|
591
474
|
const project = { noname: 'blinky' };
|
|
592
|
-
agent.
|
|
593
|
-
expect(
|
|
475
|
+
const subject = agent._getProjectContext(project);
|
|
476
|
+
expect(subject).to.not.have.property('X-Particle-Project');
|
|
594
477
|
});
|
|
595
478
|
});
|
|
596
479
|
|