Тестирование API Mocha: получение "TypeError: app.address не является функцией"

103

Моя проблема

Я закодирован очень простой CRUD API , и я начал в последнее время кодирования также некоторые тесты с использованием chaiи , chai-httpно у меня проблема при выполнении моих тестов с $ mocha.

Когда я запускаю тесты, я получаю следующую ошибку в оболочке:

TypeError: app.address is not a function

Мой код

Вот образец одного из моих тестов ( /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...

  });

});

И expressфайлы моего приложения ( /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);
});

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

Дополнительные примечания

Я пробовал выйти из serverпеременной в файле /tests/server-test.js перед запуском тестов:

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

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

и я результатом этого является пустой объект: server: {}.

Чарлибрауни
источник

Ответы:

230

Вы ничего не экспортируете в своем модуле приложения. Попробуйте добавить это в свой файл app.js:

module.exports = server
xersiee
источник
33
единственная проблема, с которой я столкнулся, заключается в том, что код приложения никогда не должен изменяться для соответствия тесту.
dman
@chovy, ты решил это? У меня есть альтернатива, которая сработала для меня.
Skyguard
1
потенциальная проблема связана с сервером, который содержит асинхронные службы, потому что chai-http не знает логики этого, и он будет работать напрямую даже до того, как ваш сервер полностью запустится
atom2ueki
1
@Nabuska в этом случае сервер, вероятно, уже настроен с помощью app.listen (...)
Гарр Годфри
Для ваших тестов вы не должны использовать app.listen (), который запускает реальный сервер, вместо этого используйте http.createServer ()
Whyhankee
42

Важно экспортировать http.Serverобъект, возвращаемый app.listen(3000)функцией app, а не только функцию , иначе вы получите TypeError: app.address is not a function.

Пример:

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
Вы должны указать в своем ответе, почему «важно экспортировать http.Serverобъект».
GrumpyCrouton 09
@GrumpyCrouton Я добавил ошибку, которую вы получите в противном случае
Ким Керн
1
Спасибо, Ким. Я поставил вам +1, потому что думаю, это улучшит ваш ответ. В будущем вам следует объяснить, почему . Представьте, что кто-то смотрит на этот вопрос и имеет только базовые знания, хорошо продуманный и объясненный ответ научит их гораздо большему.
GrumpyCrouton
Для ваших тестов вы не должны использовать app.listen (), который запускает реальный сервер, вместо этого используйте http.createServer ()
Whyhankee
28

Это также может помочь и удовлетворяет точку @dman изменения кода приложения для соответствия тесту.

сделайте свой запрос на localhost и порт по мере необходимости chai.request('http://localhost:5000')

вместо того

chai.request(server)

это исправило то же сообщение об ошибке, которое у меня было при использовании Koa JS (v2) и ava js.

Skyguard
источник
3
После выполнения эта ошибка не появляется, но в данных get приходит null и код состояния 200 в порядке.
Анита Мехта
4

Приведенные выше ответы правильно решают проблему: supertestхочет, http.Serverчтобы над ним поработали. Однако вызов app.listen()для получения сервера также запустит прослушивающий сервер, что является плохой практикой и ненужно.

Вы можете обойти это, используя 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

У нас была такая же проблема, когда мы запускали mocha с помощью ts-node в нашем бессерверном проекте node + typescript.

В нашем tsconfig.json было "sourceMap": true. Созданные таким образом файлы .js и .js.map вызывают некоторые забавные проблемы с транспилированием (похожие на это). Когда мы запускаем mocha runner с помощью ts-node. Итак, я установил для флага sourceMap значение false и удалил все файлы .js и .js.map в нашем каталоге src. Тогда проблема исчезла.

Если вы уже создали файлы в своей папке src, приведенные ниже команды будут действительно полезны.

найти src -name " .js.map" -exec rm {} \; найти src -name " .js" -exec rm {} \;

Дилуника
источник
0

На всякий случай, если кто-то использует Hapijs, проблема все равно возникает, потому что он не использует Express.js, поэтому функции address () не существует.

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

Обходной путь, чтобы заставить его работать

// 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()
      })
    })
  })
Леонардо Ампуэро
источник