Mocha API Testing: getting 'TypeError: app.address is not a function'
Solution 1
You don't export anything in your app module. Try adding this to your app.js file:
module.exports = server
Solution 2
It's important to export the http.Server
object returned by app.listen(3000)
instead of just the function app
, otherwise you will get TypeError: app.address is not a function
.
Example:
index.js
const koa = require('koa');
const app = new koa();
module.exports = app.listen(3000);
index.spec.js
const request = require('supertest');
const app = require('./index.js');
describe('User Registration', () => {
const agent = request.agent(app);
it('should ...', () => {
Solution 3
This may also help, and satisfies @dman point of changing application code to fit a test.
make your request to the localhost and port as needed
chai.request('http://localhost:5000')
instead of
chai.request(server)
this fixed the same error message I had using Koa JS (v2) and ava js.
Solution 4
The answers above correctly address the issue: supertest
wants an http.Server
to work on. However, calling app.listen()
to get a server will also start a listening server, this is bad practice and unnecessary.
You can get around by this by using http.createServer()
:
import * as http from 'http';
import * as supertest from 'supertest';
import * as test from 'tape';
import * as Koa from 'koa';
const app = new Koa();
# add some routes here
const apptest = supertest(http.createServer(app.callback()));
test('GET /healthcheck', (t) => {
apptest.get('/healthcheck')
.expect(200)
.expect(res => {
t.equal(res.text, 'Ok');
})
.end(t.end.bind(t));
});
Solution 5
Just in case, if someone uses Hapijs the issue still occurs, because it does not use Express.js, thus address() function does not exist.
TypeError: app.address is not a function
at serverAddress (node_modules/chai-http/lib/request.js:282:18)
The workaround to make it work
// this makes the server to start up
let server = require('../../server')
// pass this instead of server to avoid error
const API = 'http://localhost:3000'
describe('/GET token ', () => {
it('JWT token', (done) => {
chai.request(API)
.get('/api/token?....')
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.a('object')
res.body.should.have.property('token')
done()
})
})
})
charliebrownie
I am a Software Engineer with strong interest in: Clean Code and good practices the whole Software Development Process Web Development & Technologies "Life is about creating yourself." "Do what you love, love what you do."
Updated on November 20, 2020Comments
-
charliebrownie over 3 years
My Issue
I've coded a very simple CRUD API and I've started recently coding also some tests using
chai
andchai-http
but I'm having an issue when running my tests with$ mocha
.When I run the tests I get the following error on the shell:
TypeError: app.address is not a function
My Code
Here is a sample of one of my tests (/tests/server-test.js):
var chai = require('chai'); var mongoose = require('mongoose'); var chaiHttp = require('chai-http'); var server = require('../server/app'); // my express app var should = chai.should(); var testUtils = require('./test-utils'); chai.use(chaiHttp); describe('API Tests', function() { before(function() { mongoose.createConnection('mongodb://localhost/bot-test', myOptionsObj); }); beforeEach(function(done) { // I do stuff like populating db }); afterEach(function(done) { // I do stuff like deleting populated db }); after(function() { mongoose.connection.close(); }); describe('Boxes', function() { it.only('should list ALL boxes on /boxes GET', function(done) { chai.request(server) .get('/api/boxes') .end(function(err, res){ res.should.have.status(200); done(); }); }); // the rest of the tests would continue here... }); });
And my
express
app files (/server/app.js):var mongoose = require('mongoose'); var express = require('express'); var api = require('./routes/api.js'); var app = express(); mongoose.connect('mongodb://localhost/db-dev', myOptionsObj); // application configuration require('./config/express')(app); // routing set up app.use('/api', api); var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('App listening at http://%s:%s', host, port); });
and (/server/routes/api.js):
var express = require('express'); var boxController = require('../modules/box/controller'); var thingController = require('../modules/thing/controller'); var router = express.Router(); // API routing router.get('/boxes', boxController.getAll); // etc. module.exports = router;
Extra notes
I've tried logging out the
server
variable in the /tests/server-test.js file before running the tests:... var server = require('../server/app'); // my express app ... console.log('server: ', server); ...
and I the result of that is an empty object:
server: {}
. -
dman about 8 yearsthe only issue I have with this is that the application code should never be changed to fit a test.
-
Skyguard about 7 years@chovy did you resolve this? I have an alternative below that worked for me.
-
atom2ueki about 7 yearsthe potential problem is dealing with server which contains a async services, because chai-http don't know the logic of that, and it will run directly even before your server fully started
-
Anita Mehta almost 7 yearsAfter doing this error is not coming, but in get data is coming null and statuscode 200 ok.
-
GrumpyCrouton almost 7 yearsYou should include in your answer why it's "important to export the
http.Server
object". -
Kim Kern almost 7 years@GrumpyCrouton I added the error you will get otherwise
-
GrumpyCrouton almost 7 yearsThank you Kim. I gave you a +1 because I think that does improve your answer. In the future, you should explain why. Imagine someone looking at this question and only has basic knowledge, a well thought out and explained answer will teach them a lot more.
-
Garr Godfrey about 6 years@Nabuska in this case server is probably already set with app.listen(...)
-
Whyhankee almost 5 yearsFor your tests you shoud not use app.listen() which starts an actual server, use http.createServer() instead
-
Whyhankee almost 5 yearsFor your tests you shoud not use app.listen() which starts an actual server, use http.createServer() instead
-
Amirhosein Al over 4 yearsWorks for me but when I wrap it in an
if(!process.env.prod)
it doesn't -
1011 1110 about 3 yearsHonestly I think this should be the accepted answer, calling app.listen() in the app will make you run into issues later.
-
Catfish over 2 yearsThe problem with this answer is that you create a separate app to run your tests, which doesn't include the actual code of your route handlers. How I've always solved this problem is simply have a function which accepts a param on whether to call
app.listen
or not and that function always returns theapp
object. -
an1waukoni about 2 yearsThanks for your answer and explanation. I've been debugging this for two days straight!