Testowanie interfejsu API Mocha: uzyskanie „TypeError: app.address nie jest funkcją”


102

Mój problem

Zakodowałem bardzo prosty interfejs API CRUD i niedawno zacząłem kodować również niektóre testy przy użyciu chaii, chai-httpale mam problem podczas uruchamiania testów w programie $ mocha.

Po uruchomieniu testów w powłoce pojawia się następujący błąd:

TypeError: app.address is not a function

Mój kod

Oto próbka jednego z moich testów ( /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...

  });

});

Oraz moje expresspliki aplikacji ( /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);
});

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

Dodatkowe notatki

Próbowałem wylogować się ze serverzmiennej w pliku /tests/server-test.js przed uruchomieniem testów:

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

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

i wynik, który jest pusty obiekt: server: {}.

Odpowiedzi:


228

Nie eksportujesz niczego w swoim module aplikacji. Spróbuj dodać to do swojego pliku app.js:

module.exports = server

31
jedyny problem, jaki mam z tym, to to, że kod aplikacji nigdy nie powinien być zmieniany, aby pasował do testu.
— dman

@chovy, czy rozwiązałeś ten problem? Mam poniżej alternatywę, która zadziałała dla mnie.
— Skyguard

1
potencjalny problem dotyczy serwera, który zawiera usługi asynchroniczne, ponieważ chai-http nie zna tej logiki i będzie działać bezpośrednio, zanim serwer zostanie w pełni uruchomiony
— atom2ueki

1
@Nabuska w tym przypadku serwer prawdopodobnie jest już ustawiony z app.listen (...)
— Garr Godfrey

Do testów nie powinieneś używać app.listen (), który uruchamia rzeczywisty serwer, zamiast tego użyj http.createServer ()
— Whyhankee

42

Ważne jest, aby wyeksportować http.Serverobiekt zwrócony przez, app.listen(3000)a nie tylko funkcję app, w przeciwnym razie otrzymasz TypeError: app.address is not a function.

Przykład:

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
W swojej odpowiedzi powinieneś zawrzeć, dlaczego „ważne jest, aby wyeksportować http.Serverobiekt”.
— GrumpyCrouton

@GrumpyCrouton Dodałem błąd, który otrzymasz w przeciwnym razie
— Kim Kern

1
Dziękuję Kim. Dałem Ci +1, ponieważ myślę, że to poprawi Twoją odpowiedź. W przyszłości powinieneś wyjaśnić dlaczego . Wyobraź sobie, że ktoś patrzy na to pytanie i ma tylko podstawową wiedzę, dobrze przemyślana i wyjaśniona odpowiedź nauczy go o wiele więcej.
— GrumpyCrouton

Dla testów Ci shoud nie używać app.listen (), która rozpoczyna rzeczywisty serwer, użyj http.createServer () zamiast
— Whyhankee

28

Może to również pomóc i spełnia wymagania @dman dotyczące zmiany kodu aplikacji w celu dopasowania do testu.

w razie potrzeby wyślij żądanie do hosta lokalnego i portu chai.request('http://localhost:5000')

zamiast

chai.request(server)

naprawiło to ten sam komunikat o błędzie, który miałem przy użyciu Koa JS (v2) i ava js.


3
Po wykonaniu tego błędu nie nadchodzi, ale w pobieraniu danych nadchodzi null, a kod statusu 200 ok.
— Anita Mehta

4

Powyższe odpowiedzi poprawnie rozwiązują problem: supertestchce http.Serverpracować. Jednak wywołanie w app.listen()celu uzyskania serwera spowoduje również uruchomienie serwera nasłuchującego, jest to zła praktyka i niepotrzebne.

Możesz to obejść, używając 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

Mieliśmy ten sam problem, gdy uruchamialiśmy mokkę przy użyciu ts-node w naszym projekcie bezserwerowym node + Typecript.

Nasz tsconfig.json miał "sourceMap": true. Tak wygenerowane pliki .js i .js.map powodują pewne zabawne problemy z transpilacją (podobne do tego). Kiedy uruchamiamy mokkę runner za pomocą ts-node. Więc ustawię flagę sourceMap na false i usunę wszystkie pliki .js i .js.map w naszym katalogu src. Wtedy problem zniknął.

Jeśli już wygenerowałeś pliki w swoim folderze src, poniższe polecenia byłyby naprawdę pomocne.

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


0

Na wszelki wypadek, jeśli ktoś używa Hapijs, problem nadal występuje, ponieważ nie używa on Express.js, więc funkcja address () nie istnieje.

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

Sposób obejścia tego problemu

// 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()
      })
    })
  })
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.