Kiểm tra API Mocha: nhận được 'TypeError: app.address không phải là một hàm'


102

Vấn đề của tôi

Tôi đã viết mã một API CRUD rất đơn giản và gần đây tôi đã bắt đầu mã hóa một số thử nghiệm bằng cách sử dụng chaichai-httpnhưng tôi đang gặp sự cố khi chạy thử nghiệm của mình với $ mocha.

Khi tôi chạy các bài kiểm tra, tôi gặp lỗi sau trên shell:

TypeError: app.address is not a function

Mã của tôi

Đây là mẫu một trong các bài kiểm tra của tôi ( /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...

  });

});

expresscác tệp ứng dụng của tôi ( /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);
});

và ( /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;

Ghi chú bổ sung

Tôi đã thử đăng xuất serverbiến trong tệp /tests/server-test.js trước khi chạy thử nghiệm:

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

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

và tôi là kết quả của điều đó là một đối tượng rỗng: server: {}.

Câu trả lời:


228

Bạn không xuất bất kỳ thứ gì trong mô-đun ứng dụng của mình. Hãy thử thêm cái này vào tệp app.js của bạn:

module.exports = server

31
vấn đề duy nhất tôi gặp phải với điều này là mã ứng dụng không bao giờ được thay đổi để phù hợp với thử nghiệm.
dman

@chovy bạn đã giải quyết vấn đề này chưa? Tôi có một giải pháp thay thế bên dưới phù hợp với tôi.
Skyguard

1
vấn đề tiềm năng là đối phó với máy chủ, trong đó có một dịch vụ async, vì chai-http không biết logic đó, và nó sẽ chạy trực tiếp ngay cả trước khi máy chủ của bạn bắt đầu hoàn toàn
atom2ueki

1
@Nabuska trong máy chủ trường hợp này có lẽ đã được thiết lập với app.listen (...)
GARR Godfrey

Đối với các bài kiểm tra của mình, bạn không nên sử dụng app.listen () để khởi động một máy chủ thực tế, hãy sử dụng http.createServer () thay thế
Whyhankee

42

Điều quan trọng là xuất http.Serverđối tượng được trả về app.listen(3000)thay vì chỉ hàm app, nếu không bạn sẽ nhận được TypeError: app.address is not a function.

Thí dụ:

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
Bạn nên bao gồm trong câu trả lời của mình lý do tại sao nó "quan trọng để xuất http.Serverđối tượng".
GrumpyCrouton

@GrumpyCrouton tôi đã thêm lỗi mà bạn sẽ nhận được bằng cách khác
Kim Kern

1
Cảm ơn Kim. Tôi đã cho bạn một +1 vì tôi nghĩ điều đó sẽ cải thiện câu trả lời của bạn. Trong tương lai, bạn nên giải thích tại sao . Hãy tưởng tượng ai đó nhìn vào câu hỏi này và chỉ có kiến ​​thức cơ bản, một câu trả lời được suy nghĩ và giải thích rõ ràng sẽ dạy họ nhiều hơn.
GrumpyCrouton

Đối với các bài kiểm tra của mình, bạn không nên sử dụng app.listen () để khởi động một máy chủ thực tế, hãy sử dụng http.createServer () để thay thế
Whyhankee

28

Điều này cũng có thể hữu ích và đáp ứng @dman điểm thay đổi mã ứng dụng để phù hợp với thử nghiệm.

thực hiện yêu cầu của bạn đến máy chủ cục bộ và cổng nếu cần chai.request('http://localhost:5000')

thay vì

chai.request(server)

điều này đã khắc phục cùng một thông báo lỗi mà tôi gặp phải khi sử dụng Koa JS (v2) và ava js.


3
Sau khi thực hiện, lỗi này không đến, nhưng dữ liệu nhận được là null và mã trạng thái 200 ok.
Anita Mehta

4

Các câu trả lời ở trên giải quyết chính xác vấn đề: supertestmuốn một http.Serverhoạt động. Tuy nhiên, việc gọi app.listen()để nhận một máy chủ cũng sẽ bắt đầu một máy chủ lắng nghe, đây là một thực tiễn không tốt và không cần thiết.

Bạn có thể làm được điều này bằng cách sử dụng 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

Chúng tôi đã gặp vấn đề tương tự khi chúng tôi chạy mocha bằng ts-node trong dự án không máy chủ node + typecript của chúng tôi.

Tsconfig.json của chúng tôi có "sourceMap": true. Vì vậy, các tệp .js và .js.map được tạo ra gây ra một số vấn đề chuyển đổi buồn cười (tương tự như điều này). Khi chúng tôi chạy mocha runner bằng ts-node. Vì vậy, tôi sẽ đặt cờ sourceMap thành false và xóa tất cả tệp .js và .js.map trong thư mục src của chúng tôi. Sau đó, vấn đề đã biến mất.

Nếu bạn đã tạo tệp trong thư mục src của mình, các lệnh dưới đây sẽ thực sự hữu ích.

tìm src -name " .js.map" -exec rm {} \; tìm src -name " .js" -exec rm {} \;


0

Trong trường hợp, nếu ai đó sử dụng Hapijs, sự cố vẫn xảy ra, vì nó không sử dụng Express.js, do đó hàm address () không tồn tại.

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

Giải pháp để làm cho nó hoạt động

// 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()
      })
    })
  })
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.