Prueba de API de Mocha: obtener 'TypeError: app.address no es una función'

102

Mi problema

He codificado una API CRUD muy simple y recientemente comencé a codificar también algunas pruebas usando chaiy, chai-httppero tengo un problema al ejecutar mis pruebas con $ mocha.

Cuando ejecuto las pruebas, aparece el siguiente error en el shell:

TypeError: app.address is not a function

Mi código

Aquí hay una muestra de una de mis pruebas ( /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...

  });

});

Y mis expressarchivos de aplicación ( /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);
});

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

Notas adicionales

Intenté cerrar la sesión de la servervariable en el archivo /tests/server-test.js antes de ejecutar las pruebas:

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

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

y el resultado de ello es un objeto vacío: server: {}.

charliebrownie
fuente

Respuestas:

228

No exporta nada en el módulo de su aplicación. Intente agregar esto a su archivo app.js:

module.exports = server
xersiee
fuente
31
el único problema que tengo con esto es que el código de la aplicación nunca debe cambiarse para ajustarse a una prueba.
dman
@chovy, ¿resolviste esto? Tengo una alternativa a continuación que funcionó para mí.
Skyguard
1
el problema potencial es lidiar con un servidor que contiene servicios asíncronos, porque chai-http no conoce la lógica de eso, y se ejecutará directamente incluso antes de que su servidor se inicie por completo
atom2ueki
1
@Nabuska en este caso, el servidor probablemente ya esté configurado con app.listen (...)
Garr Godfrey
Para sus pruebas, no debe usar app.listen () que inicia un servidor real, use http.createServer () en su lugar
Whyhankee
42

Es importante exportar el http.Serverobjeto devuelto por en app.listen(3000)lugar de solo la función app, de lo contrario obtendrá TypeError: app.address is not a function.

Ejemplo:

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
fuente
2
Debe incluir en su respuesta por qué es "importante exportar el http.Serverobjeto".
GrumpyCrouton
@GrumpyCrouton Agregué el error que obtendrás de lo contrario
Kim Kern
1
Gracias Kim. Te di un +1 porque creo que eso mejora tu respuesta. En el futuro, deberías explicar por qué . Imagínese a alguien que está mirando esta pregunta y solo tiene conocimientos básicos, una respuesta bien pensada y explicada le enseñará mucho más.
GrumpyCrouton
Para sus pruebas, no debe usar app.listen () que inicia un servidor real, use http.createServer () en su lugar
Whyhankee
28

Esto también puede ayudar y satisface el punto de @dman de cambiar el código de la aplicación para que se ajuste a una prueba.

haga su solicitud al localhost y al puerto según sea necesario chai.request('http://localhost:5000')

en vez de

chai.request(server)

esto solucionó el mismo mensaje de error que tenía al usar Koa JS (v2) y ava js.

Skyguard
fuente
3
Después de hacer esto, este error no viene, pero en get data es nulo y el código de estado 200 está bien.
Anita Mehta
4

Las respuestas anteriores abordan correctamente el problema: supertestquiere http.Serverque se trabaje. Sin embargo, llamar app.listen()para obtener un servidor también iniciará un servidor de escucha, esta es una mala práctica e innecesaria.

Puede sortear esto usando 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));
});
Gracias
fuente
1

Tuvimos el mismo problema cuando ejecutamos mocha usando ts-node en nuestro proyecto sin servidor node + typecript.

Nuestro tsconfig.json tenía "sourceMap": true. Los archivos .js y .js.map generados de esta manera causan algunos problemas de transpilación divertidos (similares a este). Cuando ejecutamos mocha runner usando ts-node. Por lo tanto, estableceré el indicador sourceMap en falso y eliminaré todos los archivos .js y .js.map en nuestro directorio src. Entonces el problema se ha ido.

Si ya ha generado archivos en su carpeta src, los siguientes comandos serían realmente útiles.

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

Dilunika
fuente
0

Por si acaso, si alguien usa Hapijs, el problema aún ocurre, porque no usa Express.js, por lo que la función address () no existe.

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

La solución para que funcione

// 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()
      })
    })
  })
Leonardo Ampuero
fuente