Merge tag '4.19.0' into 5.x
[express.git] / test / res.send.js
blob2cdbe41dbf08b274fa771ffa2610684d05dba542
1 'use strict'
3 var assert = require('assert')
4 var Buffer = require('safe-buffer').Buffer
5 var express = require('..');
6 var methods = require('methods');
7 var request = require('supertest');
8 var utils = require('./support/utils');
10 describe('res', function(){
11   describe('.send()', function(){
12     it('should set body to ""', function(done){
13       var app = express();
15       app.use(function(req, res){
16         res.send();
17       });
19       request(app)
20       .get('/')
21       .expect(200, '', done);
22     })
23   })
25   describe('.send(null)', function(){
26     it('should set body to ""', function(done){
27       var app = express();
29       app.use(function(req, res){
30         res.send(null);
31       });
33       request(app)
34       .get('/')
35       .expect('Content-Length', '0')
36       .expect(200, '', done);
37     })
38   })
40   describe('.send(undefined)', function(){
41     it('should set body to ""', function(done){
42       var app = express();
44       app.use(function(req, res){
45         res.send(undefined);
46       });
48       request(app)
49       .get('/')
50       .expect(200, '', done);
51     })
52   })
54   describe('.send(Number)', function(){
55     it('should send as application/json', function(done){
56       var app = express();
58       app.use(function(req, res){
59         res.send(1000);
60       });
62       request(app)
63       .get('/')
64       .expect('Content-Type', 'application/json; charset=utf-8')
65       .expect(200, '1000', done)
66     })
67   })
69   describe('.send(String)', function(){
70     it('should send as html', function(done){
71       var app = express();
73       app.use(function(req, res){
74         res.send('<p>hey</p>');
75       });
77       request(app)
78       .get('/')
79       .expect('Content-Type', 'text/html; charset=utf-8')
80       .expect(200, '<p>hey</p>', done);
81     })
83     it('should set ETag', function (done) {
84       var app = express();
86       app.use(function (req, res) {
87         var str = Array(1000).join('-');
88         res.send(str);
89       });
91       request(app)
92       .get('/')
93       .expect('ETag', 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"')
94       .expect(200, done);
95     })
97     it('should not override Content-Type', function(done){
98       var app = express();
100       app.use(function(req, res){
101         res.set('Content-Type', 'text/plain').send('hey');
102       });
104       request(app)
105       .get('/')
106       .expect('Content-Type', 'text/plain; charset=utf-8')
107       .expect(200, 'hey', done);
108     })
110     it('should override charset in Content-Type', function(done){
111       var app = express();
113       app.use(function(req, res){
114         res.set('Content-Type', 'text/plain; charset=iso-8859-1').send('hey');
115       });
117       request(app)
118       .get('/')
119       .expect('Content-Type', 'text/plain; charset=utf-8')
120       .expect(200, 'hey', done);
121     })
123     it('should keep charset in Content-Type for Buffers', function(done){
124       var app = express();
126       app.use(function(req, res){
127         res.set('Content-Type', 'text/plain; charset=iso-8859-1').send(Buffer.from('hi'))
128       });
130       request(app)
131       .get('/')
132       .expect('Content-Type', 'text/plain; charset=iso-8859-1')
133       .expect(200, 'hi', done);
134     })
135   })
137   describe('.send(Buffer)', function(){
138     it('should send as octet-stream', function(done){
139       var app = express();
141       app.use(function(req, res){
142         res.send(Buffer.from('hello'))
143       });
145       request(app)
146         .get('/')
147         .expect(200)
148         .expect('Content-Type', 'application/octet-stream')
149         .expect(utils.shouldHaveBody(Buffer.from('hello')))
150         .end(done)
151     })
153     it('should set ETag', function (done) {
154       var app = express();
156       app.use(function (req, res) {
157         res.send(Buffer.alloc(999, '-'))
158       });
160       request(app)
161       .get('/')
162       .expect('ETag', 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"')
163       .expect(200, done);
164     })
166     it('should not override Content-Type', function(done){
167       var app = express();
169       app.use(function(req, res){
170         res.set('Content-Type', 'text/plain').send(Buffer.from('hey'))
171       });
173       request(app)
174       .get('/')
175       .expect('Content-Type', 'text/plain; charset=utf-8')
176       .expect(200, 'hey', done);
177     })
179     it('should not override ETag', function (done) {
180       var app = express()
182       app.use(function (req, res) {
183         res.type('text/plain').set('ETag', '"foo"').send(Buffer.from('hey'))
184       })
186       request(app)
187       .get('/')
188       .expect('ETag', '"foo"')
189       .expect(200, 'hey', done)
190     })
191   })
193   describe('.send(Object)', function(){
194     it('should send as application/json', function(done){
195       var app = express();
197       app.use(function(req, res){
198         res.send({ name: 'tobi' });
199       });
201       request(app)
202       .get('/')
203       .expect('Content-Type', 'application/json; charset=utf-8')
204       .expect(200, '{"name":"tobi"}', done)
205     })
206   })
208   describe('when the request method is HEAD', function(){
209     it('should ignore the body', function(done){
210       var app = express();
212       app.use(function(req, res){
213         res.send('yay');
214       });
216       request(app)
217         .head('/')
218         .expect(200)
219         .expect(utils.shouldNotHaveBody())
220         .end(done)
221     })
222   })
224   describe('when .statusCode is 204', function(){
225     it('should strip Content-* fields, Transfer-Encoding field, and body', function(done){
226       var app = express();
228       app.use(function(req, res){
229         res.status(204).set('Transfer-Encoding', 'chunked').send('foo');
230       });
232       request(app)
233       .get('/')
234       .expect(utils.shouldNotHaveHeader('Content-Type'))
235       .expect(utils.shouldNotHaveHeader('Content-Length'))
236       .expect(utils.shouldNotHaveHeader('Transfer-Encoding'))
237       .expect(204, '', done);
238     })
239   })
241   describe('when .statusCode is 205', function () {
242     it('should strip Transfer-Encoding field and body, set Content-Length', function (done) {
243       var app = express()
245       app.use(function (req, res) {
246         res.status(205).set('Transfer-Encoding', 'chunked').send('foo')
247       })
249       request(app)
250         .get('/')
251         .expect(utils.shouldNotHaveHeader('Transfer-Encoding'))
252         .expect('Content-Length', '0')
253         .expect(205, '', done)
254     })
255   })
257   describe('when .statusCode is 304', function(){
258     it('should strip Content-* fields, Transfer-Encoding field, and body', function(done){
259       var app = express();
261       app.use(function(req, res){
262         res.status(304).set('Transfer-Encoding', 'chunked').send('foo');
263       });
265       request(app)
266       .get('/')
267       .expect(utils.shouldNotHaveHeader('Content-Type'))
268       .expect(utils.shouldNotHaveHeader('Content-Length'))
269       .expect(utils.shouldNotHaveHeader('Transfer-Encoding'))
270       .expect(304, '', done);
271     })
272   })
274   it('should always check regardless of length', function(done){
275     var app = express();
276     var etag = '"asdf"';
278     app.use(function(req, res, next){
279       res.set('ETag', etag);
280       res.send('hey');
281     });
283     request(app)
284     .get('/')
285     .set('If-None-Match', etag)
286     .expect(304, done);
287   })
289   it('should respond with 304 Not Modified when fresh', function(done){
290     var app = express();
291     var etag = '"asdf"';
293     app.use(function(req, res){
294       var str = Array(1000).join('-');
295       res.set('ETag', etag);
296       res.send(str);
297     });
299     request(app)
300     .get('/')
301     .set('If-None-Match', etag)
302     .expect(304, done);
303   })
305   it('should not perform freshness check unless 2xx or 304', function(done){
306     var app = express();
307     var etag = '"asdf"';
309     app.use(function(req, res, next){
310       res.status(500);
311       res.set('ETag', etag);
312       res.send('hey');
313     });
315     request(app)
316     .get('/')
317     .set('If-None-Match', etag)
318     .expect('hey')
319     .expect(500, done);
320   })
322   it('should not support jsonp callbacks', function(done){
323     var app = express();
325     app.use(function(req, res){
326       res.send({ foo: 'bar' });
327     });
329     request(app)
330     .get('/?callback=foo')
331     .expect('{"foo":"bar"}', done);
332   })
334   it('should be chainable', function (done) {
335     var app = express()
337     app.use(function (req, res) {
338       assert.equal(res.send('hey'), res)
339     })
341     request(app)
342     .get('/')
343     .expect(200, 'hey', done)
344   })
346   describe('"etag" setting', function () {
347     describe('when enabled', function () {
348       it('should send ETag', function (done) {
349         var app = express();
351         app.use(function (req, res) {
352           res.send('kajdslfkasdf');
353         });
355         app.enable('etag');
357         request(app)
358         .get('/')
359         .expect('ETag', 'W/"c-IgR/L5SF7CJQff4wxKGF/vfPuZ0"')
360         .expect(200, done);
361       });
363       methods.forEach(function (method) {
364         if (method === 'connect') return;
366         it('should send ETag in response to ' + method.toUpperCase() + ' request', function (done) {
367           var app = express();
369           app[method]('/', function (req, res) {
370             res.send('kajdslfkasdf');
371           });
373           request(app)
374           [method]('/')
375           .expect('ETag', 'W/"c-IgR/L5SF7CJQff4wxKGF/vfPuZ0"')
376           .expect(200, done);
377         })
378       });
380       it('should send ETag for empty string response', function (done) {
381         var app = express();
383         app.use(function (req, res) {
384           res.send('');
385         });
387         app.enable('etag');
389         request(app)
390         .get('/')
391         .expect('ETag', 'W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"')
392         .expect(200, done);
393       })
395       it('should send ETag for long response', function (done) {
396         var app = express();
398         app.use(function (req, res) {
399           var str = Array(1000).join('-');
400           res.send(str);
401         });
403         app.enable('etag');
405         request(app)
406         .get('/')
407         .expect('ETag', 'W/"3e7-qPnkJ3CVdVhFJQvUBfF10TmVA7g"')
408         .expect(200, done);
409       });
411       it('should not override ETag when manually set', function (done) {
412         var app = express();
414         app.use(function (req, res) {
415           res.set('etag', '"asdf"');
416           res.send('hello!');
417         });
419         app.enable('etag');
421         request(app)
422         .get('/')
423         .expect('ETag', '"asdf"')
424         .expect(200, done);
425       });
427       it('should not send ETag for res.send()', function (done) {
428         var app = express();
430         app.use(function (req, res) {
431           res.send();
432         });
434         app.enable('etag');
436         request(app)
437         .get('/')
438         .expect(utils.shouldNotHaveHeader('ETag'))
439         .expect(200, done);
440       })
441     });
443     describe('when disabled', function () {
444       it('should send no ETag', function (done) {
445         var app = express();
447         app.use(function (req, res) {
448           var str = Array(1000).join('-');
449           res.send(str);
450         });
452         app.disable('etag');
454         request(app)
455         .get('/')
456         .expect(utils.shouldNotHaveHeader('ETag'))
457         .expect(200, done);
458       });
460       it('should send ETag when manually set', function (done) {
461         var app = express();
463         app.disable('etag');
465         app.use(function (req, res) {
466           res.set('etag', '"asdf"');
467           res.send('hello!');
468         });
470         request(app)
471         .get('/')
472         .expect('ETag', '"asdf"')
473         .expect(200, done);
474       });
475     });
477     describe('when "strong"', function () {
478       it('should send strong ETag', function (done) {
479         var app = express();
481         app.set('etag', 'strong');
483         app.use(function (req, res) {
484           res.send('hello, world!');
485         });
487         request(app)
488         .get('/')
489         .expect('ETag', '"d-HwnTDHB9U/PRbFMN1z1wps51lqk"')
490         .expect(200, done);
491       })
492     })
494     describe('when "weak"', function () {
495       it('should send weak ETag', function (done) {
496         var app = express();
498         app.set('etag', 'weak');
500         app.use(function (req, res) {
501           res.send('hello, world!');
502         });
504         request(app)
505         .get('/')
506         .expect('ETag', 'W/"d-HwnTDHB9U/PRbFMN1z1wps51lqk"')
507         .expect(200, done)
508       })
509     })
511     describe('when a function', function () {
512       it('should send custom ETag', function (done) {
513         var app = express();
515         app.set('etag', function (body, encoding) {
516           var chunk = !Buffer.isBuffer(body)
517             ? Buffer.from(body, encoding)
518             : body;
519           assert.strictEqual(chunk.toString(), 'hello, world!')
520           return '"custom"';
521         });
523         app.use(function (req, res) {
524           res.send('hello, world!');
525         });
527         request(app)
528         .get('/')
529         .expect('ETag', '"custom"')
530         .expect(200, done);
531       })
533       it('should not send falsy ETag', function (done) {
534         var app = express();
536         app.set('etag', function (body, encoding) {
537           return undefined;
538         });
540         app.use(function (req, res) {
541           res.send('hello, world!');
542         });
544         request(app)
545         .get('/')
546         .expect(utils.shouldNotHaveHeader('ETag'))
547         .expect(200, done);
548       })
549     })
550   })