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