Agent
- should remember defaults
if (typeof Promise === 'undefined') { return; } let called = 0; let event_called = 0; const agent = request .agent() .accept('json') .use(() => { called++; }) .once('request', () => { event_called++; }) .query({ hello: 'world' }) .set('X-test', 'testing'); assert.equal(0, called); assert.equal(0, event_called); return agent .get(`${base}/echo`) .then((res) => { assert.equal(1, called); assert.equal(1, event_called); assert.equal('application/json', res.headers.accept); assert.equal('testing', res.headers['x-test']); return agent.get(`${base}/querystring`); }) .then((res) => { assert.equal(2, called); assert.equal(2, event_called); assert.deepEqual({ hello: 'world' }, res.body); });
request
- should set statusCode
request.get(`${uri}/login`, (error, res) => { try { assert.strictEqual(res.statusCode, 200); done(); } catch (err) { done(err); } });
- with callback in the method call
request.get(`${uri}/login`, (error, res) => { assert.equal(res.status, 200); done(); });
- with data in the method call
request.post(`${uri}/echo`, { foo: 'bar' }).end((error, res) => { assert.equal('{"foo":"bar"}', res.text); done(); });
- with callback and data in the method call
request.post(`${uri}/echo`, { foo: 'bar' }, (error, res) => { assert.equal('{"foo":"bar"}', res.text); done(); });
- should invoke .end()
request.get(`${uri}/login`, (error, res) => { try { assert.equal(res.status, 200); done(); } catch (err) { done(err); } });
- should issue a request
request.get(`${uri}/login`).end((error, res) => { try { assert.equal(res.status, 200); done(); } catch (err) { done(err); } });
- is optional with a promise
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/login`) .then((res) => res.status) .then() .then((status) => { assert.equal(200, status, 'Real promises pass results through'); });
- called only once with a promise
if (typeof Promise === 'undefined') { return; } const request_ = request.get(`${uri}/unique`); return Promise.all([request_, request_, request_]).then((results) => { for (const item of results) { assert.deepEqual( item.body, results[0].body, 'It should keep returning the same result after being called once' ); } });
- ok
let calledErrorEvent = false; let calledOKHandler = false; request .get(`${uri}/error`) .ok((res) => { assert.strictEqual(500, res.status); calledOKHandler = true; return true; }) .on('error', (error) => { calledErrorEvent = true; }) .end((error, res) => { try { assert.ifError(error); assert.strictEqual(res.status, 500); assert(!calledErrorEvent); assert(calledOKHandler); done(); } catch (err) { done(err); } });
- should be an Error object
let calledErrorEvent = false; request .get(`${uri}/error`) .on('error', (error) => { assert.strictEqual(error.status, 500); calledErrorEvent = true; }) .end((error, res) => { try { if (NODE) { res.error.message.should.equal('cannot GET /error (500)'); } else { res.error.message.should.equal(`cannot GET ${uri}/error (500)`); } assert.strictEqual(res.error.status, 500); assert(error, 'should have an error for 500'); assert.equal(error.message, 'Internal Server Error'); assert(calledErrorEvent); done(); } catch (err) { done(err); } });
- with .then() promise
if (typeof Promise === 'undefined') { return; } return request.get(`${uri}/error`).then( () => { assert.fail(); }, (err) => { assert.equal(err.message, 'Internal Server Error'); } );
- with .ok() returning false
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/echo`) .ok(() => false) .then( () => { assert.fail(); }, (err) => { assert.equal(200, err.response.status); assert.equal(err.message, 'OK'); } );
- with .ok() throwing an Error
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/echo`) .ok(() => { throw new Error('boom'); }) .then( () => { assert.fail(); }, (err) => { assert.equal(200, err.status); assert.equal(200, err.response.status); assert.equal(err.message, 'boom'); } );
- with .ok() throwing an Error with status
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/echo`) .ok(() => { const err = new Error('boom'); err.status = 404; throw err; }) .then( () => { assert.fail(); }, (err) => { assert.equal(404, err.status); assert.equal(200, err.response.status); assert.equal(err.message, 'boom'); } );
- should be an object
request.get(`${uri}/login`).end((error, res) => { try { assert.equal('Express', res.header['x-powered-by']); done(); } catch (err) { done(err); } });
- should only set headers for ownProperties of header
try { request .get(`${uri}/echo-headers`) .set('valid', 'ok') .end((error, res) => { if ( !error && res.body && res.body.valid && !res.body.hasOwnProperty('invalid') ) { return done(); } done(error || new Error('fail')); }); } catch (err) { done(err); }
- should be set when present
request.get(`${uri}/login`).end((error, res) => { try { res.charset.should.equal('utf-8'); done(); } catch (err) { done(err); } });
- should provide the first digit
request.get(`${uri}/login`).end((error, res) => { try { assert(!error, 'should not have an error for success responses'); assert.equal(200, res.status); assert.equal(2, res.statusType); done(); } catch (err) { done(err); } });
- should provide the mime-type void of params
request.get(`${uri}/login`).end((error, res) => { try { res.type.should.equal('text/html'); res.charset.should.equal('utf-8'); done(); } catch (err) { done(err); } });
- should set the header field
request .post(`${uri}/echo`) .set('X-Foo', 'bar') .set('X-Bar', 'baz') .end((error, res) => { try { assert.equal('bar', res.header['x-foo']); assert.equal('baz', res.header['x-bar']); done(); } catch (err) { done(err); } });
- should set the header fields
request .post(`${uri}/echo`) .set({ 'X-Foo': 'bar', 'X-Bar': 'baz' }) .end((error, res) => { try { assert.equal('bar', res.header['x-foo']); assert.equal('baz', res.header['x-bar']); done(); } catch (err) { done(err); } });
- should set the Content-Type
request .post(`${uri}/echo`) .type('text/x-foo') .end((error, res) => { try { res.header['content-type'].should.equal('text/x-foo'); done(); } catch (err) { done(err); } });
- should map "json"
request .post(`${uri}/echo`) .type('json') .send('{"a": 1}') .end((error, res) => { try { res.should.be.json(); done(); } catch (err) { done(err); } });
- should map "html"
request .post(`${uri}/echo`) .type('html') .end((error, res) => { try { res.header['content-type'].should.equal('text/html'); done(); } catch (err) { done(err); } });
- should set Accept
request .get(`${uri}/echo`) .accept('text/x-foo') .end((error, res) => { try { res.header.accept.should.equal('text/x-foo'); done(); } catch (err) { done(err); } });
- should map "json"
request .get(`${uri}/echo`) .accept('json') .end((error, res) => { try { res.header.accept.should.equal('application/json'); done(); } catch (err) { done(err); } });
- should map "xml"
request .get(`${uri}/echo`) .accept('xml') .end((error, res) => { try { // Mime module keeps changing this :( assert( res.header.accept == 'application/xml' || res.header.accept == 'text/xml' ); done(); } catch (err) { done(err); } });
- should map "html"
request .get(`${uri}/echo`) .accept('html') .end((error, res) => { try { res.header.accept.should.equal('text/html'); done(); } catch (err) { done(err); } });
- should write the string
request .post(`${uri}/echo`) .type('json') .send('{"name":"tobi"}') .end((error, res) => { try { res.text.should.equal('{"name":"tobi"}'); done(); } catch (err) { done(err); } });
- should default to json
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .end((error, res) => { try { res.should.be.json(); res.text.should.equal('{"name":"tobi"}'); done(); } catch (err) { done(err); } });
- should merge the objects
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .send({ age: 1 }) .end((error, res) => { try { res.should.be.json(); if (NODE) { res.buffered.should.be.true(); } res.text.should.equal('{"name":"tobi","age":1}'); done(); } catch (err) { done(err); } });
- should check arity
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .end((error, res) => { try { assert.ifError(error); res.text.should.equal('{"name":"tobi"}'); done(); } catch (err) { done(err); } });
- should emit request
const request_ = request.post(`${uri}/echo`); request_.on('request', (request) => { assert.equal(request_, request); done(); }); request_.end();
- should emit response
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .on('response', (res) => { res.text.should.equal('{"name":"tobi"}'); done(); }) .end();
- should support successful fulfills with .then(fulfill)
if (typeof Promise === 'undefined') { return done(); } request .post(`${uri}/echo`) .send({ name: 'tobi' }) .then((res) => { res.type.should.equal('application/json'); res.text.should.equal('{"name":"tobi"}'); done(); });
- should reject an error with .then(null, reject)
if (typeof Promise === 'undefined') { return done(); } request.get(`${uri}/error`).then(null, (err) => { assert.equal(err.status, 500); assert.equal(err.response.text, 'boom'); done(); });
- should reject an error with .catch(reject)
if (typeof Promise === 'undefined') { return done(); } request.get(`${uri}/error`).catch((err) => { assert.equal(err.status, 500); assert.equal(err.response.text, 'boom'); done(); });
- should abort the request
const request_ = request.get(`${uri}/delay/3000`); request_.end((error, res) => { try { assert(false, 'should not complete the request'); } catch (err) { done(err); } }); request_.on('error', (error) => { done(error); }); request_.on('abort', done); setTimeout(() => { request_.abort(); }, 500);
- should abort the promise
const request_ = request.get(`${uri}/delay/3000`); setTimeout(() => { request_.abort(); }, 10); return request_.then( () => { assert.fail('should not complete the request'); }, (err) => { assert.equal('ABORTED', err.code); } );
- should allow chaining .abort() several times
const request_ = request.get(`${uri}/delay/3000`); request_.end((error, res) => { try { assert(false, 'should not complete the request'); } catch (err) { done(err); } }); // This also verifies only a single 'done' event is emitted request_.on('abort', done); setTimeout(() => { request_.abort().abort().abort(); }, 1000);
- should not allow abort then end
request .get(`${uri}/delay/3000`) .abort() .end((error, res) => { done(error ? undefined : new Error('Expected abort error')); });
- should describe the request
const request_ = request.post(`${uri}/echo`).send({ foo: 'baz' }); request_.end((error, res) => { try { const json = request_.toJSON(); assert.equal('POST', json.method); assert(/\/echo$/.test(json.url)); assert.equal('baz', json.data.foo); done(); } catch (err) { done(err); } });
- should allow request body
request .options(`${uri}/options/echo/body`) .send({ foo: 'baz' }) .end((error, res) => { try { assert.equal(error, null); assert.strictEqual(res.body.foo, 'baz'); done(); } catch (err) { done(err); } });
- nop with no querystring
request .get(`${uri}/url`) .sortQuery() .end((error, res) => { try { assert.equal(res.text, '/url'); done(); } catch (err) { done(err); } });
- should sort the request querystring
request .get(`${uri}/url`) .query('search=Manny') .query('order=desc') .sortQuery() .end((error, res) => { try { assert.equal(res.text, '/url?order=desc&search=Manny'); done(); } catch (err) { done(err); } });
- should allow disabling sorting
request .get(`${uri}/url`) .query('search=Manny') .query('order=desc') .sortQuery() // take default of true .sortQuery(false) // override it in later call .end((error, res) => { try { assert.equal(res.text, '/url?search=Manny&order=desc'); done(); } catch (err) { done(err); } });
- should sort the request querystring using customized function
request .get(`${uri}/url`) .query('name=Nick') .query('search=Manny') .query('order=desc') .sortQuery((a, b) => a.length - b.length) .end((error, res) => { try { assert.equal(res.text, '/url?name=Nick&order=desc&search=Manny'); done(); } catch (err) { done(err); } });
res.statusCode
should allow the send shorthand
with a callback
.end()
res.error
res.header
set headers
res.charset
res.statusType
res.type
req.set(field, val)
req.set(obj)
req.type(str)
req.accept(str)
req.send(str)
req.send(Object)
when called several times
.end(fn)
.then(fulfill, reject)
.catch(reject)
.abort()
req.toJSON()
req.options()
req.sortQuery()
req.set("Content-Type", contentType)
- should work with just the contentType component
request .post(`${uri}/echo`) .set('Content-Type', 'application/json') .send({ name: 'tobi' }) .end((error) => { assert(!error); done(); });
- should work with the charset component
request .post(`${uri}/echo`) .set('Content-Type', 'application/json; charset=utf-8') .send({ name: 'tobi' }) .end((error) => { assert(!error); done(); });
req.send(Object) as "form"
- should send x-www-form-urlencoded data
request .post(`${base}/echo`) .type('form') .send({ name: 'tobi' }) .end((error, res) => { res.header['content-type'].should.equal( 'application/x-www-form-urlencoded' ); res.text.should.equal('name=tobi'); done(); });
- should merge the objects
request .post(`${base}/echo`) .type('form') .send({ name: { first: 'tobi', last: 'holowaychuk' } }) .send({ age: '1' }) .end((error, res) => { res.header['content-type'].should.equal( 'application/x-www-form-urlencoded' ); res.text.should.equal( 'name%5Bfirst%5D=tobi&name%5Blast%5D=holowaychuk&age=1' ); done(); });
with req.type() set to form
when called several times
req.attach
- ignores null file
request .post('/echo') .attach('image', null) .end((error, res) => { done(); });
req.field
- allow bools
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field('bools', true) .field('strings', 'true') .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { bools: 'true', strings: 'true' }); done(); });
- allow objects
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field({ bools: true, strings: 'true' }) .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { bools: 'true', strings: 'true' }); done(); });
- works with arrays in objects
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field({ numbers: [1, 2, 3] }) .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { numbers: ['1', '2', '3'] }); done(); });
- works with arrays
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field('letters', ['a', 'b', 'c']) .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { letters: ['a', 'b', 'c'] }); done(); });
- throw when empty
should.throws(() => { request.post(`${base}/echo`).field(); }, /name/); should.throws(() => { request.post(`${base}/echo`).field('name'); }, /val/);
- cannot be mixed with send()
assert.throws(() => { request.post('/echo').field('form', 'data').send('hi'); }); assert.throws(() => { request.post('/echo').send('hi').field('form', 'data'); });
req.send(Object) as "json"
- should default to json
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .end((error, res) => { res.should.be.json(); res.text.should.equal('{"name":"tobi"}'); done(); });
- should work with arrays
request .post(`${uri}/echo`) .send([1, 2, 3]) .end((error, res) => { res.should.be.json(); res.text.should.equal('[1,2,3]'); done(); });
- should work with value null
request .post(`${uri}/echo`) .type('json') .send('null') .end((error, res) => { res.should.be.json(); assert.strictEqual(res.body, null); done(); });
- should work with value false
request .post(`${uri}/echo`) .type('json') .send('false') .end((error, res) => { res.should.be.json(); res.body.should.equal(false); done(); });
- should work with empty string value
request .post(`${uri}/echo`) .type('json') .send('""') .end((error, res) => { res.should.be.json(); res.body.should.equal(''); done(); });
- should work with vendor MIME type
request .post(`${uri}/echo`) .set('Content-Type', 'application/vnd.example+json') .send({ name: 'vendor' }) .end((error, res) => { res.text.should.equal('{"name":"vendor"}'); ({ name: 'vendor' }.should.eql(res.body)); done(); });
- should merge the objects
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .send({ age: 1 }) .end((error, res) => { res.should.be.json(); res.text.should.equal('{"name":"tobi","age":1}'); ({ name: 'tobi', age: 1 }.should.eql(res.body)); done(); });
when called several times
res.body
- should parse the body
request.get(`${uri}/json`).end((error, res) => { res.text.should.equal('{"name":"manny"}'); res.body.should.eql({ name: 'manny' }); done(); });
- should return the raw response
request.get(`${uri}/invalid-json`).end((error, res) => { assert.deepEqual( error.rawResponse, ")]}', {'header':{'code':200,'text':'OK','version':'1.0'},'data':'some data'}" ); done(); });
- should return the http status code
request.get(`${uri}/invalid-json-forbidden`).end((error, res) => { assert.equal(error.statusCode, 403); done(); });
application/json
Invalid JSON response
request
- should retain header fields
request .get(`${base}/header`) .set('X-Foo', 'bar') .end((error, res) => { try { assert(res.body); res.body.should.have.property('x-foo', 'bar'); done(); } catch (err) { done(err); } });
- should preserve timeout across redirects
request .get(`${base}/movies/random`) .timeout(250) .end((error, res) => { try { assert(error instanceof Error, 'expected an error'); error.should.have.property('timeout', 250); done(); } catch (err) { done(err); } });
- should successfully redirect after retry on error
const id = Math.random() * 1_000_000 * Date.now(); request .get(`${base}/error/redirect/${id}`) .retry(2) .end((error, res) => { assert(res.ok, 'response should be ok'); assert(res.text, 'first movie page'); done(); });
- should preserve retries across redirects
const id = Math.random() * 1_000_000 * Date.now(); request .get(`${base}/error/redirect-error${id}`) .retry(2) .end((error, res) => { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); });
- should redirect with same method
request .put(`${base}/redirect-303`) .send({ msg: 'hello' }) .redirects(1) .on('redirect', (res) => { res.headers.location.should.equal('/reply-method'); }) .end((error, res) => { if (error) { done(error); return; } res.text.should.equal('method=get'); done(); });
- should redirect with same method
if (isMSIE) return done(); // IE9 broken request .put(`${base}/redirect-307`) .send({ msg: 'hello' }) .redirects(1) .on('redirect', (res) => { res.headers.location.should.equal('/reply-method'); }) .end((error, res) => { if (error) { done(error); return; } res.text.should.equal('method=put'); done(); });
- should redirect with same method
if (isMSIE) return done(); // IE9 broken request .put(`${base}/redirect-308`) .send({ msg: 'hello' }) .redirects(1) .on('redirect', (res) => { res.headers.location.should.equal('/reply-method'); }) .end((error, res) => { if (error) { done(error); return; } res.text.should.equal('method=put'); done(); });
on redirect
on 303
on 307
on 308
request
- Request inheritance
assert(request.get(`${uri}/`) instanceof request.Request);
- request() simple GET without callback
request('GET', 'test/test.request.js').end(); next();
- request() simple GET
request('GET', `${uri}/ok`).end((error, res) => { try { assert(res instanceof request.Response, 'respond with Response'); assert(res.ok, 'response should be ok'); assert(res.text, 'res.text'); next(); } catch (err) { next(err); } });
- request() simple HEAD
request.head(`${uri}/ok`).end((error, res) => { try { assert(res instanceof request.Response, 'respond with Response'); assert(res.ok, 'response should be ok'); assert(!res.text, 'res.text'); next(); } catch (err) { next(err); } });
- request() GET 5xx
request('GET', `${uri}/error`).end((error, res) => { try { assert(error); assert.equal(error.message, 'Internal Server Error'); assert(!res.ok, 'response should not be ok'); assert(res.error, 'response should be an error'); assert(!res.clientError, 'response should not be a client error'); assert(res.serverError, 'response should be a server error'); next(); } catch (err) { next(err); } });
- request() GET 4xx
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal(error.message, 'Not Found'); assert(!res.ok, 'response should not be ok'); assert(res.error, 'response should be an error'); assert(res.clientError, 'response should be a client error'); assert(!res.serverError, 'response should not be a server error'); next(); } catch (err) { next(err); } });
- request() GET 404 Not Found
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert(res.notFound, 'response should be .notFound'); next(); } catch (err) { next(err); } });
- request() GET 400 Bad Request
request('GET', `${uri}/bad-request`).end((error, res) => { try { assert(error); assert(res.badRequest, 'response should be .badRequest'); next(); } catch (err) { next(err); } });
- request() GET 401 Bad Request
request('GET', `${uri}/unauthorized`).end((error, res) => { try { assert(error); assert(res.unauthorized, 'response should be .unauthorized'); next(); } catch (err) { next(err); } });
- request() GET 406 Not Acceptable
request('GET', `${uri}/not-acceptable`).end((error, res) => { try { assert(error); assert(res.notAcceptable, 'response should be .notAcceptable'); next(); } catch (err) { next(err); } });
- request() GET 204 No Content
request('GET', `${uri}/no-content`).end((error, res) => { try { assert.ifError(error); assert(res.noContent, 'response should be .noContent'); next(); } catch (err) { next(err); } });
- request() DELETE 204 No Content
request('DELETE', `${uri}/no-content`).end((error, res) => { try { assert.ifError(error); assert(res.noContent, 'response should be .noContent'); next(); } catch (err) { next(err); } });
- request() header parsing
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal('text/html; charset=utf-8', res.header['content-type']); assert.equal('Express', res.header['x-powered-by']); next(); } catch (err) { next(err); } });
- request() .status
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal(404, res.status, 'response .status'); assert.equal(4, res.statusType, 'response .statusType'); next(); } catch (err) { next(err); } });
- get()
request.get(`${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal(404, res.status, 'response .status'); assert.equal(4, res.statusType, 'response .statusType'); next(); } catch (err) { next(err); } });
- put()
request.put(`${uri}/user/12`).end((error, res) => { try { assert.equal('updated', res.text, 'response text'); next(); } catch (err) { next(err); } });
- put().send()
request .put(`${uri}/user/13/body`) .send({ user: 'new' }) .end((error, res) => { try { assert.equal('received new', res.text, 'response text'); next(); } catch (err) { next(err); } });
- post()
request.post(`${uri}/user`).end((error, res) => { try { assert.equal('created', res.text, 'response text'); next(); } catch (err) { next(err); } });
- del()
request.del(`${uri}/user/12`).end((error, res) => { try { assert.equal('deleted', res.text, 'response text'); next(); } catch (err) { next(err); } });
- delete()
request.delete(`${uri}/user/12`).end((error, res) => { try { assert.equal('deleted', res.text, 'response text'); next(); } catch (err) { next(err); } });
- post() data
request .post(`${uri}/todo/item`) .type('application/octet-stream') .send('tobi') .end((error, res) => { try { assert.equal('added "tobi"', res.text, 'response text'); next(); } catch (err) { next(err); } });
- request .type()
request .post(`${uri}/user/12/pet`) .type('urlencoded') .send('pet=tobi') .end((error, res) => { try { assert.equal('added pet "tobi"', res.text, 'response text'); next(); } catch (err) { next(err); } });
- request .type() with alias
request .post(`${uri}/user/12/pet`) .type('application/x-www-form-urlencoded') .send('pet=tobi') .end((error, res) => { try { assert.equal('added pet "tobi"', res.text, 'response text'); next(); } catch (err) { next(err); } });
- request .get() with no data or callback
request.get(`${uri}/echo-header/content-type`); next();
- request .send() with no data only
request.post(`${uri}/user/5/pet`).type('urlencoded').send('pet=tobi'); next();
- request .send() with callback only
request .get(`${uri}/echo-header/accept`) .set('Accept', 'foo/bar') .end((error, res) => { try { assert.equal('foo/bar', res.text); next(); } catch (err) { next(err); } });
- request .accept() with json
request .get(`${uri}/echo-header/accept`) .accept('json') .end((error, res) => { try { assert.equal('application/json', res.text); next(); } catch (err) { next(err); } });
- request .accept() with application/json
request .get(`${uri}/echo-header/accept`) .accept('application/json') .end((error, res) => { try { assert.equal('application/json', res.text); next(); } catch (err) { next(err); } });
- request .accept() with xml
request .get(`${uri}/echo-header/accept`) .accept('xml') .end((error, res) => { try { // We can't depend on mime module to be consistent with this assert(res.text == 'application/xml' || res.text == 'text/xml'); next(); } catch (err) { next(err); } });
- request .accept() with application/xml
request .get(`${uri}/echo-header/accept`) .accept('application/xml') .end((error, res) => { try { assert.equal('application/xml', res.text); next(); } catch (err) { next(err); } });
- request .end()
request .put(`${uri}/echo-header/content-type`) .set('Content-Type', 'text/plain') .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- request .send()
request .put(`${uri}/echo-header/content-type`) .set('Content-Type', 'text/plain') .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- request .set()
request .put(`${uri}/echo-header/content-type`) .set('Content-Type', 'text/plain') .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- request .set(object)
request .put(`${uri}/echo-header/content-type`) .set({ 'Content-Type': 'text/plain' }) .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- POST urlencoded
request .post(`${uri}/pet`) .type('urlencoded') .send({ name: 'Manny', species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST json
request .post(`${uri}/pet`) .type('json') .send({ name: 'Manny', species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST json array
request .post(`${uri}/echo`) .send([1, 2, 3]) .end((error, res) => { try { assert.equal( 'application/json', res.header['content-type'].split(';')[0] ); assert.equal('[1,2,3]', res.text); next(); } catch (err) { next(err); } });
- POST json default
request .post(`${uri}/pet`) .send({ name: 'Manny', species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST json contentType charset
request .post(`${uri}/echo`) .set('Content-Type', 'application/json; charset=UTF-8') .send({ data: ['data1', 'data2'] }) .end((error, res) => { try { assert.equal('{"data":["data1","data2"]}', res.text); next(); } catch (err) { next(err); } });
- POST json contentType vendor
request .post(`${uri}/echo`) .set('Content-Type', 'application/vnd.example+json') .send({ data: ['data1', 'data2'] }) .end((error, res) => { try { assert.equal('{"data":["data1","data2"]}', res.text); next(); } catch (err) { next(err); } });
- POST multiple .send() calls
request .post(`${uri}/pet`) .send({ name: 'Manny' }) .send({ species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST multiple .send() strings
request .post(`${uri}/echo`) .send('user[name]=tj') .send('user[email]=tj@vision-media.ca') .end((error, res) => { try { assert.equal( 'application/x-www-form-urlencoded', res.header['content-type'].split(';')[0] ); assert.equal( res.text, 'user[name]=tj&user[email]=tj@vision-media.ca' ); next(); } catch (err) { next(err); } });
- POST with no data
request .post(`${uri}/empty-body`) .send() .end((error, res) => { try { assert.ifError(error); assert(res.noContent, 'response should be .noContent'); next(); } catch (err) { next(err); } });
- GET .type
request.get(`${uri}/pets`).end((error, res) => { try { assert.equal('application/json', res.type); next(); } catch (err) { next(err); } });
- GET Content-Type params
request.get(`${uri}/text`).end((error, res) => { try { assert.equal('utf-8', res.charset); next(); } catch (err) { next(err); } });
- GET json
request.get(`${uri}/pets`).end((error, res) => { try { assert.deepEqual(res.body, ['tobi', 'loki', 'jane']); next(); } catch (err) { next(err); } });
- GET json-seq
request .get(`${uri}/json-seq`) .buffer() .end((error, res) => { try { assert.ifError(error); assert.deepEqual(res.text, '\u001E{"id":1}\n\u001E{"id":2}\n'); next(); } catch (err) { next(err); } });
- GET binary data
request .get(`${uri}/binary-data`) .buffer() .end((error, res) => { try { assert.ifError(error); assert.deepEqual(res.body, binData); next(); } catch (err) { next(err); } });
- GET x-www-form-urlencoded
request.get(`${uri}/foo`).end((error, res) => { try { assert.deepEqual(res.body, { foo: 'bar' }); next(); } catch (err) { next(err); } });
- GET shorthand
request.get(`${uri}/foo`, (error, res) => { try { assert.equal('foo=bar', res.text); next(); } catch (err) { next(err); } });
- POST shorthand
request.post(`${uri}/user/0/pet`, { pet: 'tobi' }, (error, res) => { try { assert.equal('added pet "tobi"', res.text); next(); } catch (err) { next(err); } });
- POST shorthand without callback
request.post(`${uri}/user/0/pet`, { pet: 'tobi' }).end((error, res) => { try { assert.equal('added pet "tobi"', res.text); next(); } catch (err) { next(err); } });
- GET querystring object with array
request .get(`${uri}/querystring`) .query({ val: ['a', 'b', 'c'] }) .end((error, res) => { try { assert.deepEqual(res.body, { val: ['a', 'b', 'c'] }); next(); } catch (err) { next(err); } });
- GET querystring object with array and primitives
request .get(`${uri}/querystring`) .query({ array: ['a', 'b', 'c'], string: 'foo', number: 10 }) .end((error, res) => { try { assert.deepEqual(res.body, { array: ['a', 'b', 'c'], string: 'foo', number: 10 }); next(); } catch (err) { next(err); } });
- GET querystring object with two arrays
request .get(`${uri}/querystring`) .query({ array1: ['a', 'b', 'c'], array2: [1, 2, 3] }) .end((error, res) => { try { assert.deepEqual(res.body, { array1: ['a', 'b', 'c'], array2: [1, 2, 3] }); next(); } catch (err) { next(err); } });
- GET querystring object
request .get(`${uri}/querystring`) .query({ search: 'Manny' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny' }); next(); } catch (err) { next(err); } });
- GET querystring append original
request .get(`${uri}/querystring?search=Manny`) .query({ range: '1..5' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5' }); next(); } catch (err) { next(err); } });
- GET querystring multiple objects
request .get(`${uri}/querystring`) .query({ search: 'Manny' }) .query({ range: '1..5' }) .query({ order: 'desc' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5', order: 'desc' }); next(); } catch (err) { next(err); } });
- GET querystring with strings
request .get(`${uri}/querystring`) .query('search=Manny') .query('range=1..5') .query('order=desc') .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5', order: 'desc' }); next(); } catch (err) { next(err); } });
- GET querystring with strings and objects
request .get(`${uri}/querystring`) .query('search=Manny') .query({ order: 'desc', range: '1..5' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5', order: 'desc' }); next(); } catch (err) { next(err); } });
- GET shorthand payload goes to querystring
request.get( `${uri}/querystring`, { foo: 'FOO', bar: 'BAR' }, (error, res) => { try { assert.deepEqual(res.body, { foo: 'FOO', bar: 'BAR' }); next(); } catch (err) { next(err); } } );
- HEAD shorthand payload goes to querystring
request.head( `${uri}/querystring-in-header`, { foo: 'FOO', bar: 'BAR' }, (error, res) => { try { assert.deepEqual(JSON.parse(res.headers.query), { foo: 'FOO', bar: 'BAR' }); next(); } catch (err) { next(err); } } );
- request(method, url)
request('GET', `${uri}/foo`).end((error, res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } });
- request(url)
request(`${uri}/foo`).end((error, res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } });
- request(url, fn)
request(`${uri}/foo`, (error, res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } });
- req.timeout(ms)
const request_ = request.get(`${uri}/delay/3000`).timeout(1000); request_.end((error, res) => { try { assert(error, 'error missing'); assert.equal(1000, error.timeout, 'err.timeout missing'); assert.equal( 'Timeout of 1000ms exceeded', error.message, 'err.message incorrect' ); assert.equal(null, res); assert(request_.timedout, true); next(); } catch (err) { next(err); } });
- req.timeout(ms) with redirect
const request_ = request.get(`${uri}/delay/const`).timeout(1000); request_.end((error, res) => { try { assert(error, 'error missing'); assert.equal(1000, error.timeout, 'err.timeout missing'); assert.equal( 'Timeout of 1000ms exceeded', error.message, 'err.message incorrect' ); assert.equal(null, res); assert(request_.timedout, true); next(); } catch (err) { next(err); } });
- request event
request .get(`${uri}/foo`) .on('request', (request_) => { try { assert.equal(`${uri}/foo`, request_.url); next(); } catch (err) { next(err); } }) .end();
- response event
request .get(`${uri}/foo`) .on('response', (res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } }) .end();
- response should set statusCode
request.get(`${uri}/ok`, (error, res) => { try { assert.strictEqual(res.statusCode, 200); next(); } catch (err) { next(err); } });
- req.toJSON()
request.get(`${uri}/ok`).end((error, res) => { try { const index = (res.request || res.req).toJSON(); for (const property of ['url', 'method', 'data', 'headers']) { assert(index.hasOwnProperty(property)); } next(); } catch (err) { next(err); } });
.retry(count)
- should not retry if passed "0"
request .get(`${base}/error`) .retry(0) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal( undefined, error.retries, 'expected an error without .retries' ); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should not retry if passed an invalid number
request .get(`${base}/error`) .retry(-2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal( undefined, error.retries, 'expected an error without .retries' ); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should not retry if passed undefined
request .get(`${base}/error`) .retry(undefined) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal( undefined, error.retries, 'expected an error without .retries' ); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should handle server error after repeat attempt
request .get(`${base}/error`) .retry(2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should retry if passed nothing
request .get(`${base}/error`) .retry() .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(1, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should retry if passed "true"
request .get(`${base}/error`) .retry(true) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(1, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should handle successful request after repeat attempt from server error
request .get(`${base}/error/ok/${uniqid()}`) .query({ qs: 'present' }) .retry(2) .end((error, res) => { try { assert.ifError(error); assert(res.ok, 'response should be ok'); assert(res.text, 'res.text'); done(); } catch (err) { done(err); } });
- should handle server timeout error after repeat attempt
request .get(`${base}/delay/400`) .timeout(200) .retry(2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); } catch (err) { done(err); } });
- should handle successful request after repeat attempt from server timeout
const url = `/delay/1200/ok/${uniqid()}?built=in`; request .get(base + url) .query('string=ified') .query({ json: 'ed' }) .timeout(600) .retry(2) .end((error, res) => { try { assert.ifError(error); assert(res.ok, 'response should be ok'); assert.equal(res.text, `ok = ${url}&string=ified&json=ed`); done(); } catch (err) { done(err); } });
- should handle successful request after repeat attempt from server timeout when using .then(fulfill, reject)
const url = `/delay/1200/ok/${uniqid()}?built=in`; request .get(base + url) .query('string=ified') .query({ json: 'ed' }) .timeout(600) .retry(1) .then((res, error) => { try { assert.ifError(error); assert(res.ok, 'response should be ok'); assert.equal(res.text, `ok = ${url}&string=ified&json=ed`); done(); } catch (err) { done(err); } });
- should correctly abort a retry attempt
let aborted = false; const request_ = request.get(`${base}/delay/400`).timeout(200).retry(2); request_.end((error, res) => { try { assert(false, 'should not complete the request'); } catch (err) { done(err); } }); request_.on('abort', () => { aborted = true; }); setTimeout(() => { request_.abort(); setTimeout(() => { try { assert(aborted, 'should be aborted'); done(); } catch (err) { done(err); } }, 150); }, 150);
- should correctly retain header fields
request .get(`${base}/error/ok/${uniqid()}`) .query({ qs: 'present' }) .retry(2) .set('X-Foo', 'bar') .end((error, res) => { try { assert.ifError(error); assert(res.body); res.body.should.have.property('x-foo', 'bar'); done(); } catch (err) { done(err); } });
- should not retry on 4xx responses
request .get(`${base}/bad-request`) .retry(2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(0, error.retries, 'expected an error with 0 .retries'); assert.equal(400, error.status, 'expected an error status of 400'); done(); } catch (err) { done(err); } });
- should execute callback on retry if passed
let callbackCallCount = 0; function retryCallback(request) { callbackCallCount++; } request .get(`${base}/error`) .retry(2, retryCallback) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); assert.equal( 2, callbackCallCount, 'expected the callback to be called on each retry' ); done(); } catch (err) { done(err); } });
.timeout(ms)
- should error
request .get(`${base}/delay/500`) .timeout(150) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should error in promise interface
request .get(`${base}/delay/500`) .timeout(150) .catch((err) => { assert(err, 'expected an error'); assert.equal( 'number', typeof err.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', err.code, 'expected abort error code'); done(); });
- should handle gzip timeout
request .get(`${base}/delay/zip`) .timeout(150) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should handle buffer timeout
request .get(`${base}/delay/json`) .buffer(true) .timeout(150) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should error on deadline
request .get(`${base}/delay/500`) .timeout({ deadline: 150 }) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should support setting individual options
request .get(`${base}/delay/500`) .timeout({ deadline: 10 }) .timeout({ response: 99_999 }) .end((error, res) => { assert(error, 'expected an error'); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); assert.equal('ETIME', error.errno); done(); });
- should error on response
request .get(`${base}/delay/500`) .timeout({ response: 150 }) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); assert.equal('ETIMEDOUT', error.errno); done(); });
- should accept slow body with fast response
request .get(`${base}/delay/slowbody`) .timeout({ response: 1000 }) .on('progress', () => { // This only makes the test faster without relying on arbitrary timeouts request.get(`${base}/delay/slowbody/finish`).end(); }) .end(done);
when timeout is exceeded
request
- should use plugin success
const now = `${Date.now()}`; function uuid(request_) { request_.set('X-UUID', now); return request_; } function prefix(request_) { request_.url = uri + request_.url; return request_; } request .get('/echo') .use(uuid) .use(prefix) .end((error, res) => { assert.strictEqual(res.statusCode, 200); assert.equal(res.get('X-UUID'), now); done(); });
use
subclass
- should be an instance of Request
const request_ = request.get('/'); assert(request_ instanceof request.Request);
- should use patched subclass
assert(OriginalRequest); let constructorCalled; let sendCalled; function NewRequest(...args) { constructorCalled = true; OriginalRequest.apply(this, args); } NewRequest.prototype = Object.create(OriginalRequest.prototype); NewRequest.prototype.send = function () { sendCalled = true; return this; }; request.Request = NewRequest; const request_ = request.get('/').send(); assert(constructorCalled); assert(sendCalled); assert(request_ instanceof NewRequest); assert(request_ instanceof OriginalRequest);
- should use patched subclass in agent too
if (!request.agent) return; // Node-only function NewRequest(...args) { OriginalRequest.apply(this, args); } NewRequest.prototype = Object.create(OriginalRequest.prototype); request.Request = NewRequest; const request_ = request.agent().del('/'); assert(request_ instanceof NewRequest); assert(request_ instanceof OriginalRequest);
request
- should gain a session on POST
agent3.post(`${base}/signin`).then((res) => { res.should.have.status(200); should.not.exist(res.headers['set-cookie']); res.text.should.containEql('dashboard'); })
- should start with empty session (set cookies)
agent1.get(`${base}/dashboard`).end((error, res) => { should.exist(error); res.should.have.status(401); should.exist(res.headers['set-cookie']); done(); });
- should gain a session (cookies already set)
agent1.post(`${base}/signin`).then((res) => { res.should.have.status(200); should.not.exist(res.headers['set-cookie']); res.text.should.containEql('dashboard'); })
- should persist cookies across requests
agent1.get(`${base}/dashboard`).then((res) => { res.should.have.status(200); })
- should have the cookie set in the end callback
agent4 .post(`${base}/setcookie`) .then(() => agent4.get(`${base}/getcookie`)) .then((res) => { res.should.have.status(200); assert.strictEqual(res.text, 'jar'); })
- should not share cookies
agent2.get(`${base}/dashboard`).end((error, res) => { should.exist(error); res.should.have.status(401); done(); });
- should not lose cookies between agents
agent1.get(`${base}/dashboard`).then((res) => { res.should.have.status(200); })
- should be able to follow redirects
agent1.get(base).then((res) => { res.should.have.status(200); res.text.should.containEql('dashboard'); })
- should be able to post redirects
agent1 .post(`${base}/redirect`) .send({ foo: 'bar', baz: 'blaaah' }) .then((res) => { res.should.have.status(200); res.text.should.containEql('simple'); res.redirects.should.eql([`${base}/simple`]); })
- should be able to limit redirects
agent1 .get(base) .redirects(0) .end((error, res) => { should.exist(error); res.should.have.status(302); res.redirects.should.eql([]); res.header.location.should.equal('/dashboard'); done(); });
- should be able to create a new session (clear cookie)
agent1.post(`${base}/signout`).then((res) => { res.should.have.status(200); should.exist(res.headers['set-cookie']); })
- should regenerate with an empty session
agent1.get(`${base}/dashboard`).end((error, res) => { should.exist(error); res.should.have.status(401); should.not.exist(res.headers['set-cookie']); done(); });
persistent agent
Basic auth
- should set Authorization
const new_url = URL.parse(base); new_url.auth = 'tobi:learnboost'; new_url.pathname = '/basic-auth'; request.get(URL.format(new_url)).end((error, res) => { res.status.should.equal(200); done(); });
- should set Authorization
request .get(`${base}/basic-auth`) .auth('tobi', 'learnboost') .end((error, res) => { res.status.should.equal(200); done(); });
- should set authorization
request .get(`${base}/basic-auth/again`) .auth('tobi') .end((error, res) => { res.status.should.eql(200); done(); });
when credentials are present in url
req.auth(user, pass)
req.auth(user + ":" + pass)
[node] request
- should send body with .get().send()
request .get(`${base}/echo`) .set('Content-Type', 'text/plain') .send('wahoo') .end((error, res) => { try { assert.equal('wahoo', res.text); next(); } catch (err) { next(err); } });
- should preserve the encoding of the url
request.get(`${base}/url?a=(b%29`).end((error, res) => { assert.equal('/url?a=(b%29', res.text); done(); });
- should format the url
request.get(url.parse(`${base}/login`)).then((res) => { assert(res.ok); })
- should default to http
request.get(`${base}/login`).then((res) => { assert.equal(res.status, 200); })
- should describe the response
request .post(`${base}/echo`) .send({ foo: 'baz' }) .then((res) => { const object = res.toJSON(); assert.equal('object', typeof object.header); assert.equal('object', typeof object.req); assert.equal(200, object.status); assert.equal('{"foo":"baz"}', object.text); })
- should default to an empty object
request.get(`${base}/login`).then((res) => { res.links.should.eql({}); })
- should parse the Link header field
request.get(`${base}/links`).end((error, res) => { res.links.next.should.equal( 'https://api.github.com/repos/visionmedia/mocha/issues?page=2' ); done(); });
- should remove the header field
request .post(`${base}/echo`) .unset('User-Agent') .end((error, res) => { assert.equal(void 0, res.header['user-agent']); done(); });
- should set/get header fields case-insensitively
const r = request.post(`${base}/echo`); r.set('MiXeD', 'helloes'); assert.strictEqual(r.get('mixed'), 'helloes');
- should unset header fields case-insensitively
const r = request.post(`${base}/echo`); r.set('MiXeD', 'helloes'); r.unset('MIXED'); assert.strictEqual(r.get('mixed'), undefined);
- should write the given data
const request_ = request.post(`${base}/echo`); request_.set('Content-Type', 'application/json'); assert.equal('boolean', typeof request_.write('{"name"')); assert.equal('boolean', typeof request_.write(':"tobi"}')); request_.end((error, res) => { res.text.should.equal('{"name":"tobi"}'); done(); });
- should pipe the response to the given stream
const stream = new EventEmitter(); stream.buf = ''; stream.writable = true; stream.write = function (chunk) { this.buf += chunk; }; stream.end = function () { this.buf.should.equal('{"name":"tobi"}'); done(); }; request.post(`${base}/echo`).send('{"name":"tobi"}').pipe(stream);
- should enable buffering
request .get(`${base}/custom`) .buffer() .end((error, res) => { assert.ifError(error); assert.equal('custom stuff', res.text); assert(res.buffered); done(); });
- should take precedence over request.buffer['someMimeType'] = false
const type = 'application/barbaz'; const send = 'some text'; request.buffer[type] = false; request .post(`${base}/echo`) .type(type) .send(send) .buffer() .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(res.type, type); assert.equal(send, res.text); assert(res.buffered); done(); });
- should disable buffering
request .post(`${base}/echo`) .type('application/x-dog') .send('hello this is dog') .buffer(false) .end((error, res) => { assert.ifError(error); assert.equal(null, res.text); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal('hello this is dog'); done(); }); });
- should take precedence over request.buffer['someMimeType'] = true
const type = 'application/foobar'; const send = 'hello this is a dog'; request.buffer[type] = true; request .post(`${base}/echo`) .type(type) .send(send) .buffer(false) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(null, res.text); assert.equal(res.type, type); assert(!res.buffered); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal(send); done(); }); });
- should not throw an error when using the client-side "withCredentials" method
request .get(`${base}/custom`) .withCredentials() .end((error, res) => { assert.ifError(error); done(); });
- should return the defaut agent
const request_ = request.post(`${base}/echo`); request_.agent().should.equal(false); done();
- should set an agent to undefined and ensure it is chainable
const request_ = request.get(`${base}/echo`); const returnValue = request_.agent(undefined); returnValue.should.equal(request_); assert.strictEqual(request_.agent(), undefined); done();
- should set passed agent
const http = require('http'); const request_ = request.get(`${base}/echo`); const agent = new http.Agent(); const returnValue = request_.agent(agent); returnValue.should.equal(request_); request_.agent().should.equal(agent); done();
- should still use buffering
return request .post(`${base}/echo`) .type('application/x-dog') .send('hello this is dog') .then((res) => { assert.equal(null, res.text); assert.equal(res.body.toString(), 'hello this is dog'); res.buffered.should.be.true; });
- should be set to the byte length of a non-buffer object
const decoder = new StringDecoder('utf8'); let img = fs.readFileSync(`${__dirname}/fixtures/test.png`); img = decoder.write(img); request .post(`${base}/echo`) .type('application/x-image') .send(img) .buffer(false) .end((error, res) => { assert.ifError(error); assert(!res.buffered); assert.equal(res.header['content-length'], Buffer.byteLength(img)); done(); });
- should be set to the length of a buffer object
const img = fs.readFileSync(`${__dirname}/fixtures/test.png`); request .post(`${base}/echo`) .type('application/x-image') .send(img) .buffer(true) .end((error, res) => { assert.ifError(error); assert(res.buffered); assert.equal(res.header['content-length'], img.length); done(); });
with an url
with an object
without a schema
res.toJSON()
res.links
req.unset(field)
case-insensitive
req.write(str)
req.pipe(stream)
.buffer()
.buffer(false)
.withCredentials()
.agent()
.agent(undefined)
.agent(new http.Agent())
with a content type other than application/json or text/*
content-length
req.buffer['someMimeType']
- should respect that agent.buffer(true) takes precedent
const agent = request.agent(); agent.buffer(true); const type = 'application/somerandomtype'; const send = 'somerandomtext'; request.buffer[type] = false; agent .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(res.type, type); assert.equal(send, res.text); assert(res.buffered); done(); });
- should respect that agent.buffer(false) takes precedent
const agent = request.agent(); agent.buffer(false); const type = 'application/barrr'; const send = 'some random text2'; request.buffer[type] = true; agent .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(null, res.text); assert.equal(res.type, type); assert(!res.buffered); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal(send); done(); }); });
- should disable buffering for that mimetype when false
const type = 'application/bar'; const send = 'some random text'; request.buffer[type] = false; request .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(null, res.text); assert.equal(res.type, type); assert(!res.buffered); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal(send); done(); }); });
- should enable buffering for that mimetype when true
const type = 'application/baz'; const send = 'woooo'; request.buffer[type] = true; request .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(res.type, type); assert.equal(send, res.text); assert(res.buffered); done(); });
- should fallback to default handling for that mimetype when undefined
const type = 'application/bazzz'; const send = 'woooooo'; return request .post(`${base}/echo`) .type(type) .send(send) .then((res) => { assert.equal(res.type, type); assert.equal(send, res.body.toString()); assert(res.buffered); });
exports
- should expose .protocols
Object.keys(request.protocols).should.eql(['http:', 'https:', 'http2:']);
- should expose .serialize
Object.keys(request.serialize).should.eql([ 'application/x-www-form-urlencoded', 'application/json' ]);
- should expose .parse
Object.keys(request.parse).should.eql([ 'application/x-www-form-urlencoded', 'application/json', 'text', 'application/json-seq', 'application/octet-stream', 'application/pdf', 'image' ]);
- should export .buffer
Object.keys(request.buffer).should.eql([]);
flags
- should set res.error and res.clientError
request.get(`${base}/notfound`).end((error, res) => { assert(error); assert(!res.ok, 'response should not be ok'); assert(res.error, 'response should be an error'); assert(res.clientError, 'response should be a client error'); assert(!res.serverError, 'response should not be a server error'); done(); });
- should set res.error and res.serverError
request.get(`${base}/error`).end((error, res) => { assert(error); assert(!res.ok, 'response should not be ok'); assert(!res.notFound, 'response should not be notFound'); assert(res.error, 'response should be an error'); assert(!res.clientError, 'response should not be a client error'); assert(res.serverError, 'response should be a server error'); done(); });
- should res.notFound
request.get(`${base}/notfound`).end((error, res) => { assert(error); assert(res.notFound, 'response should be .notFound'); done(); });
- should set req.badRequest
request.get(`${base}/bad-request`).end((error, res) => { assert(error); assert(res.badRequest, 'response should be .badRequest'); done(); });
- should set res.unauthorized
request.get(`${base}/unauthorized`).end((error, res) => { assert(error); assert(res.unauthorized, 'response should be .unauthorized'); done(); });
- should set res.notAcceptable
request.get(`${base}/not-acceptable`).end((error, res) => { assert(error); assert(res.notAcceptable, 'response should be .notAcceptable'); done(); });
- should set res.noContent
request.get(`${base}/no-content`).end((error, res) => { assert(!error); assert(res.noContent, 'response should be .noContent'); done(); });
- should set res.created
request.post(`${base}/created`).end((error, res) => { assert(!error); assert(res.created, 'response should be .created'); done(); });
- should set res.unprocessableEntity
request.post(`${base}/unprocessable-entity`).end((error, res) => { assert(error); assert( res.unprocessableEntity, 'response should be .unprocessableEntity' ); done(); });
with 4xx response
with 5xx response
with 404 Not Found
with 400 Bad Request
with 401 Bad Request
with 406 Not Acceptable
with 204 No Content
with 201 Created
with 422 Unprocessable Entity
Merging objects
- Don't mix Buffer and JSON
assert.throws(() => { request .post('/echo') .send(Buffer.from('some buffer')) .send({ allowed: false }); });
req.send(String)
- should default to "form"
request .post(`${base}/echo`) .send('user[name]=tj') .send('user[email]=tj@vision-media.ca') .end((error, res) => { res.header['content-type'].should.equal( 'application/x-www-form-urlencoded' ); res.body.should.eql({ user: { name: 'tj', email: 'tj@vision-media.ca' } }); done(); });
res.body
- should parse the body
request.get(`${base}/form-data`).end((error, res) => { res.text.should.equal('pet[name]=manny'); res.body.should.eql({ pet: { name: 'manny' } }); done(); });
application/x-www-form-urlencoded
https
- should give a good response
request .get(testEndpoint) .ca(ca) .end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('Safe and secure!', res.text); done(); });
- should reject unauthorized response
return request .get(testEndpoint) .trustLocalhost(false) .then( () => { throw new Error('Allows MITM'); }, () => {} );
- should not reject unauthorized response
return request .get(testEndpoint) .disableTLSCerts() .then(({ status }) => { assert.strictEqual(status, 200); });
- should trust localhost unauthorized response
return request.get(testEndpoint).trustLocalhost(true);
- should trust overriden localhost unauthorized response
return request .get(`https://example.com:${server.address().port}`) .connect('127.0.0.1') .trustLocalhost();
- should be able to make multiple requests without redefining the certificate
const agent = request.agent({ ca }); agent.get(testEndpoint).end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('Safe and secure!', res.text); agent.get(url.parse(testEndpoint)).end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('Safe and secure!', res.text); done(); }); });
certificate authority
request
.agent
client certificates
request
.agent
res.body
- should parse the body
request.get(`${base}/image`).end((error, res) => { res.type.should.equal('image/png'); Buffer.isBuffer(res.body).should.be.true(); (res.body.length - img.length).should.equal(0); done(); });
- should parse the body
request .get(`${base}/image-as-octets`) .buffer(true) // that's tech debt :( .end((error, res) => { res.type.should.equal('application/octet-stream'); Buffer.isBuffer(res.body).should.be.true(); (res.body.length - img.length).should.equal(0); done(); });
- should parse the body (using responseType)
request .get(`${base}/image-as-octets`) .responseType('blob') .end((error, res) => { res.type.should.equal('application/octet-stream'); Buffer.isBuffer(res.body).should.be.true(); (res.body.length - img.length).should.equal(0); done(); });
image/png
application/octet-stream
application/octet-stream
zlib
- should deflate the content
request.get(base).end((error, res) => { res.should.have.status(200); res.text.should.equal(subject); res.headers['content-length'].should.be.below(subject.length); done(); });
- should protect from zip bombs
request .get(base) .buffer(true) .maxResponseSize(1) .end((error, res) => { try { assert.equal('Maximum response size reached', error && error.message); done(); } catch (err) { done(err); } });
- should ignore trailing junk
request.get(`${base}/junk`).end((error, res) => { res.should.have.status(200); res.text.should.equal(subject); done(); });
- should ignore missing data
request.get(`${base}/chopped`).end((error, res) => { assert.equal(undefined, error); res.should.have.status(200); res.text.should.startWith(subject); done(); });
- should handle corrupted responses
request.get(`${base}/corrupt`).end((error, res) => { assert(error, 'missing error'); assert(!res, 'response should not be defined'); done(); });
- should handle no content with gzip header
request.get(`${base}/nocontent`).end((error, res) => { assert.ifError(error); assert(res); res.should.have.status(204); res.text.should.equal(''); res.headers.should.not.have.property('content-length'); done(); });
- should buffer if asked
return request .get(`${base}/binary`) .buffer(true) .then((res) => { res.should.have.status(200); assert(res.headers['content-length']); assert(res.body.byteLength); assert.equal(subject, res.body.toString()); });
- should emit buffers
request.get(`${base}/binary`).end((error, res) => { res.should.have.status(200); res.headers['content-length'].should.be.below(subject.length); res.on('data', (chunk) => { chunk.should.have.length(subject.length); }); res.on('end', done); });
without encoding set
req.lookup()
- should set a custom lookup
const r = request.get(`${base}/ok`).lookup(myLookup); assert(r.lookup() === myLookup); r.then((res) => { res.text.should.equal('ok'); done(); });
Multipart
- should set a multipart field value
const request_ = request.post(`${base}/echo`); request_.field('user[name]', 'tobi'); request_.field('user[age]', '2'); request_.field('user[species]', 'ferret'); return request_.then((res) => { res.body['user[name]'].should.equal('tobi'); res.body['user[age]'].should.equal('2'); res.body['user[species]'].should.equal('ferret'); });
- should work with file attachments
const request_ = request.post(`${base}/echo`); request_.field('name', 'Tobi'); request_.attach('document', 'test/node/fixtures/user.html'); request_.field('species', 'ferret'); return request_.then((res) => { res.body.name.should.equal('Tobi'); res.body.species.should.equal('ferret'); const html = res.files.document; html.originalFilename.should.equal('user.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); });
- should attach a file
const request_ = request.post(`${base}/echo`); request_.attach('one', 'test/node/fixtures/user.html'); request_.attach('two', 'test/node/fixtures/user.json'); request_.attach('three', 'test/node/fixtures/user.txt'); return request_.then((res) => { const html = res.files.one; const json = res.files.two; const text = res.files.three; html.originalFilename.should.equal('user.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); json.originalFilename.should.equal('user.json'); json.mimetype.should.equal('application/json'); read(json.filepath).should.equal('{"name":"tobi"}'); text.originalFilename.should.equal('user.txt'); text.mimetype.should.equal('text/plain'); read(text.filepath).should.equal('Tobi'); });
- should fail the request with an error
const request_ = request.post(`${base}/echo`); request_.attach('name', 'foo'); // request_.attach('name2', 'bar'); // request_.attach('name3', 'baz'); request_.end((error, res) => { assert.ok(Boolean(error), 'Request should have failed.'); error.code.should.equal('ENOENT'); error.message.should.containEql('ENOENT'); if (IS_WINDOWS) { error.path.toLowerCase().should.equal( getFullPath('foo').toLowerCase() ); } else { error.path.should.equal(getFullPath('foo')); } done(); });
- promise should fail
return request .post(`${base}/echo`) .field({ a: 1, b: 2 }) .attach('c', 'does-not-exist.txt') .then( (res) => assert.fail('It should not allow this'), (err) => { err.code.should.equal('ENOENT'); if (IS_WINDOWS) { err.path.toLowerCase().should.equal( getFullPath('does-not-exist.txt').toLowerCase() ); } else { err.path.should.equal(getFullPath('does-not-exist.txt')); } } );
- should report ENOENT via the callback
request .post(`${base}/echo`) .attach('name', 'file-does-not-exist') .end((error, res) => { assert.ok(Boolean(error), 'Request should have failed'); error.code.should.equal('ENOENT'); done(); });
- should report ENOENT via Promise
return request .post(`${base}/echo`) .attach('name', 'file-does-not-exist') .then( (res) => assert.fail('Request should have failed'), (err) => err.code.should.equal('ENOENT') );
- should use the custom filename
request .post(`${base}/echo`) .attach('document', 'test/node/fixtures/user.html', 'doc.html') .then((res) => { const html = res.files.document; html.originalFilename.should.equal('doc.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); })
- should fire progress event
let loaded = 0; let total = 0; let uploadEventWasFired = false; request .post(`${base}/echo`) .attach('document', 'test/node/fixtures/user.html') .on('progress', (event) => { total = event.total; loaded = event.loaded; if (event.direction === 'upload') { uploadEventWasFired = true; } }) .end((error, res) => { if (error) return done(error); const html = res.files.document; html.originalFilename.should.equal('user.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); total.should.equal(223); loaded.should.equal(223); uploadEventWasFired.should.equal(true); done(); });
- filesystem errors should be caught
request .post(`${base}/echo`) .attach('filedata', 'test/node/fixtures/non-existent-file.ext') .end((error, res) => { assert.ok(Boolean(error), 'Request should have failed.'); error.code.should.equal('ENOENT'); if (IS_WINDOWS) { error.path.toLowerCase().should.equal( getFullPath('test/node/fixtures/non-existent-file.ext').toLowerCase() ); } else { error.path.should.equal( getFullPath('test/node/fixtures/non-existent-file.ext') ); } done(); });
- should set a multipart field value
request .post(`${base}/echo`) .field('first-name', 'foo') .field('last-name', 'bar') .end((error, res) => { if (error) done(error); res.should.be.ok(); res.body['first-name'].should.equal('foo'); res.body['last-name'].should.equal('bar'); done(); });
- should set multiple multipart fields
request .post(`${base}/echo`) .field({ 'first-name': 'foo', 'last-name': 'bar' }) .end((error, res) => { if (error) done(error); res.should.be.ok(); res.body['first-name'].should.equal('foo'); res.body['last-name'].should.equal('bar'); done(); });
#field(name, value)
#attach(name, path)
when a file does not exist
#attach(name, path, filename)
#field(name, val)
#field(object)
with network error
- should error
request.get(`http://localhost:${this.port}/`).end((error, res) => { assert(error, 'expected an error'); done(); });
request
- should start with 200
request.get(`${base}/if-mod`).end((error, res) => { res.should.have.status(200); res.text.should.match(/^\d+$/); ts = Number(res.text); done(); });
- should then be 304
request .get(`${base}/if-mod`) .set('If-Modified-Since', new Date(ts).toUTCString()) .end((error, res) => { res.should.have.status(304); // res.text.should.be.empty done(); });
not modified
req.parse(fn)
- should take precedence over default parsers
request .get(`${base}/manny`) .parse(request.parse['application/json']) .end((error, res) => { assert(res.ok); assert.equal('{"name":"manny"}', res.text); assert.equal('manny', res.body.name); done(); });
- should be the only parser
request .get(`${base}/image`) .buffer(false) .parse((res, fn) => { res.on('data', () => {}); }) .then((res) => { assert(res.ok); assert.strictEqual(res.text, undefined); res.body.should.eql({}); })
- should emit error if parser throws
request .get(`${base}/manny`) .parse(() => { throw new Error('I am broken'); }) .on('error', (error) => { error.message.should.equal('I am broken'); done(); }) .end();
- should emit error if parser returns an error
request .get(`${base}/manny`) .parse((res, fn) => { fn(new Error('I am broken')); }) .on('error', (error) => { error.message.should.equal('I am broken'); done(); }) .end();
- should not emit error on chunked json
request.get(`${base}/chunked-json`).end((error) => { assert.ifError(error); done(); });
- should not emit error on aborted chunked json
const request_ = request.get(`${base}/chunked-json`); request_.end((error) => { assert.ifError(error); done(); }); setTimeout(() => { request_.abort(); }, 50);
pipe on redirect
- should follow Location
const stream = fs.createWriteStream(destinationPath); const redirects = []; const request_ = request .get(base) .on('redirect', (res) => { redirects.push(res.headers.location); }) .connect({ inapplicable: 'should be ignored' }); stream.on('finish', () => { redirects.should.eql(['/movies', '/movies/all', '/movies/all/0']); fs.readFileSync(destinationPath, 'utf8').should.eql('first movie page'); done(); }); request_.pipe(stream);
request pipe
- should act as a writable stream
const request_ = request.post(base); const stream = fs.createReadStream('test/node/fixtures/user.json'); request_.type('json'); request_.on('response', (res) => { res.body.should.eql({ name: 'tobi' }); done(); }); stream.pipe(request_);
- end() stops piping
const stream = fs.createWriteStream(destinationPath); request.get(base).end((error, res) => { try { res.pipe(stream); return done(new Error('Did not prevent nonsense pipe')); } catch { /* expected error */ } done(); });
- should act as a readable stream
const stream = fs.createWriteStream(destinationPath); let responseCalled = false; const request_ = request.get(base); request_.type('json'); request_.on('response', (res) => { res.status.should.eql(200); responseCalled = true; }); stream.on('finish', () => { JSON.parse(fs.readFileSync(destinationPath)).should.eql({ name: 'tobi' }); responseCalled.should.be.true(); done(); }); request_.pipe(stream);
- should follow redirects
const stream = fs.createWriteStream(destinationPath); let responseCalled = false; const request_ = request.get(base + '/redirect'); request_.type('json'); request_.on('response', (res) => { res.status.should.eql(200); responseCalled = true; }); stream.on('finish', () => { JSON.parse(fs.readFileSync(destinationPath)).should.eql({ name: 'tobi' }); responseCalled.should.be.true(); done(); }); request_.pipe(stream);
- should not throw on bad redirects
const stream = fs.createWriteStream(destinationPath); let responseCalled = false; let errorCalled = false; const request_ = request.get(base + '/badRedirectNoLocation'); request_.type('json'); request_.on('response', (res) => { responseCalled = true; }); request_.on('error', (error) => { error.message.should.eql('No location header for redirect'); errorCalled = true; stream.end(); }); stream.on('finish', () => { responseCalled.should.be.false(); errorCalled.should.be.true(); done(); }); request_.pipe(stream);
req.query(String)
- should support passing in a string
request .del(base) .query('name=t%F6bi') .end((error, res) => { res.body.should.eql({ name: 't%F6bi' }); done(); });
- should work with url query-string and string for query
request .del(`${base}/?name=tobi`) .query('age=2%20') .end((error, res) => { res.body.should.eql({ name: 'tobi', age: '2 ' }); done(); });
- should support compound elements in a string
request .del(base) .query('name=t%F6bi&age=2') .end((error, res) => { res.body.should.eql({ name: 't%F6bi', age: '2' }); done(); });
- should work when called multiple times with a string
request .del(base) .query('name=t%F6bi') .query('age=2%F6') .end((error, res) => { res.body.should.eql({ name: 't%F6bi', age: '2%F6' }); done(); });
- should work with normal `query` object and query string
request .del(base) .query('name=t%F6bi') .query({ age: '2' }) .end((error, res) => { res.body.should.eql({ name: 't%F6bi', age: '2' }); done(); });
- should not encode raw backticks, but leave encoded ones as is
return Promise.all([ request .get(`${base}/raw-query`) .query('name=`t%60bi`&age`=2') .then((res) => { res.text.should.eql('name=`t%60bi`&age`=2'); }), request.get(base + '/raw-query?`age%60`=2%60`').then((res) => { res.text.should.eql('`age%60`=2%60`'); }), request .get(`${base}/raw-query`) .query('name=`t%60bi`') .query('age`=2') .then((res) => { res.text.should.eql('name=`t%60bi`&age`=2'); }) ]);
req.query(Object)
- should construct the query-string
request .del(base) .query({ name: 'tobi' }) .query({ order: 'asc' }) .query({ limit: ['1', '2'] }) .end((error, res) => { res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] }); done(); });
- should encode raw backticks
request .get(`${base}/raw-query`) .query({ name: '`tobi`' }) .query({ 'orde%60r': null }) .query({ '`limit`': ['%602`'] }) .end((error, res) => { res.text.should.eql('name=%60tobi%60&orde%2560r&%60limit%60=%25602%60'); done(); });
- should not error on dates
const date = new Date(0); request .del(base) .query({ at: date }) .end((error, res) => { assert.equal(date.toISOString(), res.body.at); done(); });
- should work after setting header fields
request .del(base) .set('Foo', 'bar') .set('Bar', 'baz') .query({ name: 'tobi' }) .query({ order: 'asc' }) .query({ limit: ['1', '2'] }) .end((error, res) => { res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] }); done(); });
- should append to the original query-string
request .del(`${base}/?name=tobi`) .query({ order: 'asc' }) .end((error, res) => { res.body.should.eql({ name: 'tobi', order: 'asc' }); done(); });
- should retain the original query-string
request.del(`${base}/?name=tobi`).end((error, res) => { res.body.should.eql({ name: 'tobi' }); done(); });
- should keep only keys with null querystring values
request .del(`${base}/url`) .query({ nil: null }) .end((error, res) => { res.text.should.equal('/url?nil'); done(); });
- query-string should be sent on pipe
this.timeout(15_000); const request_ = request.put(`${base}/?name=tobi`); const stream = fs.createReadStream('test/node/fixtures/user.json'); request_.on('response', (res) => { res.body.should.eql({ name: 'tobi' }); done(); }); request_.on('error', (err) => { done(err); }); stream.on('error', function (err) { done(err); }); stream.pipe(request_);
request.get
- should follow Location with a GET request
const request_ = request.get(`${base}/test-301`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-302`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-303`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-307`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-308`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
on 301 redirect
on 302 redirect
on 303 redirect
on 307 redirect
on 308 redirect
request.post
- should follow Location with a GET request
const request_ = request.post(`${base}/test-301`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.post(`${base}/test-302`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.post(`${base}/test-303`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a POST request
const request_ = request.post(`${base}/test-307`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('POST'); done(); });
- should follow Location with a POST request
const request_ = request.post(`${base}/test-308`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('POST'); done(); });
on 301 redirect
on 302 redirect
on 303 redirect
on 307 redirect
on 308 redirect
request
- should merge cookies if agent is used
request .agent() .get(`${base}/cookie-redirect`) .set('Cookie', 'orig=1; replaced=not') .end((error, res) => { try { assert.ifError(error); assert(/orig=1/.test(res.text), 'orig=1/.test'); assert(/replaced=yes/.test(res.text), 'replaced=yes/.test'); assert(/from-redir=1/.test(res.text), 'from-redir=1'); done(); } catch (err) { done(err); } });
- should not merge cookies if agent is not used
request .get(`${base}/cookie-redirect`) .set('Cookie', 'orig=1; replaced=not') .end((error, res) => { try { assert.ifError(error); assert(/orig=1/.test(res.text), '/orig=1'); assert(/replaced=not/.test(res.text), '/replaced=not'); assert(!/replaced=yes/.test(res.text), '!/replaced=yes'); assert(!/from-redir/.test(res.text), '!/from-redir'); done(); } catch (err) { done(err); } });
- should have previously set cookie for subsquent requests when agent is used
const agent = request.agent(); agent.get(`${base}/set-cookie`).end((error) => { assert.ifError(error); agent .get(`${base}/show-cookies`) .set({ Cookie: 'orig=1' }) .end((error, res) => { try { assert.ifError(error); assert(/orig=1/.test(res.text), 'orig=1/.test'); assert(/persist=123/.test(res.text), 'persist=123'); done(); } catch (err) { done(err); } }); });
- should follow Location
const redirects = []; request .get(base) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { const array = ['/movies', '/movies/all', '/movies/all/0']; redirects.should.eql(array); res.text.should.equal('first movie page'); done(); } catch (err) { done(err); } });
- should follow Location with IP override
const redirects = []; const url = URL.parse(base); return request .get(`http://redir.example.com:${url.port || '80'}${url.pathname}`) .connect({ '*': url.hostname }) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { const array = ['/movies', '/movies/all', '/movies/all/0']; redirects.should.eql(array); res.text.should.equal('first movie page'); });
- should follow Location with IP:port override
const redirects = []; const url = URL.parse(base); return request .get(`http://redir.example.com:9999${url.pathname}`) .connect({ '*': { host: url.hostname, port: url.port || 80 } }) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { const array = ['/movies', '/movies/all', '/movies/all/0']; redirects.should.eql(array); res.text.should.equal('first movie page'); });
- should not follow on HEAD by default
const redirects = []; return request .head(base) .ok(() => true) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { redirects.should.eql([]); res.status.should.equal(302); });
- should follow on HEAD when redirects are set
const redirects = []; request .head(base) .redirects(10) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { const array = []; array.push('/movies', '/movies/all', '/movies/all/0'); redirects.should.eql(array); assert(!res.text); done(); } catch (err) { done(err); } });
- should remove Content-* fields
request .post(`${base}/header`) .type('txt') .set('X-Foo', 'bar') .set('X-Bar', 'baz') .send('hey') .end((error, res) => { try { assert(res.body); res.body.should.have.property('x-foo', 'bar'); res.body.should.have.property('x-bar', 'baz'); res.body.should.not.have.property('content-type'); res.body.should.not.have.property('content-length'); res.body.should.not.have.property('transfer-encoding'); done(); } catch (err) { done(err); } });
- should retain cookies
request .get(`${base}/header`) .set('Cookie', 'foo=bar;') .end((error, res) => { try { assert(res.body); res.body.should.have.property('cookie', 'foo=bar;'); done(); } catch (err) { done(err); } });
- should not resend query parameters
const redirects = []; const query = []; request .get(`${base}/?foo=bar`) .on('redirect', (res) => { query.push(res.headers.query); redirects.push(res.headers.location); }) .end((error, res) => { try { const array = []; array.push('/movies', '/movies/all', '/movies/all/0'); redirects.should.eql(array); res.text.should.equal('first movie page'); query.should.eql(['{"foo":"bar"}', '{}', '{}']); res.headers.query.should.eql('{}'); done(); } catch (err) { done(err); } });
- should handle no location header
request.get(`${base}/bad-redirect`).end((error, res) => { try { error.message.should.equal('No location header for redirect'); done(); } catch (err) { done(err); } });
- should redirect to a sibling path
const redirects = []; request .get(`${base}/relative`) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { redirects.should.eql(['tobi']); res.text.should.equal('tobi'); done(); } catch (err) { done(err); } });
- should redirect to a parent path
const redirects = []; request .get(`${base}/relative/sub`) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { redirects.should.eql(['../tobi']); res.text.should.equal('tobi'); done(); } catch (err) { done(err); } });
- should alter the default number of redirects to follow
const redirects = []; request .get(base) .redirects(2) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { const array = []; assert(res.redirect, 'res.redirect'); array.push('/movies', '/movies/all'); redirects.should.eql(array); res.text.should.match(/Moved Temporarily|Found/); done(); } catch (err) { done(err); } });
- should redirect as GET
const redirects = []; return request .post(`${base}/movie`) .send({ name: 'Tobi' }) .redirects(2) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { redirects.should.eql(['/movies/all/0']); res.text.should.equal('first movie page'); });
- using multipart/form-data should redirect as GET
const redirects = []; request .post(`${base}/movie`) .type('form') .field('name', 'Tobi') .redirects(2) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { redirects.should.eql(['/movies/all/0']); res.text.should.equal('first movie page'); });
on redirect
when relative
req.redirects(n)
on POST
response
- should act as a readable stream
const request_ = request.get(base).buffer(false); request_.end((error, res) => { if (error) return done(error); let trackEndEvent = 0; let trackCloseEvent = 0; res.on('end', () => { trackEndEvent++; trackEndEvent.should.equal(1); if (!process.env.HTTP2_TEST) { trackCloseEvent.should.equal(0); // close should not have been called } done(); }); res.on('close', () => { trackCloseEvent++; }); setTimeout(() => { (() => { res.pause(); }).should.not.throw(); (() => { res.resume(); }).should.not.throw(); (() => { res.destroy(); }).should.not.throw(); }, 50); });
req.serialize(fn)
- should take precedence over default parsers
request .post(`${base}/echo`) .send({ foo: 123 }) .serialize(() => '{"bar":456}') .end((error, res) => { assert.ifError(error); assert.equal('{"bar":456}', res.text); assert.equal(456, res.body.bar); done(); });
request.get().set()
- should set host header after get()
app.get('/', (request_, res) => { assert.equal(request_.hostname, 'example.com'); res.end(); }); server = http.createServer(app); server.listen(0, function listening() { request .get(`http://localhost:${server.address().port}`) .set('host', 'example.com') .then(() => { return request .get(`http://example.com:${server.address().port}`) .connect({ 'example.com': 'localhost', '*': 'fail' }); }) .then(() => done(), done); });
res.toError()
- should return an Error
request.get(base).end((err, res) => { const error = res.toError(); assert.equal(error.status, 400); assert.equal(error.method, 'GET'); assert.equal(error.path, '/'); assert.equal(error.message, 'cannot GET / (400)'); assert.equal(error.text, 'invalid json'); done(); });
[unix-sockets] http
- path: / (root)
request.get(`${base}/`).end((error, res) => { assert(res.ok); assert.strictEqual('root ok!', res.text); done(); });
- path: /request/path
request.get(`${base}/request/path`).end((error, res) => { assert(res.ok); assert.strictEqual('request path ok!', res.text); done(); });
request
[unix-sockets] https
- path: / (root)
request .get(`${base}/`) .ca(cacert) .end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('root ok!', res.text); done(); });
- path: /request/path
request .get(`${base}/request/path`) .ca(cacert) .end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('request path ok!', res.text); done(); });
request
req.get()
- should not set a default user-agent
request.get(`${base}/ua`).then((res) => { assert(res.headers); assert(!res.headers['user-agent']); })
utils.type(str)
- should return the mime type
utils .type('application/json; charset=utf-8') .should.equal('application/json'); utils.type('application/json').should.equal('application/json');
utils.params(str)
- should return the field parameters
const object = utils.params('application/json; charset=utf-8; foo = bar'); object.charset.should.equal('utf-8'); object.foo.should.equal('bar'); utils.params('application/json').should.eql({});
utils.parseLinks(str)
- should parse links
const string_ = '<https://api.github.com/repos/visionmedia/mocha/issues?page=2>; rel="next", <https://api.github.com/repos/visionmedia/mocha/issues?page=5>; rel="last"'; const returnValue = utils.parseLinks(string_); returnValue.next.should.equal( 'https://api.github.com/repos/visionmedia/mocha/issues?page=2' ); returnValue.last.should.equal( 'https://api.github.com/repos/visionmedia/mocha/issues?page=5' );
Agent
- should remember defaults
if (typeof Promise === 'undefined') { return; } let called = 0; let event_called = 0; const agent = request .agent() .accept('json') .use(() => { called++; }) .once('request', () => { event_called++; }) .query({ hello: 'world' }) .set('X-test', 'testing'); assert.equal(0, called); assert.equal(0, event_called); return agent .get(`${base}/echo`) .then((res) => { assert.equal(1, called); assert.equal(1, event_called); assert.equal('application/json', res.headers.accept); assert.equal('testing', res.headers['x-test']); return agent.get(`${base}/querystring`); }) .then((res) => { assert.equal(2, called); assert.equal(2, event_called); assert.deepEqual({ hello: 'world' }, res.body); });
request
- should set statusCode
request.get(`${uri}/login`, (error, res) => { try { assert.strictEqual(res.statusCode, 200); done(); } catch (err) { done(err); } });
- with callback in the method call
request.get(`${uri}/login`, (error, res) => { assert.equal(res.status, 200); done(); });
- with data in the method call
request.post(`${uri}/echo`, { foo: 'bar' }).end((error, res) => { assert.equal('{"foo":"bar"}', res.text); done(); });
- with callback and data in the method call
request.post(`${uri}/echo`, { foo: 'bar' }, (error, res) => { assert.equal('{"foo":"bar"}', res.text); done(); });
- should invoke .end()
request.get(`${uri}/login`, (error, res) => { try { assert.equal(res.status, 200); done(); } catch (err) { done(err); } });
- should issue a request
request.get(`${uri}/login`).end((error, res) => { try { assert.equal(res.status, 200); done(); } catch (err) { done(err); } });
- is optional with a promise
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/login`) .then((res) => res.status) .then() .then((status) => { assert.equal(200, status, 'Real promises pass results through'); });
- called only once with a promise
if (typeof Promise === 'undefined') { return; } const request_ = request.get(`${uri}/unique`); return Promise.all([request_, request_, request_]).then((results) => { for (const item of results) { assert.deepEqual( item.body, results[0].body, 'It should keep returning the same result after being called once' ); } });
- ok
let calledErrorEvent = false; let calledOKHandler = false; request .get(`${uri}/error`) .ok((res) => { assert.strictEqual(500, res.status); calledOKHandler = true; return true; }) .on('error', (error) => { calledErrorEvent = true; }) .end((error, res) => { try { assert.ifError(error); assert.strictEqual(res.status, 500); assert(!calledErrorEvent); assert(calledOKHandler); done(); } catch (err) { done(err); } });
- should be an Error object
let calledErrorEvent = false; request .get(`${uri}/error`) .on('error', (error) => { assert.strictEqual(error.status, 500); calledErrorEvent = true; }) .end((error, res) => { try { if (NODE) { res.error.message.should.equal('cannot GET /error (500)'); } else { res.error.message.should.equal(`cannot GET ${uri}/error (500)`); } assert.strictEqual(res.error.status, 500); assert(error, 'should have an error for 500'); assert.equal(error.message, 'Internal Server Error'); assert(calledErrorEvent); done(); } catch (err) { done(err); } });
- with .then() promise
if (typeof Promise === 'undefined') { return; } return request.get(`${uri}/error`).then( () => { assert.fail(); }, (err) => { assert.equal(err.message, 'Internal Server Error'); } );
- with .ok() returning false
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/echo`) .ok(() => false) .then( () => { assert.fail(); }, (err) => { assert.equal(200, err.response.status); assert.equal(err.message, 'OK'); } );
- with .ok() throwing an Error
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/echo`) .ok(() => { throw new Error('boom'); }) .then( () => { assert.fail(); }, (err) => { assert.equal(200, err.status); assert.equal(200, err.response.status); assert.equal(err.message, 'boom'); } );
- with .ok() throwing an Error with status
if (typeof Promise === 'undefined') { return; } return request .get(`${uri}/echo`) .ok(() => { const err = new Error('boom'); err.status = 404; throw err; }) .then( () => { assert.fail(); }, (err) => { assert.equal(404, err.status); assert.equal(200, err.response.status); assert.equal(err.message, 'boom'); } );
- should be an object
request.get(`${uri}/login`).end((error, res) => { try { assert.equal('Express', res.header['x-powered-by']); done(); } catch (err) { done(err); } });
- should only set headers for ownProperties of header
try { request .get(`${uri}/echo-headers`) .set('valid', 'ok') .end((error, res) => { if ( !error && res.body && res.body.valid && !res.body.hasOwnProperty('invalid') ) { return done(); } done(error || new Error('fail')); }); } catch (err) { done(err); }
- should be set when present
request.get(`${uri}/login`).end((error, res) => { try { res.charset.should.equal('utf-8'); done(); } catch (err) { done(err); } });
- should provide the first digit
request.get(`${uri}/login`).end((error, res) => { try { assert(!error, 'should not have an error for success responses'); assert.equal(200, res.status); assert.equal(2, res.statusType); done(); } catch (err) { done(err); } });
- should provide the mime-type void of params
request.get(`${uri}/login`).end((error, res) => { try { res.type.should.equal('text/html'); res.charset.should.equal('utf-8'); done(); } catch (err) { done(err); } });
- should set the header field
request .post(`${uri}/echo`) .set('X-Foo', 'bar') .set('X-Bar', 'baz') .end((error, res) => { try { assert.equal('bar', res.header['x-foo']); assert.equal('baz', res.header['x-bar']); done(); } catch (err) { done(err); } });
- should set the header fields
request .post(`${uri}/echo`) .set({ 'X-Foo': 'bar', 'X-Bar': 'baz' }) .end((error, res) => { try { assert.equal('bar', res.header['x-foo']); assert.equal('baz', res.header['x-bar']); done(); } catch (err) { done(err); } });
- should set the Content-Type
request .post(`${uri}/echo`) .type('text/x-foo') .end((error, res) => { try { res.header['content-type'].should.equal('text/x-foo'); done(); } catch (err) { done(err); } });
- should map "json"
request .post(`${uri}/echo`) .type('json') .send('{"a": 1}') .end((error, res) => { try { res.should.be.json(); done(); } catch (err) { done(err); } });
- should map "html"
request .post(`${uri}/echo`) .type('html') .end((error, res) => { try { res.header['content-type'].should.equal('text/html'); done(); } catch (err) { done(err); } });
- should set Accept
request .get(`${uri}/echo`) .accept('text/x-foo') .end((error, res) => { try { res.header.accept.should.equal('text/x-foo'); done(); } catch (err) { done(err); } });
- should map "json"
request .get(`${uri}/echo`) .accept('json') .end((error, res) => { try { res.header.accept.should.equal('application/json'); done(); } catch (err) { done(err); } });
- should map "xml"
request .get(`${uri}/echo`) .accept('xml') .end((error, res) => { try { // Mime module keeps changing this :( assert( res.header.accept == 'application/xml' || res.header.accept == 'text/xml' ); done(); } catch (err) { done(err); } });
- should map "html"
request .get(`${uri}/echo`) .accept('html') .end((error, res) => { try { res.header.accept.should.equal('text/html'); done(); } catch (err) { done(err); } });
- should write the string
request .post(`${uri}/echo`) .type('json') .send('{"name":"tobi"}') .end((error, res) => { try { res.text.should.equal('{"name":"tobi"}'); done(); } catch (err) { done(err); } });
- should default to json
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .end((error, res) => { try { res.should.be.json(); res.text.should.equal('{"name":"tobi"}'); done(); } catch (err) { done(err); } });
- should merge the objects
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .send({ age: 1 }) .end((error, res) => { try { res.should.be.json(); if (NODE) { res.buffered.should.be.true(); } res.text.should.equal('{"name":"tobi","age":1}'); done(); } catch (err) { done(err); } });
- should check arity
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .end((error, res) => { try { assert.ifError(error); res.text.should.equal('{"name":"tobi"}'); done(); } catch (err) { done(err); } });
- should emit request
const request_ = request.post(`${uri}/echo`); request_.on('request', (request) => { assert.equal(request_, request); done(); }); request_.end();
- should emit response
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .on('response', (res) => { res.text.should.equal('{"name":"tobi"}'); done(); }) .end();
- should support successful fulfills with .then(fulfill)
if (typeof Promise === 'undefined') { return done(); } request .post(`${uri}/echo`) .send({ name: 'tobi' }) .then((res) => { res.type.should.equal('application/json'); res.text.should.equal('{"name":"tobi"}'); done(); });
- should reject an error with .then(null, reject)
if (typeof Promise === 'undefined') { return done(); } request.get(`${uri}/error`).then(null, (err) => { assert.equal(err.status, 500); assert.equal(err.response.text, 'boom'); done(); });
- should reject an error with .catch(reject)
if (typeof Promise === 'undefined') { return done(); } request.get(`${uri}/error`).catch((err) => { assert.equal(err.status, 500); assert.equal(err.response.text, 'boom'); done(); });
- should abort the request
const request_ = request.get(`${uri}/delay/3000`); request_.end((error, res) => { try { assert(false, 'should not complete the request'); } catch (err) { done(err); } }); request_.on('error', (error) => { done(error); }); request_.on('abort', done); setTimeout(() => { request_.abort(); }, 500);
- should abort the promise
const request_ = request.get(`${uri}/delay/3000`); setTimeout(() => { request_.abort(); }, 10); return request_.then( () => { assert.fail('should not complete the request'); }, (err) => { assert.equal('ABORTED', err.code); } );
- should allow chaining .abort() several times
const request_ = request.get(`${uri}/delay/3000`); request_.end((error, res) => { try { assert(false, 'should not complete the request'); } catch (err) { done(err); } }); // This also verifies only a single 'done' event is emitted request_.on('abort', done); setTimeout(() => { request_.abort().abort().abort(); }, 1000);
- should not allow abort then end
request .get(`${uri}/delay/3000`) .abort() .end((error, res) => { done(error ? undefined : new Error('Expected abort error')); });
- should describe the request
const request_ = request.post(`${uri}/echo`).send({ foo: 'baz' }); request_.end((error, res) => { try { const json = request_.toJSON(); assert.equal('POST', json.method); assert(/\/echo$/.test(json.url)); assert.equal('baz', json.data.foo); done(); } catch (err) { done(err); } });
- should allow request body
request .options(`${uri}/options/echo/body`) .send({ foo: 'baz' }) .end((error, res) => { try { assert.equal(error, null); assert.strictEqual(res.body.foo, 'baz'); done(); } catch (err) { done(err); } });
- nop with no querystring
request .get(`${uri}/url`) .sortQuery() .end((error, res) => { try { assert.equal(res.text, '/url'); done(); } catch (err) { done(err); } });
- should sort the request querystring
request .get(`${uri}/url`) .query('search=Manny') .query('order=desc') .sortQuery() .end((error, res) => { try { assert.equal(res.text, '/url?order=desc&search=Manny'); done(); } catch (err) { done(err); } });
- should allow disabling sorting
request .get(`${uri}/url`) .query('search=Manny') .query('order=desc') .sortQuery() // take default of true .sortQuery(false) // override it in later call .end((error, res) => { try { assert.equal(res.text, '/url?search=Manny&order=desc'); done(); } catch (err) { done(err); } });
- should sort the request querystring using customized function
request .get(`${uri}/url`) .query('name=Nick') .query('search=Manny') .query('order=desc') .sortQuery((a, b) => a.length - b.length) .end((error, res) => { try { assert.equal(res.text, '/url?name=Nick&order=desc&search=Manny'); done(); } catch (err) { done(err); } });
res.statusCode
should allow the send shorthand
with a callback
.end()
res.error
res.header
set headers
res.charset
res.statusType
res.type
req.set(field, val)
req.set(obj)
req.type(str)
req.accept(str)
req.send(str)
req.send(Object)
when called several times
.end(fn)
.then(fulfill, reject)
.catch(reject)
.abort()
req.toJSON()
req.options()
req.sortQuery()
req.set("Content-Type", contentType)
- should work with just the contentType component
request .post(`${uri}/echo`) .set('Content-Type', 'application/json') .send({ name: 'tobi' }) .end((error) => { assert(!error); done(); });
- should work with the charset component
request .post(`${uri}/echo`) .set('Content-Type', 'application/json; charset=utf-8') .send({ name: 'tobi' }) .end((error) => { assert(!error); done(); });
req.send(Object) as "form"
- should send x-www-form-urlencoded data
request .post(`${base}/echo`) .type('form') .send({ name: 'tobi' }) .end((error, res) => { res.header['content-type'].should.equal( 'application/x-www-form-urlencoded' ); res.text.should.equal('name=tobi'); done(); });
- should merge the objects
request .post(`${base}/echo`) .type('form') .send({ name: { first: 'tobi', last: 'holowaychuk' } }) .send({ age: '1' }) .end((error, res) => { res.header['content-type'].should.equal( 'application/x-www-form-urlencoded' ); res.text.should.equal( 'name%5Bfirst%5D=tobi&name%5Blast%5D=holowaychuk&age=1' ); done(); });
with req.type() set to form
when called several times
req.attach
- ignores null file
request .post('/echo') .attach('image', null) .end((error, res) => { done(); });
req.field
- allow bools
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field('bools', true) .field('strings', 'true') .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { bools: 'true', strings: 'true' }); done(); });
- allow objects
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field({ bools: true, strings: 'true' }) .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { bools: 'true', strings: 'true' }); done(); });
- works with arrays in objects
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field({ numbers: [1, 2, 3] }) .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { numbers: ['1', '2', '3'] }); done(); });
- works with arrays
if (!formDataSupported) { return done(); } request .post(`${base}/formecho`) .field('letters', ['a', 'b', 'c']) .end((error, res) => { assert.ifError(error); assert.deepStrictEqual(res.body, { letters: ['a', 'b', 'c'] }); done(); });
- throw when empty
should.throws(() => { request.post(`${base}/echo`).field(); }, /name/); should.throws(() => { request.post(`${base}/echo`).field('name'); }, /val/);
- cannot be mixed with send()
assert.throws(() => { request.post('/echo').field('form', 'data').send('hi'); }); assert.throws(() => { request.post('/echo').send('hi').field('form', 'data'); });
req.send(Object) as "json"
- should default to json
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .end((error, res) => { res.should.be.json(); res.text.should.equal('{"name":"tobi"}'); done(); });
- should work with arrays
request .post(`${uri}/echo`) .send([1, 2, 3]) .end((error, res) => { res.should.be.json(); res.text.should.equal('[1,2,3]'); done(); });
- should work with value null
request .post(`${uri}/echo`) .type('json') .send('null') .end((error, res) => { res.should.be.json(); assert.strictEqual(res.body, null); done(); });
- should work with value false
request .post(`${uri}/echo`) .type('json') .send('false') .end((error, res) => { res.should.be.json(); res.body.should.equal(false); done(); });
- should work with empty string value
request .post(`${uri}/echo`) .type('json') .send('""') .end((error, res) => { res.should.be.json(); res.body.should.equal(''); done(); });
- should work with vendor MIME type
request .post(`${uri}/echo`) .set('Content-Type', 'application/vnd.example+json') .send({ name: 'vendor' }) .end((error, res) => { res.text.should.equal('{"name":"vendor"}'); ({ name: 'vendor' }.should.eql(res.body)); done(); });
- should merge the objects
request .post(`${uri}/echo`) .send({ name: 'tobi' }) .send({ age: 1 }) .end((error, res) => { res.should.be.json(); res.text.should.equal('{"name":"tobi","age":1}'); ({ name: 'tobi', age: 1 }.should.eql(res.body)); done(); });
when called several times
res.body
- should parse the body
request.get(`${uri}/json`).end((error, res) => { res.text.should.equal('{"name":"manny"}'); res.body.should.eql({ name: 'manny' }); done(); });
- should return the raw response
request.get(`${uri}/invalid-json`).end((error, res) => { assert.deepEqual( error.rawResponse, ")]}', {'header':{'code':200,'text':'OK','version':'1.0'},'data':'some data'}" ); done(); });
- should return the http status code
request.get(`${uri}/invalid-json-forbidden`).end((error, res) => { assert.equal(error.statusCode, 403); done(); });
application/json
Invalid JSON response
request
- should retain header fields
request .get(`${base}/header`) .set('X-Foo', 'bar') .end((error, res) => { try { assert(res.body); res.body.should.have.property('x-foo', 'bar'); done(); } catch (err) { done(err); } });
- should preserve timeout across redirects
request .get(`${base}/movies/random`) .timeout(250) .end((error, res) => { try { assert(error instanceof Error, 'expected an error'); error.should.have.property('timeout', 250); done(); } catch (err) { done(err); } });
- should successfully redirect after retry on error
const id = Math.random() * 1_000_000 * Date.now(); request .get(`${base}/error/redirect/${id}`) .retry(2) .end((error, res) => { assert(res.ok, 'response should be ok'); assert(res.text, 'first movie page'); done(); });
- should preserve retries across redirects
const id = Math.random() * 1_000_000 * Date.now(); request .get(`${base}/error/redirect-error${id}`) .retry(2) .end((error, res) => { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); });
- should redirect with same method
request .put(`${base}/redirect-303`) .send({ msg: 'hello' }) .redirects(1) .on('redirect', (res) => { res.headers.location.should.equal('/reply-method'); }) .end((error, res) => { if (error) { done(error); return; } res.text.should.equal('method=get'); done(); });
- should redirect with same method
if (isMSIE) return done(); // IE9 broken request .put(`${base}/redirect-307`) .send({ msg: 'hello' }) .redirects(1) .on('redirect', (res) => { res.headers.location.should.equal('/reply-method'); }) .end((error, res) => { if (error) { done(error); return; } res.text.should.equal('method=put'); done(); });
- should redirect with same method
if (isMSIE) return done(); // IE9 broken request .put(`${base}/redirect-308`) .send({ msg: 'hello' }) .redirects(1) .on('redirect', (res) => { res.headers.location.should.equal('/reply-method'); }) .end((error, res) => { if (error) { done(error); return; } res.text.should.equal('method=put'); done(); });
on redirect
on 303
on 307
on 308
request
- Request inheritance
assert(request.get(`${uri}/`) instanceof request.Request);
- request() simple GET without callback
request('GET', 'test/test.request.js').end(); next();
- request() simple GET
request('GET', `${uri}/ok`).end((error, res) => { try { assert(res instanceof request.Response, 'respond with Response'); assert(res.ok, 'response should be ok'); assert(res.text, 'res.text'); next(); } catch (err) { next(err); } });
- request() simple HEAD
request.head(`${uri}/ok`).end((error, res) => { try { assert(res instanceof request.Response, 'respond with Response'); assert(res.ok, 'response should be ok'); assert(!res.text, 'res.text'); next(); } catch (err) { next(err); } });
- request() GET 5xx
request('GET', `${uri}/error`).end((error, res) => { try { assert(error); assert.equal(error.message, 'Internal Server Error'); assert(!res.ok, 'response should not be ok'); assert(res.error, 'response should be an error'); assert(!res.clientError, 'response should not be a client error'); assert(res.serverError, 'response should be a server error'); next(); } catch (err) { next(err); } });
- request() GET 4xx
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal(error.message, 'Not Found'); assert(!res.ok, 'response should not be ok'); assert(res.error, 'response should be an error'); assert(res.clientError, 'response should be a client error'); assert(!res.serverError, 'response should not be a server error'); next(); } catch (err) { next(err); } });
- request() GET 404 Not Found
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert(res.notFound, 'response should be .notFound'); next(); } catch (err) { next(err); } });
- request() GET 400 Bad Request
request('GET', `${uri}/bad-request`).end((error, res) => { try { assert(error); assert(res.badRequest, 'response should be .badRequest'); next(); } catch (err) { next(err); } });
- request() GET 401 Bad Request
request('GET', `${uri}/unauthorized`).end((error, res) => { try { assert(error); assert(res.unauthorized, 'response should be .unauthorized'); next(); } catch (err) { next(err); } });
- request() GET 406 Not Acceptable
request('GET', `${uri}/not-acceptable`).end((error, res) => { try { assert(error); assert(res.notAcceptable, 'response should be .notAcceptable'); next(); } catch (err) { next(err); } });
- request() GET 204 No Content
request('GET', `${uri}/no-content`).end((error, res) => { try { assert.ifError(error); assert(res.noContent, 'response should be .noContent'); next(); } catch (err) { next(err); } });
- request() DELETE 204 No Content
request('DELETE', `${uri}/no-content`).end((error, res) => { try { assert.ifError(error); assert(res.noContent, 'response should be .noContent'); next(); } catch (err) { next(err); } });
- request() header parsing
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal('text/html; charset=utf-8', res.header['content-type']); assert.equal('Express', res.header['x-powered-by']); next(); } catch (err) { next(err); } });
- request() .status
request('GET', `${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal(404, res.status, 'response .status'); assert.equal(4, res.statusType, 'response .statusType'); next(); } catch (err) { next(err); } });
- get()
request.get(`${uri}/notfound`).end((error, res) => { try { assert(error); assert.equal(404, res.status, 'response .status'); assert.equal(4, res.statusType, 'response .statusType'); next(); } catch (err) { next(err); } });
- put()
request.put(`${uri}/user/12`).end((error, res) => { try { assert.equal('updated', res.text, 'response text'); next(); } catch (err) { next(err); } });
- put().send()
request .put(`${uri}/user/13/body`) .send({ user: 'new' }) .end((error, res) => { try { assert.equal('received new', res.text, 'response text'); next(); } catch (err) { next(err); } });
- post()
request.post(`${uri}/user`).end((error, res) => { try { assert.equal('created', res.text, 'response text'); next(); } catch (err) { next(err); } });
- del()
request.del(`${uri}/user/12`).end((error, res) => { try { assert.equal('deleted', res.text, 'response text'); next(); } catch (err) { next(err); } });
- delete()
request.delete(`${uri}/user/12`).end((error, res) => { try { assert.equal('deleted', res.text, 'response text'); next(); } catch (err) { next(err); } });
- post() data
request .post(`${uri}/todo/item`) .type('application/octet-stream') .send('tobi') .end((error, res) => { try { assert.equal('added "tobi"', res.text, 'response text'); next(); } catch (err) { next(err); } });
- request .type()
request .post(`${uri}/user/12/pet`) .type('urlencoded') .send('pet=tobi') .end((error, res) => { try { assert.equal('added pet "tobi"', res.text, 'response text'); next(); } catch (err) { next(err); } });
- request .type() with alias
request .post(`${uri}/user/12/pet`) .type('application/x-www-form-urlencoded') .send('pet=tobi') .end((error, res) => { try { assert.equal('added pet "tobi"', res.text, 'response text'); next(); } catch (err) { next(err); } });
- request .get() with no data or callback
request.get(`${uri}/echo-header/content-type`); next();
- request .send() with no data only
request.post(`${uri}/user/5/pet`).type('urlencoded').send('pet=tobi'); next();
- request .send() with callback only
request .get(`${uri}/echo-header/accept`) .set('Accept', 'foo/bar') .end((error, res) => { try { assert.equal('foo/bar', res.text); next(); } catch (err) { next(err); } });
- request .accept() with json
request .get(`${uri}/echo-header/accept`) .accept('json') .end((error, res) => { try { assert.equal('application/json', res.text); next(); } catch (err) { next(err); } });
- request .accept() with application/json
request .get(`${uri}/echo-header/accept`) .accept('application/json') .end((error, res) => { try { assert.equal('application/json', res.text); next(); } catch (err) { next(err); } });
- request .accept() with xml
request .get(`${uri}/echo-header/accept`) .accept('xml') .end((error, res) => { try { // We can't depend on mime module to be consistent with this assert(res.text == 'application/xml' || res.text == 'text/xml'); next(); } catch (err) { next(err); } });
- request .accept() with application/xml
request .get(`${uri}/echo-header/accept`) .accept('application/xml') .end((error, res) => { try { assert.equal('application/xml', res.text); next(); } catch (err) { next(err); } });
- request .end()
request .put(`${uri}/echo-header/content-type`) .set('Content-Type', 'text/plain') .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- request .send()
request .put(`${uri}/echo-header/content-type`) .set('Content-Type', 'text/plain') .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- request .set()
request .put(`${uri}/echo-header/content-type`) .set('Content-Type', 'text/plain') .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- request .set(object)
request .put(`${uri}/echo-header/content-type`) .set({ 'Content-Type': 'text/plain' }) .send('wahoo') .end((error, res) => { try { assert.equal('text/plain', res.text); next(); } catch (err) { next(err); } });
- POST urlencoded
request .post(`${uri}/pet`) .type('urlencoded') .send({ name: 'Manny', species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST json
request .post(`${uri}/pet`) .type('json') .send({ name: 'Manny', species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST json array
request .post(`${uri}/echo`) .send([1, 2, 3]) .end((error, res) => { try { assert.equal( 'application/json', res.header['content-type'].split(';')[0] ); assert.equal('[1,2,3]', res.text); next(); } catch (err) { next(err); } });
- POST json default
request .post(`${uri}/pet`) .send({ name: 'Manny', species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST json contentType charset
request .post(`${uri}/echo`) .set('Content-Type', 'application/json; charset=UTF-8') .send({ data: ['data1', 'data2'] }) .end((error, res) => { try { assert.equal('{"data":["data1","data2"]}', res.text); next(); } catch (err) { next(err); } });
- POST json contentType vendor
request .post(`${uri}/echo`) .set('Content-Type', 'application/vnd.example+json') .send({ data: ['data1', 'data2'] }) .end((error, res) => { try { assert.equal('{"data":["data1","data2"]}', res.text); next(); } catch (err) { next(err); } });
- POST multiple .send() calls
request .post(`${uri}/pet`) .send({ name: 'Manny' }) .send({ species: 'cat' }) .end((error, res) => { try { assert.equal('added Manny the cat', res.text); next(); } catch (err) { next(err); } });
- POST multiple .send() strings
request .post(`${uri}/echo`) .send('user[name]=tj') .send('user[email]=tj@vision-media.ca') .end((error, res) => { try { assert.equal( 'application/x-www-form-urlencoded', res.header['content-type'].split(';')[0] ); assert.equal( res.text, 'user[name]=tj&user[email]=tj@vision-media.ca' ); next(); } catch (err) { next(err); } });
- POST with no data
request .post(`${uri}/empty-body`) .send() .end((error, res) => { try { assert.ifError(error); assert(res.noContent, 'response should be .noContent'); next(); } catch (err) { next(err); } });
- GET .type
request.get(`${uri}/pets`).end((error, res) => { try { assert.equal('application/json', res.type); next(); } catch (err) { next(err); } });
- GET Content-Type params
request.get(`${uri}/text`).end((error, res) => { try { assert.equal('utf-8', res.charset); next(); } catch (err) { next(err); } });
- GET json
request.get(`${uri}/pets`).end((error, res) => { try { assert.deepEqual(res.body, ['tobi', 'loki', 'jane']); next(); } catch (err) { next(err); } });
- GET json-seq
request .get(`${uri}/json-seq`) .buffer() .end((error, res) => { try { assert.ifError(error); assert.deepEqual(res.text, '\u001E{"id":1}\n\u001E{"id":2}\n'); next(); } catch (err) { next(err); } });
- GET binary data
request .get(`${uri}/binary-data`) .buffer() .end((error, res) => { try { assert.ifError(error); assert.deepEqual(res.body, binData); next(); } catch (err) { next(err); } });
- GET x-www-form-urlencoded
request.get(`${uri}/foo`).end((error, res) => { try { assert.deepEqual(res.body, { foo: 'bar' }); next(); } catch (err) { next(err); } });
- GET shorthand
request.get(`${uri}/foo`, (error, res) => { try { assert.equal('foo=bar', res.text); next(); } catch (err) { next(err); } });
- POST shorthand
request.post(`${uri}/user/0/pet`, { pet: 'tobi' }, (error, res) => { try { assert.equal('added pet "tobi"', res.text); next(); } catch (err) { next(err); } });
- POST shorthand without callback
request.post(`${uri}/user/0/pet`, { pet: 'tobi' }).end((error, res) => { try { assert.equal('added pet "tobi"', res.text); next(); } catch (err) { next(err); } });
- GET querystring object with array
request .get(`${uri}/querystring`) .query({ val: ['a', 'b', 'c'] }) .end((error, res) => { try { assert.deepEqual(res.body, { val: ['a', 'b', 'c'] }); next(); } catch (err) { next(err); } });
- GET querystring object with array and primitives
request .get(`${uri}/querystring`) .query({ array: ['a', 'b', 'c'], string: 'foo', number: 10 }) .end((error, res) => { try { assert.deepEqual(res.body, { array: ['a', 'b', 'c'], string: 'foo', number: 10 }); next(); } catch (err) { next(err); } });
- GET querystring object with two arrays
request .get(`${uri}/querystring`) .query({ array1: ['a', 'b', 'c'], array2: [1, 2, 3] }) .end((error, res) => { try { assert.deepEqual(res.body, { array1: ['a', 'b', 'c'], array2: [1, 2, 3] }); next(); } catch (err) { next(err); } });
- GET querystring object
request .get(`${uri}/querystring`) .query({ search: 'Manny' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny' }); next(); } catch (err) { next(err); } });
- GET querystring append original
request .get(`${uri}/querystring?search=Manny`) .query({ range: '1..5' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5' }); next(); } catch (err) { next(err); } });
- GET querystring multiple objects
request .get(`${uri}/querystring`) .query({ search: 'Manny' }) .query({ range: '1..5' }) .query({ order: 'desc' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5', order: 'desc' }); next(); } catch (err) { next(err); } });
- GET querystring with strings
request .get(`${uri}/querystring`) .query('search=Manny') .query('range=1..5') .query('order=desc') .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5', order: 'desc' }); next(); } catch (err) { next(err); } });
- GET querystring with strings and objects
request .get(`${uri}/querystring`) .query('search=Manny') .query({ order: 'desc', range: '1..5' }) .end((error, res) => { try { assert.deepEqual(res.body, { search: 'Manny', range: '1..5', order: 'desc' }); next(); } catch (err) { next(err); } });
- GET shorthand payload goes to querystring
request.get( `${uri}/querystring`, { foo: 'FOO', bar: 'BAR' }, (error, res) => { try { assert.deepEqual(res.body, { foo: 'FOO', bar: 'BAR' }); next(); } catch (err) { next(err); } } );
- HEAD shorthand payload goes to querystring
request.head( `${uri}/querystring-in-header`, { foo: 'FOO', bar: 'BAR' }, (error, res) => { try { assert.deepEqual(JSON.parse(res.headers.query), { foo: 'FOO', bar: 'BAR' }); next(); } catch (err) { next(err); } } );
- request(method, url)
request('GET', `${uri}/foo`).end((error, res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } });
- request(url)
request(`${uri}/foo`).end((error, res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } });
- request(url, fn)
request(`${uri}/foo`, (error, res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } });
- req.timeout(ms)
const request_ = request.get(`${uri}/delay/3000`).timeout(1000); request_.end((error, res) => { try { assert(error, 'error missing'); assert.equal(1000, error.timeout, 'err.timeout missing'); assert.equal( 'Timeout of 1000ms exceeded', error.message, 'err.message incorrect' ); assert.equal(null, res); assert(request_.timedout, true); next(); } catch (err) { next(err); } });
- req.timeout(ms) with redirect
const request_ = request.get(`${uri}/delay/const`).timeout(1000); request_.end((error, res) => { try { assert(error, 'error missing'); assert.equal(1000, error.timeout, 'err.timeout missing'); assert.equal( 'Timeout of 1000ms exceeded', error.message, 'err.message incorrect' ); assert.equal(null, res); assert(request_.timedout, true); next(); } catch (err) { next(err); } });
- request event
request .get(`${uri}/foo`) .on('request', (request_) => { try { assert.equal(`${uri}/foo`, request_.url); next(); } catch (err) { next(err); } }) .end();
- response event
request .get(`${uri}/foo`) .on('response', (res) => { try { assert.equal('bar', res.body.foo); next(); } catch (err) { next(err); } }) .end();
- response should set statusCode
request.get(`${uri}/ok`, (error, res) => { try { assert.strictEqual(res.statusCode, 200); next(); } catch (err) { next(err); } });
- req.toJSON()
request.get(`${uri}/ok`).end((error, res) => { try { const index = (res.request || res.req).toJSON(); for (const property of ['url', 'method', 'data', 'headers']) { assert(index.hasOwnProperty(property)); } next(); } catch (err) { next(err); } });
.retry(count)
- should not retry if passed "0"
request .get(`${base}/error`) .retry(0) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal( undefined, error.retries, 'expected an error without .retries' ); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should not retry if passed an invalid number
request .get(`${base}/error`) .retry(-2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal( undefined, error.retries, 'expected an error without .retries' ); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should not retry if passed undefined
request .get(`${base}/error`) .retry(undefined) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal( undefined, error.retries, 'expected an error without .retries' ); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should handle server error after repeat attempt
request .get(`${base}/error`) .retry(2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should retry if passed nothing
request .get(`${base}/error`) .retry() .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(1, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should retry if passed "true"
request .get(`${base}/error`) .retry(true) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(1, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); done(); } catch (err) { done(err); } });
- should handle successful request after repeat attempt from server error
request .get(`${base}/error/ok/${uniqid()}`) .query({ qs: 'present' }) .retry(2) .end((error, res) => { try { assert.ifError(error); assert(res.ok, 'response should be ok'); assert(res.text, 'res.text'); done(); } catch (err) { done(err); } });
- should handle server timeout error after repeat attempt
request .get(`${base}/delay/400`) .timeout(200) .retry(2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); } catch (err) { done(err); } });
- should handle successful request after repeat attempt from server timeout
const url = `/delay/1200/ok/${uniqid()}?built=in`; request .get(base + url) .query('string=ified') .query({ json: 'ed' }) .timeout(600) .retry(2) .end((error, res) => { try { assert.ifError(error); assert(res.ok, 'response should be ok'); assert.equal(res.text, `ok = ${url}&string=ified&json=ed`); done(); } catch (err) { done(err); } });
- should handle successful request after repeat attempt from server timeout when using .then(fulfill, reject)
const url = `/delay/1200/ok/${uniqid()}?built=in`; request .get(base + url) .query('string=ified') .query({ json: 'ed' }) .timeout(600) .retry(1) .then((res, error) => { try { assert.ifError(error); assert(res.ok, 'response should be ok'); assert.equal(res.text, `ok = ${url}&string=ified&json=ed`); done(); } catch (err) { done(err); } });
- should correctly abort a retry attempt
let aborted = false; const request_ = request.get(`${base}/delay/400`).timeout(200).retry(2); request_.end((error, res) => { try { assert(false, 'should not complete the request'); } catch (err) { done(err); } }); request_.on('abort', () => { aborted = true; }); setTimeout(() => { request_.abort(); setTimeout(() => { try { assert(aborted, 'should be aborted'); done(); } catch (err) { done(err); } }, 150); }, 150);
- should correctly retain header fields
request .get(`${base}/error/ok/${uniqid()}`) .query({ qs: 'present' }) .retry(2) .set('X-Foo', 'bar') .end((error, res) => { try { assert.ifError(error); assert(res.body); res.body.should.have.property('x-foo', 'bar'); done(); } catch (err) { done(err); } });
- should not retry on 4xx responses
request .get(`${base}/bad-request`) .retry(2) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(0, error.retries, 'expected an error with 0 .retries'); assert.equal(400, error.status, 'expected an error status of 400'); done(); } catch (err) { done(err); } });
- should execute callback on retry if passed
let callbackCallCount = 0; function retryCallback(request) { callbackCallCount++; } request .get(`${base}/error`) .retry(2, retryCallback) .end((error, res) => { try { assert(error, 'expected an error'); assert.equal(2, error.retries, 'expected an error with .retries'); assert.equal(500, error.status, 'expected an error status of 500'); assert.equal( 2, callbackCallCount, 'expected the callback to be called on each retry' ); done(); } catch (err) { done(err); } });
.timeout(ms)
- should error
request .get(`${base}/delay/500`) .timeout(150) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should error in promise interface
request .get(`${base}/delay/500`) .timeout(150) .catch((err) => { assert(err, 'expected an error'); assert.equal( 'number', typeof err.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', err.code, 'expected abort error code'); done(); });
- should handle gzip timeout
request .get(`${base}/delay/zip`) .timeout(150) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should handle buffer timeout
request .get(`${base}/delay/json`) .buffer(true) .timeout(150) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should error on deadline
request .get(`${base}/delay/500`) .timeout({ deadline: 150 }) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); done(); });
- should support setting individual options
request .get(`${base}/delay/500`) .timeout({ deadline: 10 }) .timeout({ response: 99_999 }) .end((error, res) => { assert(error, 'expected an error'); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); assert.equal('ETIME', error.errno); done(); });
- should error on response
request .get(`${base}/delay/500`) .timeout({ response: 150 }) .end((error, res) => { assert(error, 'expected an error'); assert.equal( 'number', typeof error.timeout, 'expected an error with .timeout' ); assert.equal('ECONNABORTED', error.code, 'expected abort error code'); assert.equal('ETIMEDOUT', error.errno); done(); });
- should accept slow body with fast response
request .get(`${base}/delay/slowbody`) .timeout({ response: 1000 }) .on('progress', () => { // This only makes the test faster without relying on arbitrary timeouts request.get(`${base}/delay/slowbody/finish`).end(); }) .end(done);
when timeout is exceeded
request
- should use plugin success
const now = `${Date.now()}`; function uuid(request_) { request_.set('X-UUID', now); return request_; } function prefix(request_) { request_.url = uri + request_.url; return request_; } request .get('/echo') .use(uuid) .use(prefix) .end((error, res) => { assert.strictEqual(res.statusCode, 200); assert.equal(res.get('X-UUID'), now); done(); });
use
subclass
- should be an instance of Request
const request_ = request.get('/'); assert(request_ instanceof request.Request);
- should use patched subclass
assert(OriginalRequest); let constructorCalled; let sendCalled; function NewRequest(...args) { constructorCalled = true; OriginalRequest.apply(this, args); } NewRequest.prototype = Object.create(OriginalRequest.prototype); NewRequest.prototype.send = function () { sendCalled = true; return this; }; request.Request = NewRequest; const request_ = request.get('/').send(); assert(constructorCalled); assert(sendCalled); assert(request_ instanceof NewRequest); assert(request_ instanceof OriginalRequest);
- should use patched subclass in agent too
if (!request.agent) return; // Node-only function NewRequest(...args) { OriginalRequest.apply(this, args); } NewRequest.prototype = Object.create(OriginalRequest.prototype); request.Request = NewRequest; const request_ = request.agent().del('/'); assert(request_ instanceof NewRequest); assert(request_ instanceof OriginalRequest);
request
- should gain a session on POST
agent3.post(`${base}/signin`).then((res) => { res.should.have.status(200); should.not.exist(res.headers['set-cookie']); res.text.should.containEql('dashboard'); })
- should start with empty session (set cookies)
agent1.get(`${base}/dashboard`).end((error, res) => { should.exist(error); res.should.have.status(401); should.exist(res.headers['set-cookie']); done(); });
- should gain a session (cookies already set)
agent1.post(`${base}/signin`).then((res) => { res.should.have.status(200); should.not.exist(res.headers['set-cookie']); res.text.should.containEql('dashboard'); })
- should persist cookies across requests
agent1.get(`${base}/dashboard`).then((res) => { res.should.have.status(200); })
- should have the cookie set in the end callback
agent4 .post(`${base}/setcookie`) .then(() => agent4.get(`${base}/getcookie`)) .then((res) => { res.should.have.status(200); assert.strictEqual(res.text, 'jar'); })
- should not share cookies
agent2.get(`${base}/dashboard`).end((error, res) => { should.exist(error); res.should.have.status(401); done(); });
- should not lose cookies between agents
agent1.get(`${base}/dashboard`).then((res) => { res.should.have.status(200); })
- should be able to follow redirects
agent1.get(base).then((res) => { res.should.have.status(200); res.text.should.containEql('dashboard'); })
- should be able to post redirects
agent1 .post(`${base}/redirect`) .send({ foo: 'bar', baz: 'blaaah' }) .then((res) => { res.should.have.status(200); res.text.should.containEql('simple'); res.redirects.should.eql([`${base}/simple`]); })
- should be able to limit redirects
agent1 .get(base) .redirects(0) .end((error, res) => { should.exist(error); res.should.have.status(302); res.redirects.should.eql([]); res.header.location.should.equal('/dashboard'); done(); });
- should be able to create a new session (clear cookie)
agent1.post(`${base}/signout`).then((res) => { res.should.have.status(200); should.exist(res.headers['set-cookie']); })
- should regenerate with an empty session
agent1.get(`${base}/dashboard`).end((error, res) => { should.exist(error); res.should.have.status(401); should.not.exist(res.headers['set-cookie']); done(); });
persistent agent
Basic auth
- should set Authorization
const new_url = URL.parse(base); new_url.auth = 'tobi:learnboost'; new_url.pathname = '/basic-auth'; request.get(URL.format(new_url)).end((error, res) => { res.status.should.equal(200); done(); });
- should set Authorization
request .get(`${base}/basic-auth`) .auth('tobi', 'learnboost') .end((error, res) => { res.status.should.equal(200); done(); });
- should set authorization
request .get(`${base}/basic-auth/again`) .auth('tobi') .end((error, res) => { res.status.should.eql(200); done(); });
when credentials are present in url
req.auth(user, pass)
req.auth(user + ":" + pass)
[node] request
- should preserve the encoding of the url
request.get(`${base}/url?a=(b%29`).end((error, res) => { assert.equal('/url?a=(b%29', res.text); done(); });
- should format the url
request.get(url.parse(`${base}/login`)).then((res) => { assert(res.ok); })
- should default to http
request.get(`${base}/login`).then((res) => { assert.equal(res.status, 200); })
- should describe the response
request .post(`${base}/echo`) .send({ foo: 'baz' }) .then((res) => { const object = res.toJSON(); assert.equal('object', typeof object.header); assert.equal('object', typeof object.req); assert.equal(200, object.status); assert.equal('{"foo":"baz"}', object.text); })
- should default to an empty object
request.get(`${base}/login`).then((res) => { res.links.should.eql({}); })
- should parse the Link header field
request.get(`${base}/links`).end((error, res) => { res.links.next.should.equal( 'https://api.github.com/repos/visionmedia/mocha/issues?page=2' ); done(); });
- should remove the header field
request .post(`${base}/echo`) .unset('User-Agent') .end((error, res) => { assert.equal(void 0, res.header['user-agent']); done(); });
- should set/get header fields case-insensitively
const r = request.post(`${base}/echo`); r.set('MiXeD', 'helloes'); assert.strictEqual(r.get('mixed'), 'helloes');
- should unset header fields case-insensitively
const r = request.post(`${base}/echo`); r.set('MiXeD', 'helloes'); r.unset('MIXED'); assert.strictEqual(r.get('mixed'), undefined);
- should write the given data
const request_ = request.post(`${base}/echo`); request_.set('Content-Type', 'application/json'); assert.equal('boolean', typeof request_.write('{"name"')); assert.equal('boolean', typeof request_.write(':"tobi"}')); request_.end((error, res) => { res.text.should.equal('{"name":"tobi"}'); done(); });
- should pipe the response to the given stream
const stream = new EventEmitter(); stream.buf = ''; stream.writable = true; stream.write = function (chunk) { this.buf += chunk; }; stream.end = function () { this.buf.should.equal('{"name":"tobi"}'); done(); }; request.post(`${base}/echo`).send('{"name":"tobi"}').pipe(stream);
- should enable buffering
request .get(`${base}/custom`) .buffer() .end((error, res) => { assert.ifError(error); assert.equal('custom stuff', res.text); assert(res.buffered); done(); });
- should take precedence over request.buffer['someMimeType'] = false
const type = 'application/barbaz'; const send = 'some text'; request.buffer[type] = false; request .post(`${base}/echo`) .type(type) .send(send) .buffer() .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(res.type, type); assert.equal(send, res.text); assert(res.buffered); done(); });
- should disable buffering
request .post(`${base}/echo`) .type('application/x-dog') .send('hello this is dog') .buffer(false) .end((error, res) => { assert.ifError(error); assert.equal(null, res.text); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal('hello this is dog'); done(); }); });
- should take precedence over request.buffer['someMimeType'] = true
const type = 'application/foobar'; const send = 'hello this is a dog'; request.buffer[type] = true; request .post(`${base}/echo`) .type(type) .send(send) .buffer(false) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(null, res.text); assert.equal(res.type, type); assert(!res.buffered); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal(send); done(); }); });
- should not throw an error when using the client-side "withCredentials" method
request .get(`${base}/custom`) .withCredentials() .end((error, res) => { assert.ifError(error); done(); });
- should return the defaut agent
const request_ = request.post(`${base}/echo`); request_.agent().should.equal(false); done();
- should set an agent to undefined and ensure it is chainable
const request_ = request.get(`${base}/echo`); const returnValue = request_.agent(undefined); returnValue.should.equal(request_); assert.strictEqual(request_.agent(), undefined); done();
- should set passed agent
const http = require('http'); const request_ = request.get(`${base}/echo`); const agent = new http.Agent(); const returnValue = request_.agent(agent); returnValue.should.equal(request_); request_.agent().should.equal(agent); done();
- should still use buffering
return request .post(`${base}/echo`) .type('application/x-dog') .send('hello this is dog') .then((res) => { assert.equal(null, res.text); assert.equal(res.body.toString(), 'hello this is dog'); res.buffered.should.be.true; });
- should be set to the byte length of a non-buffer object
const decoder = new StringDecoder('utf8'); let img = fs.readFileSync(`${__dirname}/fixtures/test.png`); img = decoder.write(img); request .post(`${base}/echo`) .type('application/x-image') .send(img) .buffer(false) .end((error, res) => { assert.ifError(error); assert(!res.buffered); assert.equal(res.header['content-length'], Buffer.byteLength(img)); done(); });
- should be set to the length of a buffer object
const img = fs.readFileSync(`${__dirname}/fixtures/test.png`); request .post(`${base}/echo`) .type('application/x-image') .send(img) .buffer(true) .end((error, res) => { assert.ifError(error); assert(res.buffered); assert.equal(res.header['content-length'], img.length); done(); });
with an url
with an object
without a schema
res.toJSON()
res.links
req.unset(field)
case-insensitive
req.write(str)
req.pipe(stream)
.buffer()
.buffer(false)
.withCredentials()
.agent()
.agent(undefined)
.agent(new http.Agent())
with a content type other than application/json or text/*
content-length
req.buffer['someMimeType']
- should respect that agent.buffer(true) takes precedent
const agent = request.agent(); agent.buffer(true); const type = 'application/somerandomtype'; const send = 'somerandomtext'; request.buffer[type] = false; agent .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(res.type, type); assert.equal(send, res.text); assert(res.buffered); done(); });
- should respect that agent.buffer(false) takes precedent
const agent = request.agent(); agent.buffer(false); const type = 'application/barrr'; const send = 'some random text2'; request.buffer[type] = true; agent .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(null, res.text); assert.equal(res.type, type); assert(!res.buffered); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal(send); done(); }); });
- should disable buffering for that mimetype when false
const type = 'application/bar'; const send = 'some random text'; request.buffer[type] = false; request .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(null, res.text); assert.equal(res.type, type); assert(!res.buffered); res.body.should.eql({}); let buf = ''; res.setEncoding('utf8'); res.on('data', (chunk) => { buf += chunk; }); res.on('end', () => { buf.should.equal(send); done(); }); });
- should enable buffering for that mimetype when true
const type = 'application/baz'; const send = 'woooo'; request.buffer[type] = true; request .post(`${base}/echo`) .type(type) .send(send) .end((error, res) => { delete request.buffer[type]; assert.ifError(error); assert.equal(res.type, type); assert.equal(send, res.text); assert(res.buffered); done(); });
- should fallback to default handling for that mimetype when undefined
const type = 'application/bazzz'; const send = 'woooooo'; return request .post(`${base}/echo`) .type(type) .send(send) .then((res) => { assert.equal(res.type, type); assert.equal(send, res.body.toString()); assert(res.buffered); });
exports
- should expose .protocols
Object.keys(request.protocols).should.eql(['http:', 'https:', 'http2:']);
- should expose .serialize
Object.keys(request.serialize).should.eql([ 'application/x-www-form-urlencoded', 'application/json' ]);
- should expose .parse
Object.keys(request.parse).should.eql([ 'application/x-www-form-urlencoded', 'application/json', 'text', 'application/json-seq', 'application/octet-stream', 'application/pdf', 'image' ]);
- should export .buffer
Object.keys(request.buffer).should.eql([]);
flags
- should set res.error and res.clientError
request.get(`${base}/notfound`).end((error, res) => { assert(error); assert(!res.ok, 'response should not be ok'); assert(res.error, 'response should be an error'); assert(res.clientError, 'response should be a client error'); assert(!res.serverError, 'response should not be a server error'); done(); });
- should set res.error and res.serverError
request.get(`${base}/error`).end((error, res) => { assert(error); assert(!res.ok, 'response should not be ok'); assert(!res.notFound, 'response should not be notFound'); assert(res.error, 'response should be an error'); assert(!res.clientError, 'response should not be a client error'); assert(res.serverError, 'response should be a server error'); done(); });
- should res.notFound
request.get(`${base}/notfound`).end((error, res) => { assert(error); assert(res.notFound, 'response should be .notFound'); done(); });
- should set req.badRequest
request.get(`${base}/bad-request`).end((error, res) => { assert(error); assert(res.badRequest, 'response should be .badRequest'); done(); });
- should set res.unauthorized
request.get(`${base}/unauthorized`).end((error, res) => { assert(error); assert(res.unauthorized, 'response should be .unauthorized'); done(); });
- should set res.notAcceptable
request.get(`${base}/not-acceptable`).end((error, res) => { assert(error); assert(res.notAcceptable, 'response should be .notAcceptable'); done(); });
- should set res.noContent
request.get(`${base}/no-content`).end((error, res) => { assert(!error); assert(res.noContent, 'response should be .noContent'); done(); });
- should set res.created
request.post(`${base}/created`).end((error, res) => { assert(!error); assert(res.created, 'response should be .created'); done(); });
- should set res.unprocessableEntity
request.post(`${base}/unprocessable-entity`).end((error, res) => { assert(error); assert( res.unprocessableEntity, 'response should be .unprocessableEntity' ); done(); });
with 4xx response
with 5xx response
with 404 Not Found
with 400 Bad Request
with 401 Bad Request
with 406 Not Acceptable
with 204 No Content
with 201 Created
with 422 Unprocessable Entity
Merging objects
- Don't mix Buffer and JSON
assert.throws(() => { request .post('/echo') .send(Buffer.from('some buffer')) .send({ allowed: false }); });
req.send(String)
- should default to "form"
request .post(`${base}/echo`) .send('user[name]=tj') .send('user[email]=tj@vision-media.ca') .end((error, res) => { res.header['content-type'].should.equal( 'application/x-www-form-urlencoded' ); res.body.should.eql({ user: { name: 'tj', email: 'tj@vision-media.ca' } }); done(); });
res.body
- should parse the body
request.get(`${base}/form-data`).end((error, res) => { res.text.should.equal('pet[name]=manny'); res.body.should.eql({ pet: { name: 'manny' } }); done(); });
application/x-www-form-urlencoded
request.get().http2()
- should preserve the encoding of the url
request .get(`${base}/url?a=(b%29`) .http2() .end((error, res) => { assert.equal('/url?a=(b%29', res.text); done(); });
- should format the url
request .get(url.parse(`${base}/login`)) .http2() .then((res) => { assert(res.ok); })
https
- should give a good response
request .get(testEndpoint) .ca(ca) .end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('Safe and secure!', res.text); done(); });
- should reject unauthorized response
return request .get(testEndpoint) .trustLocalhost(false) .then( () => { throw new Error('Allows MITM'); }, () => {} );
- should not reject unauthorized response
return request .get(testEndpoint) .disableTLSCerts() .then(({ status }) => { assert.strictEqual(status, 200); });
- should trust localhost unauthorized response
return request.get(testEndpoint).trustLocalhost(true);
- should trust overriden localhost unauthorized response
return request .get(`https://example.com:${server.address().port}`) .connect('127.0.0.1') .trustLocalhost();
- should be able to make multiple requests without redefining the certificate
const agent = request.agent({ ca }); agent.get(testEndpoint).end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('Safe and secure!', res.text); agent.get(url.parse(testEndpoint)).end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('Safe and secure!', res.text); done(); }); });
certificate authority
request
.agent
client certificates
request
.agent
res.body
- should parse the body
request.get(`${base}/image`).end((error, res) => { res.type.should.equal('image/png'); Buffer.isBuffer(res.body).should.be.true(); (res.body.length - img.length).should.equal(0); done(); });
- should parse the body
request .get(`${base}/image-as-octets`) .buffer(true) // that's tech debt :( .end((error, res) => { res.type.should.equal('application/octet-stream'); Buffer.isBuffer(res.body).should.be.true(); (res.body.length - img.length).should.equal(0); done(); });
- should parse the body (using responseType)
request .get(`${base}/image-as-octets`) .responseType('blob') .end((error, res) => { res.type.should.equal('application/octet-stream'); Buffer.isBuffer(res.body).should.be.true(); (res.body.length - img.length).should.equal(0); done(); });
image/png
application/octet-stream
application/octet-stream
zlib
- should deflate the content
request.get(base).end((error, res) => { res.should.have.status(200); res.text.should.equal(subject); res.headers['content-length'].should.be.below(subject.length); done(); });
- should protect from zip bombs
request .get(base) .buffer(true) .maxResponseSize(1) .end((error, res) => { try { assert.equal('Maximum response size reached', error && error.message); done(); } catch (err) { done(err); } });
- should ignore trailing junk
request.get(`${base}/junk`).end((error, res) => { res.should.have.status(200); res.text.should.equal(subject); done(); });
- should ignore missing data
request.get(`${base}/chopped`).end((error, res) => { assert.equal(undefined, error); res.should.have.status(200); res.text.should.startWith(subject); done(); });
- should handle corrupted responses
request.get(`${base}/corrupt`).end((error, res) => { assert(error, 'missing error'); assert(!res, 'response should not be defined'); done(); });
- should handle no content with gzip header
request.get(`${base}/nocontent`).end((error, res) => { assert.ifError(error); assert(res); res.should.have.status(204); res.text.should.equal(''); res.headers.should.not.have.property('content-length'); done(); });
- should buffer if asked
return request .get(`${base}/binary`) .buffer(true) .then((res) => { res.should.have.status(200); assert(res.headers['content-length']); assert(res.body.byteLength); assert.equal(subject, res.body.toString()); });
- should emit buffers
request.get(`${base}/binary`).end((error, res) => { res.should.have.status(200); res.headers['content-length'].should.be.below(subject.length); res.on('data', (chunk) => { chunk.should.have.length(subject.length); }); res.on('end', done); });
without encoding set
req.lookup()
- should set a custom lookup
const r = request.get(`${base}/ok`).lookup(myLookup); assert(r.lookup() === myLookup); r.then((res) => { res.text.should.equal('ok'); done(); });
Multipart
- should set a multipart field value
const request_ = request.post(`${base}/echo`); request_.field('user[name]', 'tobi'); request_.field('user[age]', '2'); request_.field('user[species]', 'ferret'); return request_.then((res) => { res.body['user[name]'].should.equal('tobi'); res.body['user[age]'].should.equal('2'); res.body['user[species]'].should.equal('ferret'); });
- should work with file attachments
const request_ = request.post(`${base}/echo`); request_.field('name', 'Tobi'); request_.attach('document', 'test/node/fixtures/user.html'); request_.field('species', 'ferret'); return request_.then((res) => { res.body.name.should.equal('Tobi'); res.body.species.should.equal('ferret'); const html = res.files.document; html.originalFilename.should.equal('user.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); });
- should attach a file
const request_ = request.post(`${base}/echo`); request_.attach('one', 'test/node/fixtures/user.html'); request_.attach('two', 'test/node/fixtures/user.json'); request_.attach('three', 'test/node/fixtures/user.txt'); return request_.then((res) => { const html = res.files.one; const json = res.files.two; const text = res.files.three; html.originalFilename.should.equal('user.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); json.originalFilename.should.equal('user.json'); json.mimetype.should.equal('application/json'); read(json.filepath).should.equal('{"name":"tobi"}'); text.originalFilename.should.equal('user.txt'); text.mimetype.should.equal('text/plain'); read(text.filepath).should.equal('Tobi'); });
- should fail the request with an error
const request_ = request.post(`${base}/echo`); request_.attach('name', 'foo'); // request_.attach('name2', 'bar'); // request_.attach('name3', 'baz'); request_.end((error, res) => { assert.ok(Boolean(error), 'Request should have failed.'); error.code.should.equal('ENOENT'); error.message.should.containEql('ENOENT'); if (IS_WINDOWS) { error.path.toLowerCase().should.equal( getFullPath('foo').toLowerCase() ); } else { error.path.should.equal(getFullPath('foo')); } done(); });
- promise should fail
return request .post(`${base}/echo`) .field({ a: 1, b: 2 }) .attach('c', 'does-not-exist.txt') .then( (res) => assert.fail('It should not allow this'), (err) => { err.code.should.equal('ENOENT'); if (IS_WINDOWS) { err.path.toLowerCase().should.equal( getFullPath('does-not-exist.txt').toLowerCase() ); } else { err.path.should.equal(getFullPath('does-not-exist.txt')); } } );
- should report ENOENT via the callback
request .post(`${base}/echo`) .attach('name', 'file-does-not-exist') .end((error, res) => { assert.ok(Boolean(error), 'Request should have failed'); error.code.should.equal('ENOENT'); done(); });
- should report ENOENT via Promise
return request .post(`${base}/echo`) .attach('name', 'file-does-not-exist') .then( (res) => assert.fail('Request should have failed'), (err) => err.code.should.equal('ENOENT') );
- should use the custom filename
request .post(`${base}/echo`) .attach('document', 'test/node/fixtures/user.html', 'doc.html') .then((res) => { const html = res.files.document; html.originalFilename.should.equal('doc.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); })
- should fire progress event
let loaded = 0; let total = 0; let uploadEventWasFired = false; request .post(`${base}/echo`) .attach('document', 'test/node/fixtures/user.html') .on('progress', (event) => { total = event.total; loaded = event.loaded; if (event.direction === 'upload') { uploadEventWasFired = true; } }) .end((error, res) => { if (error) return done(error); const html = res.files.document; html.originalFilename.should.equal('user.html'); html.mimetype.should.equal('text/html'); read(html.filepath).should.equal('<h1>name</h1>'); total.should.equal(223); loaded.should.equal(223); uploadEventWasFired.should.equal(true); done(); });
- filesystem errors should be caught
request .post(`${base}/echo`) .attach('filedata', 'test/node/fixtures/non-existent-file.ext') .end((error, res) => { assert.ok(Boolean(error), 'Request should have failed.'); error.code.should.equal('ENOENT'); if (IS_WINDOWS) { error.path.toLowerCase().should.equal( getFullPath('test/node/fixtures/non-existent-file.ext').toLowerCase() ); } else { error.path.should.equal( getFullPath('test/node/fixtures/non-existent-file.ext') ); } done(); });
- should set a multipart field value
request .post(`${base}/echo`) .field('first-name', 'foo') .field('last-name', 'bar') .end((error, res) => { if (error) done(error); res.should.be.ok(); res.body['first-name'].should.equal('foo'); res.body['last-name'].should.equal('bar'); done(); });
- should set multiple multipart fields
request .post(`${base}/echo`) .field({ 'first-name': 'foo', 'last-name': 'bar' }) .end((error, res) => { if (error) done(error); res.should.be.ok(); res.body['first-name'].should.equal('foo'); res.body['last-name'].should.equal('bar'); done(); });
#field(name, value)
#attach(name, path)
when a file does not exist
#attach(name, path, filename)
#field(name, val)
#field(object)
with network error
- should error
request.get(`http://localhost:${this.port}/`).end((error, res) => { assert(error, 'expected an error'); done(); });
request
- should start with 200
request.get(`${base}/if-mod`).end((error, res) => { res.should.have.status(200); res.text.should.match(/^\d+$/); ts = Number(res.text); done(); });
- should then be 304
request .get(`${base}/if-mod`) .set('If-Modified-Since', new Date(ts).toUTCString()) .end((error, res) => { res.should.have.status(304); // res.text.should.be.empty done(); });
not modified
req.parse(fn)
- should take precedence over default parsers
request .get(`${base}/manny`) .parse(request.parse['application/json']) .end((error, res) => { assert(res.ok); assert.equal('{"name":"manny"}', res.text); assert.equal('manny', res.body.name); done(); });
- should be the only parser
request .get(`${base}/image`) .buffer(false) .parse((res, fn) => { res.on('data', () => {}); }) .then((res) => { assert(res.ok); assert.strictEqual(res.text, undefined); res.body.should.eql({}); })
- should emit error if parser throws
request .get(`${base}/manny`) .parse(() => { throw new Error('I am broken'); }) .on('error', (error) => { error.message.should.equal('I am broken'); done(); }) .end();
- should emit error if parser returns an error
request .get(`${base}/manny`) .parse((res, fn) => { fn(new Error('I am broken')); }) .on('error', (error) => { error.message.should.equal('I am broken'); done(); }) .end();
pipe on redirect
- should follow Location
const stream = fs.createWriteStream(destinationPath); const redirects = []; const request_ = request .get(base) .on('redirect', (res) => { redirects.push(res.headers.location); }) .connect({ inapplicable: 'should be ignored' }); stream.on('finish', () => { redirects.should.eql(['/movies', '/movies/all', '/movies/all/0']); fs.readFileSync(destinationPath, 'utf8').should.eql('first movie page'); done(); }); request_.pipe(stream);
request pipe
- should act as a writable stream
const request_ = request.post(base); const stream = fs.createReadStream('test/node/fixtures/user.json'); request_.type('json'); request_.on('response', (res) => { res.body.should.eql({ name: 'tobi' }); done(); }); stream.pipe(request_);
- end() stops piping
const stream = fs.createWriteStream(destinationPath); request.get(base).end((error, res) => { try { res.pipe(stream); return done(new Error('Did not prevent nonsense pipe')); } catch { /* expected error */ } done(); });
- should act as a readable stream
const stream = fs.createWriteStream(destinationPath); let responseCalled = false; const request_ = request.get(base); request_.type('json'); request_.on('response', (res) => { res.status.should.eql(200); responseCalled = true; }); stream.on('finish', () => { JSON.parse(fs.readFileSync(destinationPath)).should.eql({ name: 'tobi' }); responseCalled.should.be.true(); done(); }); request_.pipe(stream);
- should follow redirects
const stream = fs.createWriteStream(destinationPath); let responseCalled = false; const request_ = request.get(base + '/redirect'); request_.type('json'); request_.on('response', (res) => { res.status.should.eql(200); responseCalled = true; }); stream.on('finish', () => { JSON.parse(fs.readFileSync(destinationPath)).should.eql({ name: 'tobi' }); responseCalled.should.be.true(); done(); }); request_.pipe(stream);
- should not throw on bad redirects
const stream = fs.createWriteStream(destinationPath); let responseCalled = false; let errorCalled = false; const request_ = request.get(base + '/badRedirectNoLocation'); request_.type('json'); request_.on('response', (res) => { responseCalled = true; }); request_.on('error', (error) => { error.message.should.eql('No location header for redirect'); errorCalled = true; stream.end(); }); stream.on('finish', () => { responseCalled.should.be.false(); errorCalled.should.be.true(); done(); }); request_.pipe(stream);
req.query(String)
- should support passing in a string
request .del(base) .query('name=t%F6bi') .end((error, res) => { res.body.should.eql({ name: 't%F6bi' }); done(); });
- should work with url query-string and string for query
request .del(`${base}/?name=tobi`) .query('age=2%20') .end((error, res) => { res.body.should.eql({ name: 'tobi', age: '2 ' }); done(); });
- should support compound elements in a string
request .del(base) .query('name=t%F6bi&age=2') .end((error, res) => { res.body.should.eql({ name: 't%F6bi', age: '2' }); done(); });
- should work when called multiple times with a string
request .del(base) .query('name=t%F6bi') .query('age=2%F6') .end((error, res) => { res.body.should.eql({ name: 't%F6bi', age: '2%F6' }); done(); });
- should work with normal `query` object and query string
request .del(base) .query('name=t%F6bi') .query({ age: '2' }) .end((error, res) => { res.body.should.eql({ name: 't%F6bi', age: '2' }); done(); });
- should not encode raw backticks, but leave encoded ones as is
return Promise.all([ request .get(`${base}/raw-query`) .query('name=`t%60bi`&age`=2') .then((res) => { res.text.should.eql('name=`t%60bi`&age`=2'); }), request.get(base + '/raw-query?`age%60`=2%60`').then((res) => { res.text.should.eql('`age%60`=2%60`'); }), request .get(`${base}/raw-query`) .query('name=`t%60bi`') .query('age`=2') .then((res) => { res.text.should.eql('name=`t%60bi`&age`=2'); }) ]);
req.query(Object)
- should construct the query-string
request .del(base) .query({ name: 'tobi' }) .query({ order: 'asc' }) .query({ limit: ['1', '2'] }) .end((error, res) => { res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] }); done(); });
- should encode raw backticks
request .get(`${base}/raw-query`) .query({ name: '`tobi`' }) .query({ 'orde%60r': null }) .query({ '`limit`': ['%602`'] }) .end((error, res) => { res.text.should.eql('name=%60tobi%60&orde%2560r&%60limit%60=%25602%60'); done(); });
- should not error on dates
const date = new Date(0); request .del(base) .query({ at: date }) .end((error, res) => { assert.equal(date.toISOString(), res.body.at); done(); });
- should work after setting header fields
request .del(base) .set('Foo', 'bar') .set('Bar', 'baz') .query({ name: 'tobi' }) .query({ order: 'asc' }) .query({ limit: ['1', '2'] }) .end((error, res) => { res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] }); done(); });
- should append to the original query-string
request .del(`${base}/?name=tobi`) .query({ order: 'asc' }) .end((error, res) => { res.body.should.eql({ name: 'tobi', order: 'asc' }); done(); });
- should retain the original query-string
request.del(`${base}/?name=tobi`).end((error, res) => { res.body.should.eql({ name: 'tobi' }); done(); });
- should keep only keys with null querystring values
request .del(`${base}/url`) .query({ nil: null }) .end((error, res) => { res.text.should.equal('/url?nil'); done(); });
- query-string should be sent on pipe
this.timeout(15_000); const request_ = request.put(`${base}/?name=tobi`); const stream = fs.createReadStream('test/node/fixtures/user.json'); request_.on('response', (res) => { res.body.should.eql({ name: 'tobi' }); done(); }); request_.on('error', (err) => { done(err); }); stream.on('error', function (err) { done(err); }); stream.pipe(request_);
request.get
- should follow Location with a GET request
const request_ = request.get(`${base}/test-301`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-302`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-303`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-307`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.get(`${base}/test-308`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
on 301 redirect
on 302 redirect
on 303 redirect
on 307 redirect
on 308 redirect
request.post
- should follow Location with a GET request
const request_ = request.post(`${base}/test-301`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.post(`${base}/test-302`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a GET request
const request_ = request.post(`${base}/test-303`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('GET'); done(); });
- should follow Location with a POST request
const request_ = request.post(`${base}/test-307`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('POST'); done(); });
- should follow Location with a POST request
const request_ = request.post(`${base}/test-308`).redirects(1); request_.end((error, res) => { const headers = request_.req.getHeaders ? request_.req.getHeaders() : request_.req._headers; headers.host.should.eql(`localhost:${server2.address().port}`); res.status.should.eql(200); res.text.should.eql('POST'); done(); });
on 301 redirect
on 302 redirect
on 303 redirect
on 307 redirect
on 308 redirect
request
- should merge cookies if agent is used
request .agent() .get(`${base}/cookie-redirect`) .set('Cookie', 'orig=1; replaced=not') .end((error, res) => { try { assert.ifError(error); assert(/orig=1/.test(res.text), 'orig=1/.test'); assert(/replaced=yes/.test(res.text), 'replaced=yes/.test'); assert(/from-redir=1/.test(res.text), 'from-redir=1'); done(); } catch (err) { done(err); } });
- should not merge cookies if agent is not used
request .get(`${base}/cookie-redirect`) .set('Cookie', 'orig=1; replaced=not') .end((error, res) => { try { assert.ifError(error); assert(/orig=1/.test(res.text), '/orig=1'); assert(/replaced=not/.test(res.text), '/replaced=not'); assert(!/replaced=yes/.test(res.text), '!/replaced=yes'); assert(!/from-redir/.test(res.text), '!/from-redir'); done(); } catch (err) { done(err); } });
- should have previously set cookie for subsquent requests when agent is used
const agent = request.agent(); agent.get(`${base}/set-cookie`).end((error) => { assert.ifError(error); agent .get(`${base}/show-cookies`) .set({ Cookie: 'orig=1' }) .end((error, res) => { try { assert.ifError(error); assert(/orig=1/.test(res.text), 'orig=1/.test'); assert(/persist=123/.test(res.text), 'persist=123'); done(); } catch (err) { done(err); } }); });
- should follow Location
const redirects = []; request .get(base) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { const array = ['/movies', '/movies/all', '/movies/all/0']; redirects.should.eql(array); res.text.should.equal('first movie page'); done(); } catch (err) { done(err); } });
- should follow Location with IP override
const redirects = []; const url = URL.parse(base); return request .get(`http://redir.example.com:${url.port || '80'}${url.pathname}`) .connect({ '*': url.hostname }) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { const array = ['/movies', '/movies/all', '/movies/all/0']; redirects.should.eql(array); res.text.should.equal('first movie page'); });
- should follow Location with IP:port override
const redirects = []; const url = URL.parse(base); return request .get(`http://redir.example.com:9999${url.pathname}`) .connect({ '*': { host: url.hostname, port: url.port || 80 } }) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { const array = ['/movies', '/movies/all', '/movies/all/0']; redirects.should.eql(array); res.text.should.equal('first movie page'); });
- should not follow on HEAD by default
const redirects = []; return request .head(base) .ok(() => true) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { redirects.should.eql([]); res.status.should.equal(302); });
- should follow on HEAD when redirects are set
const redirects = []; request .head(base) .redirects(10) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { const array = []; array.push('/movies', '/movies/all', '/movies/all/0'); redirects.should.eql(array); assert(!res.text); done(); } catch (err) { done(err); } });
- should remove Content-* fields
request .post(`${base}/header`) .type('txt') .set('X-Foo', 'bar') .set('X-Bar', 'baz') .send('hey') .end((error, res) => { try { assert(res.body); res.body.should.have.property('x-foo', 'bar'); res.body.should.have.property('x-bar', 'baz'); res.body.should.not.have.property('content-type'); res.body.should.not.have.property('content-length'); res.body.should.not.have.property('transfer-encoding'); done(); } catch (err) { done(err); } });
- should retain cookies
request .get(`${base}/header`) .set('Cookie', 'foo=bar;') .end((error, res) => { try { assert(res.body); res.body.should.have.property('cookie', 'foo=bar;'); done(); } catch (err) { done(err); } });
- should not resend query parameters
const redirects = []; const query = []; request .get(`${base}/?foo=bar`) .on('redirect', (res) => { query.push(res.headers.query); redirects.push(res.headers.location); }) .end((error, res) => { try { const array = []; array.push('/movies', '/movies/all', '/movies/all/0'); redirects.should.eql(array); res.text.should.equal('first movie page'); query.should.eql(['{"foo":"bar"}', '{}', '{}']); res.headers.query.should.eql('{}'); done(); } catch (err) { done(err); } });
- should handle no location header
request.get(`${base}/bad-redirect`).end((error, res) => { try { error.message.should.equal('No location header for redirect'); done(); } catch (err) { done(err); } });
- should redirect to a sibling path
const redirects = []; request .get(`${base}/relative`) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { redirects.should.eql(['tobi']); res.text.should.equal('tobi'); done(); } catch (err) { done(err); } });
- should redirect to a parent path
const redirects = []; request .get(`${base}/relative/sub`) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { redirects.should.eql(['../tobi']); res.text.should.equal('tobi'); done(); } catch (err) { done(err); } });
- should alter the default number of redirects to follow
const redirects = []; request .get(base) .redirects(2) .on('redirect', (res) => { redirects.push(res.headers.location); }) .end((error, res) => { try { const array = []; assert(res.redirect, 'res.redirect'); array.push('/movies', '/movies/all'); redirects.should.eql(array); res.text.should.match(/Moved Temporarily|Found/); done(); } catch (err) { done(err); } });
- should redirect as GET
const redirects = []; return request .post(`${base}/movie`) .send({ name: 'Tobi' }) .redirects(2) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { redirects.should.eql(['/movies/all/0']); res.text.should.equal('first movie page'); });
- using multipart/form-data should redirect as GET
const redirects = []; request .post(`${base}/movie`) .type('form') .field('name', 'Tobi') .redirects(2) .on('redirect', (res) => { redirects.push(res.headers.location); }) .then((res) => { redirects.should.eql(['/movies/all/0']); res.text.should.equal('first movie page'); });
on redirect
when relative
req.redirects(n)
on POST
response
- should act as a readable stream
const request_ = request.get(base).buffer(false); request_.end((error, res) => { if (error) return done(error); let trackEndEvent = 0; let trackCloseEvent = 0; res.on('end', () => { trackEndEvent++; trackEndEvent.should.equal(1); if (!process.env.HTTP2_TEST) { trackCloseEvent.should.equal(0); // close should not have been called } done(); }); res.on('close', () => { trackCloseEvent++; }); setTimeout(() => { (() => { res.pause(); }).should.not.throw(); (() => { res.resume(); }).should.not.throw(); (() => { res.destroy(); }).should.not.throw(); }, 50); });
req.serialize(fn)
- should take precedence over default parsers
request .post(`${base}/echo`) .send({ foo: 123 }) .serialize(() => '{"bar":456}') .end((error, res) => { assert.ifError(error); assert.equal('{"bar":456}', res.text); assert.equal(456, res.body.bar); done(); });
res.toError()
- should return an Error
request.get(base).end((err, res) => { const error = res.toError(); assert.equal(error.status, 400); assert.equal(error.method, 'GET'); assert.equal(error.path, '/'); assert.equal(error.message, 'cannot GET / (400)'); assert.equal(error.text, 'invalid json'); done(); });
[unix-sockets] http
- path: / (root)
request.get(`${base}/`).end((error, res) => { assert(res.ok); assert.strictEqual('root ok!', res.text); done(); });
- path: /request/path
request.get(`${base}/request/path`).end((error, res) => { assert(res.ok); assert.strictEqual('request path ok!', res.text); done(); });
request
[unix-sockets] https
- path: / (root)
request .get(`${base}/`) .ca(cacert) .end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('root ok!', res.text); done(); });
- path: /request/path
request .get(`${base}/request/path`) .ca(cacert) .end((error, res) => { assert.ifError(error); assert(res.ok); assert.strictEqual('request path ok!', res.text); done(); });
request
req.get()
- should not set a default user-agent
request.get(`${base}/ua`).then((res) => { assert(res.headers); assert(!res.headers['user-agent']); })
utils.type(str)
- should return the mime type
utils .type('application/json; charset=utf-8') .should.equal('application/json'); utils.type('application/json').should.equal('application/json');
utils.params(str)
- should return the field parameters
const object = utils.params('application/json; charset=utf-8; foo = bar'); object.charset.should.equal('utf-8'); object.foo.should.equal('bar'); utils.params('application/json').should.eql({});
utils.parseLinks(str)
- should parse links
const string_ = '<https://api.github.com/repos/visionmedia/mocha/issues?page=2>; rel="next", <https://api.github.com/repos/visionmedia/mocha/issues?page=5>; rel="last"'; const returnValue = utils.parseLinks(string_); returnValue.next.should.equal( 'https://api.github.com/repos/visionmedia/mocha/issues?page=2' ); returnValue.last.should.equal( 'https://api.github.com/repos/visionmedia/mocha/issues?page=5' );