UNPKG

9.09 kBMarkdownView Raw
1# SuperTest
2
3[![code coverage][coverage-badge]][coverage]
4[![Build Status][travis-badge]][travis]
5[![Dependencies][dependencies-badge]][dependencies]
6[![PRs Welcome][prs-badge]][prs]
7[![MIT License][license-badge]][license]
8
9> HTTP assertions made easy via [superagent](http://github.com/ladjs/superagent). Maintained for [Forward Email](https://github.com/forwardemail) and [Lad](https://github.com/ladjs).
10
11## About
12
13The motivation with this module is to provide a high-level abstraction for testing
14HTTP, while still allowing you to drop down to the [lower-level API](https://ladjs.github.io/superagent/) provided by superagent.
15
16## Getting Started
17
18Install SuperTest as an npm module and save it to your package.json file as a development dependency:
19
20```bash
21npm install supertest --save-dev
22```
23
24 Once installed it can now be referenced by simply calling ```require('supertest');```
25
26## Example
27
28You may pass an `http.Server`, or a `Function` to `request()` - if the server is not
29already listening for connections then it is bound to an ephemeral port for you so
30there is no need to keep track of ports.
31
32SuperTest works with any test framework, here is an example without using any
33test framework at all:
34
35```js
36const request = require('supertest');
37const assert = require('assert');
38const express = require('express');
39
40const app = express();
41
42app.get('/user', function(req, res) {
43 res.status(200).json({ name: 'john' });
44});
45
46request(app)
47 .get('/user')
48 .expect('Content-Type', /json/)
49 .expect('Content-Length', '15')
50 .expect(200)
51 .end(function(err, res) {
52 if (err) throw err;
53 });
54```
55
56To enable http2 protocol, simply append an options to `request` or `request.agent`:
57
58```js
59const request = require('supertest');
60const express = require('express');
61
62const app = express();
63
64app.get('/user', function(req, res) {
65 res.status(200).json({ name: 'john' });
66});
67
68request(app, { http2: true })
69 .get('/user')
70 .expect('Content-Type', /json/)
71 .expect('Content-Length', '15')
72 .expect(200)
73 .end(function(err, res) {
74 if (err) throw err;
75 });
76
77request.agent(app, { http2: true })
78 .get('/user')
79 .expect('Content-Type', /json/)
80 .expect('Content-Length', '15')
81 .expect(200)
82 .end(function(err, res) {
83 if (err) throw err;
84 });
85```
86
87Here's an example with mocha, note how you can pass `done` straight to any of the `.expect()` calls:
88
89```js
90describe('GET /user', function() {
91 it('responds with json', function(done) {
92 request(app)
93 .get('/user')
94 .set('Accept', 'application/json')
95 .expect('Content-Type', /json/)
96 .expect(200, done);
97 });
98});
99```
100
101You can use `auth` method to pass HTTP username and password in the same way as in the [superagent](http://ladjs.github.io/superagent/#authentication):
102
103```js
104describe('GET /user', function() {
105 it('responds with json', function(done) {
106 request(app)
107 .get('/user')
108 .auth('username', 'password')
109 .set('Accept', 'application/json')
110 .expect('Content-Type', /json/)
111 .expect(200, done);
112 });
113});
114```
115
116One thing to note with the above statement is that superagent now sends any HTTP
117error (anything other than a 2XX response code) to the callback as the first argument if
118you do not add a status code expect (i.e. `.expect(302)`).
119
120If you are using the `.end()` method `.expect()` assertions that fail will
121not throw - they will return the assertion as an error to the `.end()` callback. In
122order to fail the test case, you will need to rethrow or pass `err` to `done()`, as follows:
123
124```js
125describe('POST /users', function() {
126 it('responds with json', function(done) {
127 request(app)
128 .post('/users')
129 .send({name: 'john'})
130 .set('Accept', 'application/json')
131 .expect('Content-Type', /json/)
132 .expect(200)
133 .end(function(err, res) {
134 if (err) return done(err);
135 return done();
136 });
137 });
138});
139```
140
141You can also use promises:
142
143```js
144describe('GET /users', function() {
145 it('responds with json', function() {
146 return request(app)
147 .get('/users')
148 .set('Accept', 'application/json')
149 .expect('Content-Type', /json/)
150 .expect(200)
151 .then(response => {
152 assert(response.body.email, 'foo@bar.com')
153 })
154 });
155});
156```
157
158Or async/await syntax:
159
160```js
161describe('GET /users', function() {
162 it('responds with json', async function() {
163 const response = await request(app)
164 .get('/users')
165 .set('Accept', 'application/json')
166 expect(response.headers["Content-Type"]).toMatch(/json/);
167 expect(response.status).toEqual(200);
168 expect(response.body.email).toEqual('foo@bar.com');
169 });
170});
171```
172
173Expectations are run in the order of definition. This characteristic can be used
174to modify the response body or headers before executing an assertion.
175
176```js
177describe('POST /user', function() {
178 it('user.name should be an case-insensitive match for "john"', function(done) {
179 request(app)
180 .post('/user')
181 .send('name=john') // x-www-form-urlencoded upload
182 .set('Accept', 'application/json')
183 .expect(function(res) {
184 res.body.id = 'some fixed id';
185 res.body.name = res.body.name.toLowerCase();
186 })
187 .expect(200, {
188 id: 'some fixed id',
189 name: 'john'
190 }, done);
191 });
192});
193```
194
195Anything you can do with superagent, you can do with supertest - for example multipart file uploads!
196
197```js
198request(app)
199 .post('/')
200 .field('name', 'my awesome avatar')
201 .field('complex_object', '{"attribute": "value"}', {contentType: 'application/json'})
202 .attach('avatar', 'test/fixtures/avatar.jpg')
203 ...
204```
205
206Passing the app or url each time is not necessary, if you're testing
207the same host you may simply re-assign the request variable with the
208initialization app or url, a new `Test` is created per `request.VERB()` call.
209
210```js
211request = request('http://localhost:5555');
212
213request.get('/').expect(200, function(err){
214 console.log(err);
215});
216
217request.get('/').expect('heya', function(err){
218 console.log(err);
219});
220```
221
222Here's an example with mocha that shows how to persist a request and its cookies:
223
224```js
225const request = require('supertest');
226const should = require('should');
227const express = require('express');
228const cookieParser = require('cookie-parser');
229
230describe('request.agent(app)', function() {
231 const app = express();
232 app.use(cookieParser());
233
234 app.get('/', function(req, res) {
235 res.cookie('cookie', 'hey');
236 res.send();
237 });
238
239 app.get('/return', function(req, res) {
240 if (req.cookies.cookie) res.send(req.cookies.cookie);
241 else res.send(':(')
242 });
243
244 const agent = request.agent(app);
245
246 it('should save cookies', function(done) {
247 agent
248 .get('/')
249 .expect('set-cookie', 'cookie=hey; Path=/', done);
250 });
251
252 it('should send cookies', function(done) {
253 agent
254 .get('/return')
255 .expect('hey', done);
256 });
257});
258```
259
260There is another example that is introduced by the file [agency.js](https://github.com/ladjs/superagent/blob/master/test/node/agency.js)
261
262Here is an example where 2 cookies are set on the request.
263
264```js
265agent(app)
266 .get('/api/content')
267 .set('Cookie', ['nameOne=valueOne;nameTwo=valueTwo'])
268 .send()
269 .expect(200)
270 .end((err, res) => {
271 if (err) {
272 return done(err);
273 }
274 expect(res.text).to.be.equal('hey');
275 return done();
276 });
277```
278
279## API
280
281You may use any [superagent](http://github.com/ladjs/superagent) methods,
282including `.write()`, `.pipe()` etc and perform assertions in the `.end()` callback
283for lower-level needs.
284
285### .expect(status[, fn])
286
287Assert response `status` code.
288
289### .expect(status, body[, fn])
290
291Assert response `status` code and `body`.
292
293### .expect(body[, fn])
294
295Assert response `body` text with a string, regular expression, or
296parsed body object.
297
298### .expect(field, value[, fn])
299
300Assert header `field` `value` with a string or regular expression.
301
302### .expect(function(res) {})
303
304Pass a custom assertion function. It'll be given the response object to check. If the check fails, throw an error.
305
306```js
307request(app)
308 .get('/')
309 .expect(hasPreviousAndNextKeys)
310 .end(done);
311
312function hasPreviousAndNextKeys(res) {
313 if (!('next' in res.body)) throw new Error("missing next key");
314 if (!('prev' in res.body)) throw new Error("missing prev key");
315}
316```
317
318### .end(fn)
319
320Perform the request and invoke `fn(err, res)`.
321
322## Notes
323
324Inspired by [api-easy](https://github.com/flatiron/api-easy) minus vows coupling.
325
326## License
327
328MIT
329
330[coverage-badge]: https://img.shields.io/codecov/c/github/ladjs/supertest.svg
331[coverage]: https://codecov.io/gh/ladjs/supertest
332[travis-badge]: https://travis-ci.org/ladjs/supertest.svg?branch=master
333[travis]: https://travis-ci.org/ladjs/supertest
334[dependencies-badge]: https://david-dm.org/ladjs/supertest/status.svg
335[dependencies]: https://david-dm.org/ladjs/supertest
336[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
337[prs]: http://makeapullrequest.com
338[license-badge]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square
339[license]: https://github.com/ladjs/supertest/blob/master/LICENSE