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: {}.

Respuestas:


228

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

module.exports = server

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 ...', () => {

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.


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));
});

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 {} \;


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()
      })
    })
  })
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.