Test d'API Mocha: obtenir 'TypeError: app.address n'est pas une fonction'

102

Mon problème

J'ai codé une API CRUD très simple et j'ai récemment commencé à coder également certains tests en utilisant chaiet, chai-httpmais j'ai un problème lors de l'exécution de mes tests avec $ mocha.

Lorsque j'exécute les tests, j'obtiens l'erreur suivante sur le shell:

TypeError: app.address is not a function

Mon code

Voici un échantillon de l'un de mes 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...

  });

});

Et mes expressfichiers d'application ( /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);
});

et ( /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;

Notes supplémentaires

J'ai essayé de déconnecter la servervariable dans le fichier /tests/server-test.js avant d'exécuter les tests:

...
var server = require('../server/app'); // my express app
...

console.log('server: ', server);
...

et je le résultat de c'est un objet vide: server: {}.

charliebrownie
la source

Réponses:

228

Vous n'exportez rien dans votre module d'application. Essayez d'ajouter ceci à votre fichier app.js:

module.exports = server
xersiee
la source
31
le seul problème que j'ai avec ceci est que le code de l'application ne doit jamais être modifié pour s'adapter à un test.
dman
@chovy avez-vous résolu ce problème? J'ai une alternative ci-dessous qui a fonctionné pour moi.
Skyguard
1
le problème potentiel concerne le serveur qui contient des services asynchrones, car chai-http ne connaît pas la logique de cela, et il fonctionnera directement avant même que votre serveur ne démarre complètement
atom2ueki
1
@Nabuska dans ce cas, le serveur est probablement déjà configuré avec app.listen (...)
Garr Godfrey
Pour vos tests, vous ne devez pas utiliser app.listen () qui démarre un serveur réel, utilisez plutôt http.createServer ()
Whyhankee
42

Il est important d'exporter l' http.Serverobjet retourné par app.listen(3000)au lieu de la fonction uniquement app, sinon vous obtiendrez TypeError: app.address is not a function.

Exemple:

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 ...', () => {
Kim Kern
la source
2
Vous devriez inclure dans votre réponse pourquoi il est "important d'exporter l' http.Serverobjet".
GrumpyCrouton
@GrumpyCrouton J'ai ajouté l'erreur que vous obtiendrez autrement
Kim Kern
1
Merci Kim. Je vous ai donné un +1 car je pense que cela améliore votre réponse. À l'avenir, vous devriez expliquer pourquoi . Imaginez quelqu'un qui regarde cette question et qui n'a que des connaissances de base, une réponse bien pensée et expliquée leur en apprendra beaucoup plus.
GrumpyCrouton
Pour vos tests, vous ne devez pas utiliser app.listen () qui démarre un serveur réel, utilisez plutôt http.createServer ()
Whyhankee
28

Cela peut également aider et satisfait le point @dman de changer le code d'application pour s'adapter à un test.

faites votre demande à l'hôte local et au port si nécessaire chai.request('http://localhost:5000')

au lieu de

chai.request(server)

cela a corrigé le même message d'erreur que j'avais en utilisant Koa JS (v2) et ava js.

Skyguard
la source
3
Après avoir fait, cette erreur ne vient pas, mais dans get, les données sont nulles et le statuscode 200 ok.
Anita Mehta
4

Les réponses ci-dessus abordent correctement le problème: supertestveut un http.Servertravail sur. Cependant, appeler app.listen()pour obtenir un serveur démarrera également un serveur d'écoute, c'est une mauvaise pratique et inutile.

Vous pouvez contourner cela en utilisant 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));
});
Whyhankee
la source
1

Nous avons eu le même problème lorsque nous avons exécuté mocha en utilisant ts-node dans notre projet sans serveur node + typScript.

Notre tsconfig.json avait "sourceMap": true. Ainsi générés, les fichiers .js et .js.map provoquent des problèmes de transpilage amusants (similaires à celui-ci). Lorsque nous exécutons mocha runner en utilisant ts-node. Donc, je vais définir l'indicateur sourceMap sur false et supprimer tous les fichiers .js et .js.map de notre répertoire src. Ensuite, le problème est parti.

Si vous avez déjà généré des fichiers dans votre dossier src, les commandes ci-dessous seraient vraiment utiles.

trouver src -name " .js.map" -exec rm {} \; trouver src -name " .js" -exec rm {} \;

Dilunika
la source
0

Juste au cas où, si quelqu'un utilise Hapijs, le problème se produit toujours, car il n'utilise pas Express.js, donc la fonction address () n'existe pas.

TypeError: app.address is not a function
      at serverAddress (node_modules/chai-http/lib/request.js:282:18)

La solution de contournement pour le faire fonctionner

// 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()
      })
    })
  })
Léonard Ampuero
la source