Using await / async with mocha, chai

非 Y 不嫁゛ 提交于 2020-06-16 02:25:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!