modularize tests for application

closes #517

add index test for Application

add app.toJSON test

add test for app.inspect()

add tests for app.use()

add tests for app.onerror()

add tests for app.respond()

add tests for app.context()

add tests for app.request()

add tests for app.response

refactor for non-existence of test/app...js

no need for *.js

use helpers/ dir for non-tests
master
Tejas Manohar 2015-10-11 23:59:30 -05:00 committed by Jonathan Ong
parent ef467caabd
commit e8f79d43f9
62 changed files with 385 additions and 345 deletions

View File

@ -4,7 +4,7 @@ include node_modules/make-lint/index.mk
REQUIRED = --require should --require should-http
TESTS = test/application \
TESTS = test/application/* \
test/context/* \
test/request/* \
test/response/* \

View File

@ -0,0 +1,34 @@
'use strict';
const request = require('supertest');
const assert = require('assert');
const koa = require('../..');
describe('app.context', function(){
const app1 = koa();
app1.context.msg = 'hello';
const app2 = koa();
it('should merge properties', function(done){
app1.use(function *(next){
assert.equal(this.msg, 'hello')
this.status = 204
});
request(app1.listen())
.get('/')
.expect(204, done);
})
it('should not affect the original prototype', function(done){
app2.use(function *(next){
assert.equal(this.msg, undefined)
this.status = 204;
});
request(app2.listen())
.get('/')
.expect(204, done);
})
})

56
test/application/index.js Normal file
View File

@ -0,0 +1,56 @@
'use strict';
const request = require('supertest');
const assert = require('assert');
const koa = require('../..');
describe('app', function(){
it('should handle socket errors', function(done){
const app = koa();
app.use(function *(next){
// triggers this.socket.writable == false
this.socket.emit('error', new Error('boom'));
});
app.on('error', function(err){
err.message.should.equal('boom');
done();
});
request(app.listen())
.get('/')
.end(function(){});
})
it('should not .writeHead when !socket.writable', function(done){
const app = koa();
app.use(function *(next){
// set .writable to false
this.socket.writable = false;
this.status = 204;
// throw if .writeHead or .end is called
this.res.writeHead =
this.res.end = function(){
throw new Error('response sent');
};
})
// hackish, but the response should occur in a single tick
setImmediate(done);
request(app.listen())
.get('/')
.end(function(){});
})
it('should set development env when NODE_ENV missing', function(){
const NODE_ENV = process.env.NODE_ENV;
process.env.NODE_ENV = '';
const app = koa();
process.env.NODE_ENV = NODE_ENV;
assert.equal(app.env, 'development');
})
})

View File

@ -0,0 +1,12 @@
'use strict';
const koa = require('../..');
describe('app.inspect()', function(){
it('should work', function(){
const app = koa();
const util = require('util');
const str = util.inspect(app);
})
})

View File

@ -0,0 +1,84 @@
'use strict';
const stderr = require('test-console').stderr;
const koa = require('../..');
const AssertionError = require('assert').AssertionError;
describe('app.onerror(err)', function(){
it('should throw an error if a non-error is given', function(done){
const app = koa();
try {
app.onerror('foo');
should.fail();
} catch (err) {
err.should.be.instanceOf(AssertionError);
err.message.should.equal('non-error thrown: foo');
}
done();
})
it('should do nothing if status is 404', function(done){
const app = koa();
const err = new Error();
err.status = 404;
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql([]);
done();
})
it('should do nothing if .silent', function(done){
const app = koa();
app.silent = true;
const err = new Error();
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql([]);
done();
})
it('should log the error to stderr', function(done){
const app = koa();
app.env = 'dev';
const err = new Error();
err.stack = 'Foo';
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql(["\n", " Foo\n", "\n"]);
done();
})
it('should use err.toString() instad of err.stack', function(done){
const app = koa();
app.env = 'dev';
const err = new Error('mock stack null');
err.stack = null;
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql(["\n", " Error: mock stack null\n", "\n"]);
done();
})
})

View File

@ -0,0 +1,34 @@
'use strict';
const request = require('supertest');
const assert = require('assert');
const koa = require('../..');
describe('app.request', function(){
const app1 = koa();
app1.request.message = 'hello';
const app2 = koa();
it('should merge properties', function(done){
app1.use(function *(next){
assert.equal(this.request.message, 'hello')
this.status = 204
});
request(app1.listen())
.get('/')
.expect(204, done);
})
it('should not affect the original prototype', function(done){
app2.use(function *(next){
assert.equal(this.request.message, undefined)
this.status = 204;
});
request(app2.listen())
.get('/')
.expect(204, done);
})
})

View File

@ -1,214 +1,11 @@
'use strict';
const stderr = require('test-console').stderr;
const request = require('supertest');
const statuses = require('statuses');
const assert = require('assert');
const http = require('http');
const koa = require('..');
const koa = require('../..');
const fs = require('fs');
const AssertionError = assert.AssertionError;
describe('app', function(){
it('should handle socket errors', function(done){
const app = koa();
app.use(function *(next){
// triggers this.socket.writable == false
this.socket.emit('error', new Error('boom'));
});
app.on('error', function(err){
err.message.should.equal('boom');
done();
});
request(app.listen())
.get('/')
.end(function(){});
})
it('should not .writeHead when !socket.writable', function(done){
const app = koa();
app.use(function *(next){
// set .writable to false
this.socket.writable = false;
this.status = 204;
// throw if .writeHead or .end is called
this.res.writeHead =
this.res.end = function(){
throw new Error('response sent');
};
})
// hackish, but the response should occur in a single tick
setImmediate(done);
request(app.listen())
.get('/')
.end(function(){});
})
it('should set development env when NODE_ENV missing', function(){
const NODE_ENV = process.env.NODE_ENV;
process.env.NODE_ENV = '';
const app = koa();
process.env.NODE_ENV = NODE_ENV;
assert.equal(app.env, 'development');
})
})
describe('app.toJSON()', function(){
it('should work', function(){
const app = koa();
const obj = app.toJSON();
obj.should.eql({
subdomainOffset: 2,
env: 'test'
});
})
})
describe('app.inspect()', function(){
it('should work', function(){
const app = koa();
const util = require('util');
const str = util.inspect(app);
})
})
describe('app.use(fn)', function(){
it('should compose middleware', function(done){
const app = koa();
const calls = [];
app.use(function *(next){
calls.push(1);
yield next;
calls.push(6);
});
app.use(function *(next){
calls.push(2);
yield next;
calls.push(5);
});
app.use(function *(next){
calls.push(3);
yield next;
calls.push(4);
});
const server = app.listen();
request(server)
.get('/')
.expect(404)
.end(function(err){
if (err) return done(err);
calls.should.eql([1,2,3,4,5,6]);
done();
});
})
it('should error when a non-generator function is passed', function(){
const app = koa();
try {
app.use(function(){});
} catch (err) {
err.message.should.equal('app.use() requires a generator function');
}
})
it('should not error when a non-generator function is passed when .experimental=true', function(){
const app = koa();
app.experimental = true;
app.use(function(){});
})
})
describe('app.onerror(err)', function(){
it('should throw an error if a non-error is given', function(done){
const app = koa();
try {
app.onerror('foo');
should.fail();
} catch (err) {
err.should.be.instanceOf(AssertionError);
err.message.should.equal('non-error thrown: foo');
}
done();
})
it('should do nothing if status is 404', function(done){
const app = koa();
const err = new Error();
err.status = 404;
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql([]);
done();
})
it('should do nothing if .silent', function(done){
const app = koa();
app.silent = true;
const err = new Error();
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql([]);
done();
})
it('should log the error to stderr', function(done){
const app = koa();
app.env = 'dev';
const err = new Error();
err.stack = 'Foo';
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql(["\n", " Foo\n", "\n"]);
done();
})
it('should use err.toString() instad of err.stack', function(done){
const app = koa();
app.env = 'dev';
const err = new Error('mock stack null');
err.stack = null;
const output = stderr.inspectSync(function() {
app.onerror(err);
});
output.should.eql(["\n", " Error: mock stack null\n", "\n"]);
done();
})
})
describe('app.respond', function(){
describe('when this.respond === false', function(){
@ -722,7 +519,7 @@ describe('app.respond', function(){
.expect('Content-Type', 'application/json; charset=utf-8')
.end(function(err, res){
if (err) return done(err);
const pkg = require('../package');
const pkg = require('../../package');
res.should.not.have.header('Content-Length');
res.body.should.eql(pkg);
done();
@ -745,7 +542,7 @@ describe('app.respond', function(){
.expect('Content-Type', 'application/json; charset=utf-8')
.end(function(err, res){
if (err) return done(err);
const pkg = require('../package');
const pkg = require('../../package');
res.should.not.have.header('Content-Length');
res.body.should.eql(pkg);
done();
@ -768,7 +565,7 @@ describe('app.respond', function(){
.expect('Content-Type', 'application/json; charset=utf-8')
.end(function(err, res){
if (err) return done(err);
const pkg = require('../package');
const pkg = require('../../package');
res.should.have.header('Content-Length');
res.body.should.eql(pkg);
done();
@ -793,7 +590,7 @@ describe('app.respond', function(){
.expect('Content-Type', 'application/json; charset=utf-8')
.end(function(err, res){
if (err) return done(err);
const pkg = require('../package');
const pkg = require('../../package');
res.should.have.header('Content-Length');
res.body.should.eql(pkg);
done();
@ -1001,87 +798,3 @@ describe('app.respond', function(){
});
})
})
describe('app.context', function(){
const app1 = koa();
app1.context.msg = 'hello';
const app2 = koa();
it('should merge properties', function(done){
app1.use(function *(next){
assert.equal(this.msg, 'hello')
this.status = 204
});
request(app1.listen())
.get('/')
.expect(204, done);
})
it('should not affect the original prototype', function(done){
app2.use(function *(next){
assert.equal(this.msg, undefined)
this.status = 204;
});
request(app2.listen())
.get('/')
.expect(204, done);
})
})
describe('app.request', function(){
const app1 = koa();
app1.request.message = 'hello';
const app2 = koa();
it('should merge properties', function(done){
app1.use(function *(next){
assert.equal(this.request.message, 'hello')
this.status = 204
});
request(app1.listen())
.get('/')
.expect(204, done);
})
it('should not affect the original prototype', function(done){
app2.use(function *(next){
assert.equal(this.request.message, undefined)
this.status = 204;
});
request(app2.listen())
.get('/')
.expect(204, done);
})
})
describe('app.response', function(){
const app1 = koa();
app1.response.msg = 'hello';
const app2 = koa();
it('should merge properties', function(done){
app1.use(function *(next){
assert.equal(this.response.msg, 'hello')
this.status = 204
});
request(app1.listen())
.get('/')
.expect(204, done);
})
it('should not affect the original prototype', function(done){
app2.use(function *(next){
assert.equal(this.response.msg, undefined)
this.status = 204;
});
request(app2.listen())
.get('/')
.expect(204, done);
})
})

View File

@ -0,0 +1,34 @@
'use strict';
const request = require('supertest');
const assert = require('assert');
const koa = require('../..');
describe('app.response', function(){
const app1 = koa();
app1.response.msg = 'hello';
const app2 = koa();
it('should merge properties', function(done){
app1.use(function *(next){
assert.equal(this.response.msg, 'hello')
this.status = 204
});
request(app1.listen())
.get('/')
.expect(204, done);
})
it('should not affect the original prototype', function(done){
app2.use(function *(next){
assert.equal(this.response.msg, undefined)
this.status = 204;
});
request(app2.listen())
.get('/')
.expect(204, done);
})
})

View File

@ -0,0 +1,16 @@
'use strict';
const koa = require('../..');
describe('app.toJSON()', function(){
it('should work', function(){
const app = koa();
const obj = app.toJSON();
obj.should.eql({
subdomainOffset: 2,
env: 'test'
});
})
})

57
test/application/use.js Normal file
View File

@ -0,0 +1,57 @@
'use strict';
const request = require('supertest');
const koa = require('../..');
describe('app.use(fn)', function(){
it('should compose middleware', function(done){
const app = koa();
const calls = [];
app.use(function *(next){
calls.push(1);
yield next;
calls.push(6);
});
app.use(function *(next){
calls.push(2);
yield next;
calls.push(5);
});
app.use(function *(next){
calls.push(3);
yield next;
calls.push(4);
});
const server = app.listen();
request(server)
.get('/')
.expect(404)
.end(function(err){
if (err) return done(err);
calls.should.eql([1,2,3,4,5,6]);
done();
});
})
it('should error when a non-generator function is passed', function(){
const app = koa();
try {
app.use(function(){});
} catch (err) {
err.message.should.equal('app.use() requires a generator function');
}
})
it('should not error when a non-generator function is passed when .experimental=true', function(){
const app = koa();
app.experimental = true;
app.use(function(){});
})
})

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
const assert = require('assert');
describe('ctx.assert(value, status)', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.inspect()', function(){
it('should return a json representation', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
const assert = require('assert');
describe('ctx.throw(msg)', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.toJSON()', function(){
it('should return a json representation', function(){

View File

@ -2,7 +2,7 @@
'use strict';
const Stream = require('stream');
const koa = require('..');
const koa = require('../..');
exports = module.exports = function(req, res){
const socket = new Stream.Duplex();

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.accepts(types)', function(){
describe('with no arguments', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.acceptsCharsets()', function(){
describe('with no arguments', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.acceptsEncodings()', function(){
describe('with no arguments', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.acceptsLanguages(langs)', function(){
describe('with no arguments', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
const assert = require('assert');
describe('req.charset', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.fresh', function(){
describe('the request method is not GET and HEAD', function (){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.get(name)', function(){
it('should return the field value', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('req.header', function(){
it('should return the request header object', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('req.headers', function(){
it('should return the request header object', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
const assert = require('assert');
describe('req.host', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
const assert = require('assert');
describe('req.hostname', function(){

View File

@ -4,7 +4,7 @@
const Stream = require('stream');
const http = require('http');
const koa = require('../../');
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.href', function(){
it('should return the full request url', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('ctx.idempotent', function(){
describe('when the request method is idempotent', function (){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
const assert = require('assert');
describe('req.inspect()', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('req.ip', function(){
describe('with req.ips present', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('req.ips', function(){
describe('when X-Forwarded-For is present', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
const should = require('should');
const assert = require('assert');

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
const assert = require('assert');
describe('ctx.length', function(){

View File

@ -4,7 +4,7 @@
const Stream = require('stream');
const http = require('http');
const koa = require('../../');
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.origin', function(){
it('should return the origin of url', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.path', function(){
it('should return the pathname', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('req.protocol', function(){
describe('when encrypted', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.query', function(){
describe('when missing', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.querystring', function(){
it('should return the querystring', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.search=', function(){
it('should replace the search', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('req.secure', function(){
it('should return true when encrypted', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('req.stale', function(){
it('should be the inverse of req.fresh', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
describe('req.subdomains', function(){
it('should return subdomain array', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const request = require('../context').request;
const request = require('../helpers/context').request;
const assert = require('assert');
describe('req.type', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.append(name, val)', function(){
it('should append multiple headers', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
const request = require('supertest');
const koa = require('../..');

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
const assert = require('assert');
const fs = require('fs');

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
describe('res.etag=', function(){
it('should not modify an etag with quotes', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
describe('res.header', function(){
it('should return the response header object', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
describe('res.header', function(){
it('should return the response header object', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
const assert = require('assert');
describe('res.inspect()', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
const should = require('should');
const assert = require('assert');

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
describe('res.lastModified', function(){
it('should set the header as a UTCString', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
const should = require('should');
const assert = require('assert');
const fs = require('fs');

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
const Stream = require('stream');
describe('res.message', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.redirect(url)', function(){
it('should redirect to the given url', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.remove(name)', function(){
it('should remove a field', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.set(name, val)', function(){
it('should set a field value', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
const Stream = require('stream');
describe('res.socket', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
const request = require('supertest');
const statuses = require('statuses');
const assert = require('assert');

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
const assert = require('assert');
describe('ctx.type=', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const context = require('../context');
const context = require('../helpers/context');
describe('ctx.vary(field)', function(){
describe('when Vary is not set', function(){

View File

@ -1,7 +1,7 @@
'use strict';
const response = require('../context').response;
const response = require('../helpers/context').response;
describe('res.writable', function(){
it('should return the request is writable', function(){