首页 > 解决方案 > 使用 nodejs 测试 API 确保“done()”

问题描述

我正在使用 Nodejs 创建一个 API,我正在尝试测试她,但是当我运行 npm run test 时,会发生以下错误,我不知道如何解决,我尝试将 done() 放在最后每次测试,但没有成功,我也尝试将超时设置为 10000 毫秒,但同样的错误不断发生。

我正在使用 docker 将 mongodb 和后端联机。

错误超过 2000 毫秒的超时。对于异步测试和钩子,确保调用了“done()”;如果返回 Promise,请确保它已解决。(/home/nodejs/app/tests/unitTests.js)

测试/unitTests.js

const test = require('tape')
const request = require('supertest')
const express = require('express')

const User = require('../models/User')
const app = require('../index')
let userId

before(done => {
    app.on('APP_STARTED', () => {
        done()
    })
})

describe('API Integration Test', () => {
    it('Runs all tests', done => {
        test('/api/v1/users/', assert => {
            request(app)
                .post('/api/v1/users/')
                .send(new User('test name', '27810384074'))
                .expect(200)
                .end((err, res) => {
                    if (err) return assert.fail(JSON.stringify(res))
                    assert.pass('Created a new user successfully, test passed!')
                    assert.end()
                    done()
                })
        })

        test('/api/v1/users/', assert => {
            request(app)
                .get('/api/v1/users/')
                .expect(200)
                .end((err, res) => {
                    if (err) return assert.fail(JSON.stringify(res))
                    userId = res.body[0]._id
                    assert.pass('Got all users successfully, test passed!')
                    assert.end()
                    done()
                })
        })

        test('/api/v1/users/:id', assert => {
            request(app)
                .get(`/api/v1/users/${userId}`)
                .expect(200)
                .end((err, res) => {
                    if (err) return assert.fail(JSON.stringify(res))
                    assert.pass('Got a specific user successfully, test passed!')
                    assert.end()
                    done()
                })
        })

        test('/api/v1/users/:id', assert => {
            request(app)
                .patch(`/api/v1/users/${userId}`)
                .send(new User('test name edit', 'test cpfcnpj edit'))
                .expect(200)
                .end((err, res) => {
                    if (err) return assert.fail(JSON.stringify(res))
                    assert.pass('Edited a users successfully, test passed!')
                    assert.end()
                    done()
                })
        })

        test('/api/v1/users/:id', assert => {
            request(app)
                .delete(`/api/v1/users/${userId}`)
                .expect(200)
                .end((err, res) => {
                    if (err) return assert.fail(JSON.stringify(res))
                    assert.pass('Deleted a specific user successfully, test passed!')
                    assert.end()
                    done()
                })
        })
    })
})

index.js

const express = require('express')
const bodyParser = require('body-parser')
const MongoClient = require('mongodb')

const dbName = process.env.NODE_ENV === 'dev' ? 'database-test' : 'database'
const url = `mongodb://${process.env.MONGO_INITDB_ROOT_USERNAME}:${process.env.MONGO_INITDB_ROOT_PASSWORD}@${dbName}:27017?authMechanism=SCRAM-SHA-1&authSource=admin`
const options = {
    useNewUrlParser: true, 
    reconnectTries: 60, 
    reconnectInterval: 1000
}
const routes = require('./routes/userRoutes.js')
const port = process.env.PORT || 80
const app = express()
const http = require('http').Server(app)

app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true}))
app.use('/api/v1', routes)
app.use((req, res) => {
    res.status(404)
})

MongoClient.connect(url, options, (err, database) => {
    if(err) {
        console.log(`FATAL MONGODB CONNECTION ERROR: $(err):$(err.stack)`)
        process.exit(1)
    }
    app.locals.db = database.db('api')
    http.listen(port, () => {
        console.log("Listening on port " + port)
        app.emit('APP_STARTED')
    })
})

module.exports = app

包.json

{
  "name": "user-register",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "docker-compose -f docker/docker-compose.test.yml up --build --abort-on-container-exit",
    "production": "docker-compose -f docker/docker-compose.yml up -d",
    "build": "docker-compose -f docker/docker-compose.yml build"
  },
  "keywords": [
    "express",
    "mongo"
  ],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.3",
    "express": "^4.16.4",
    "mongodb": "^3.1.10"
  },
  "devDependencies": {
    "mocha": "^5.2.0",
    "supertest": "^3.3.0",
    "tape": "^4.9.1"
  }
}

模型/User.js

module.exports = class User {
    constructor(name, cpfcnpj){
        this.name = name
        this.cpfcnpj = cpfcnpj
    }
}

路线/userRoutes.js

const express = require('express')

const User = require('../models/User')
const router = express.Router()

router.get('/users/', (req, res, next) => {
    req.app.locals.db.collection('users').find({}).toArray((err, result) => {
        if (err) {
            res.status(400).send({
                'error': err
            })
        }
        if (result === undefined || result.length === 0) {
            res.status(400).send({
                'error': 'No users in database'
            })
        } else {
            res.status(200).send(result)
        }
    })
})

router.get('/users/:id', (req, res, next) => {
    req.app.locals.db.collection('users').findOne({
        '_id': req.params.id
    }, (err, result) => {
        if (err) {
            res.status(400).send({
                'error': err
            })
        }
        if (result === undefined) {
            res.status(400).send({
                'error': 'No user matching that id was found'
            })
        } else {
            res.status(200).send(result)
        }
    })
})

router.post('/users/', (req, res, next) => {
    const newUser = new User(req.body.title, req.body.username, req.body.body)
    req.app.locals.db.collection('users').insertOne({
        newUser
    }, (err, result) => {
        if (err) {
            res.status(400).send({
                'error': err
            })
        }
        res.status(200).send(result)
    })
})

router.delete('/users/:id', (req, res, next) => {
    req.app.locals.db.collection('users').deleteOne({
        '_id': req.params.id
    }, (err, result) => {
        if (err) {
            res.status(400).send({
                'error': err
            })
        }
        res.status(200).send(result)
    })
})

router.patch('/users/:id', (req, res, next) => {
    req.app.locals.db.collection('users').updateOne({
        '_id': req.params.id
    }, {
        $set: {
            title: req.body.title,
            username: req.body.username,
            body: req.body.body
        }
    }, (err, result) => {
        if (err) {
            res.status(400).send({
                'error': err
            })
        }
        res.status(200).send(result)
    })
})

module.exports = router

Dockerfiles:

Dockerfile.test

FROM docker_backend
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.2.1/wait /wait
RUN chmod +x /wait
ENV NODE_ENV dev
RUN npm install && npm install -g mocha --timeout 10000
ARG port=80
CMD /wait && mocha tests/unitTests.js --exit

docker-compose.test.yml

version: '3'
services:
  backend-test:
    build: 
      context: ../
      dockerfile: docker/Dockerfile.test
      args:
        port: ${PORT}
    env_file:
      - ../.env
    environment:
      WAIT_HOSTS: database-test:27017
  database-test:
    image: mongo:4.0
    env_file:
      - ../.env
    volumes:
      - ".${MONGO_TEST_DATA_DIR}:${MONGO_TEST_DATA_DIR}"
    expose:
      - 27017
    command: "mongod --smallfiles --logpath=${MONGO_LOG_FILE}"

错误:

database-test_1  | MongoDB init process complete; ready for start up.
database-test_1  |
backend-test_1   | Host database-test:27017 not yet available
backend-test_1   | Host database-test:27017 not yet available
backend-test_1   | Host database-test:27017 is now available
backend-test_1   |
backend-test_1   |
backend-test_1   | Listening on port 80
backend-test_1   |   API Integration Test
backend-test_1   | TAP version 13
backend-test_1   | # /api/users/new
backend-test_1   |     1) Runs all tests
backend-test_1   |
backend-test_1   |
backend-test_1   |   0 passing (2s)
backend-test_1   |   1 failing
backend-test_1   |
backend-test_1   |   1) API Integration Test
backend-test_1   |        Runs all tests:
backend-test_1   |      Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/nodejs/app/tests/unitTests.js)

标签: node.jsunit-testingexpressmocha.jssupertest

解决方案


推荐阅读