问题
I'm quite new to node and express. And have been trying to write test code using mocha, chai and chai-http. Here's the part of source code.
const mongoose = require('mongoose'),
User = require('../../models/user');
const mongoUrl = 'mongodb://xxxxxxxxxxx';
describe('/test', function() {
before('connect', function() {
return mongoose.createConnection(mongoUrl);
});
beforeEach(async function(done) {
try {
await User.remove({}); // <-- This doesn't work
chai.request('http://localhost:3000')
.post('/api/test')
.send(something)
.end((err, res) => {
if (err) return done(err);
done();
});
} catch (error) {
done(error);
}
});
});
And I get the following error with "npm test"(nyc mocha --timeout 10000 test/**/*.js).
Error: Timeout of 10000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
I confirmed the database connection works properly from log. And seems I get the timeout error with await User.remove({}). I've also tried different methods such as a User.save() But, I got the same error. Do I need to do something special with database model and connection?
回答1:
I had the same problem and have not found a way to get any promises that involve mongoose
working with Mocha/Chai.
What may help you is doing what I did and putting your mongoose code in a script so you can run it with node <scriptfile>.js
. You can use that to confirm it's working properly by itself. In my test, the mongoose operation finished in less than a second. You can also call that file from another (non-test related) to confirm it executes properly and returns a promise. You can see from my example how to make sure you close db properly. Partial example:
...
db.close();
return new Promise((resolve) => {
db.on('disconnected', () => {
console.log('***************************************Mongoose CONNECTION TERMINATED');
resolve('user ready');
});
});
...
You may also find some clues by looking at the following issues here and here.
The work around that I did after wasting too much time trying to figure out this crazy behavior was to perform my mongoose needs in a route. I wrap each request that needs to use it in the end
block of the extra chai.request...
or use async. Example:
describe('something', () => {
it('should do something and change it back', async () => {
try {
// change user password
let re1 = await chai.request(app)
.post('/users/edit')
.set('authorization', `Bearer ${token}`)
.send({
username: 'user@domain.com',
password: 'password6',
});
expect(re1.statusCode).to.equal(200);
// change password back since before hook not working
let re2 = await chai.request(app)
.post('/users/edit')
.set('authorization', `Bearer ${token}`)
.send({
username: 'user@domain.com',
password: 'password6',
passwordNew: 'password',
passwordConfirm: 'password',
});
expect(re2.statusCode).to.equal(200);
} catch (error) {
// error stuff here
}
});
Note that using the try/catch
syntax above will cause test that should normally fail to show passing and the results will be caught in the catch block. If you want to avoid that, just remove the try/catch
.
回答2:
How did you implement ./models/user
? await
only works if User.remove()
returns a promise, not if it expects a callback. I would add debug information to your User.remove()
function to see where it gets stuck.
回答3:
This is all pretty simple.
To avoid the error you must not use both done
and async/await
in Mocha at the same time. Either use async/await
and remove both done
as function parameter and done()
call. Or use done
. Then remove both async/await
. See example test below for both.
Use try/catch
with async/await
as you would normally use it with synchronous code.
Following are the most basic Mocha tests with both async/await
and done
approaches testing the same basic HTTP server endpoint.
This is async/await
approach.
it('with async/await', async function() {
const res = await chai.request(server)
.get('/')
.send();
assert.equal(res.status, 200);
});
This is done
approach.
it('with done & callbacks', (done) => {
chai.request(server)
.get('/')
.end((err, res) => {
assert.equal(res.status, 200);
done();
});
});
See the full test file snippet.
For working example additionally spin most basic Express server as the tests counterpart in src/app.js
.
See Chai HTTP plugin docs for more info on what you can do with request testing.
This is it.
来源:https://stackoverflow.com/questions/51675305/using-await-async-with-mocha-chai