So i have this code below. It deletes the db and adds two users for test case.
when i verify it manually in mongo database everything shows correct but in mocha test case I get the timeout error even after defining the done argument and calling it.
Please help me on this.
const users = [{
_id: new ObjectID(),
email: 'First'
}, {
_id: new ObjectID(),
email: 'Second'
}];
beforeEach((done) => {
User.remove({}).then(() => {
return User.insertMany(users);
}).then(() => done());
})
In mocha, tests will time out after 2000 ms by default. Even if you were handling the asynchrony 100% correctly (which you are not), if you do an async operation that takes longer than 2 seconds, mocha will assume a failure. This is true even if the async operation is in a beforeEach or some other hook.
To change this, you need to invoke the timeout method on the test instance, giving it a sufficiently-high value. To access the test instance, you need to define your test functions using the function keyword rather than arrow syntax, and it will be available as this in your test functions:
beforeEach(function(done) {
this.timeout(6000); // For 6 seconds.
User.remove({}).then(() => {
return User.insertMany(users);
}).then(() => done());
});
In what way could you handle the asynchrony here better, though? As Henrik pointed out in comments, you'll never call done if either of your database calls fail. To be honest, though, since you're already dealing with promises, you shouldn't even use the done callback. Instead, just use Mocha's built-in promise support by returning the chained promise.
beforeEach(function() {
this.timeout(6000); // For 6 seconds.
return User.remove({})
.then(() => User.insertMany(users));
});
This way, if either of those promises rejects, Mocha will know and will show the rejection instead of just sitting around waiting for your test to time out.
You can even use async/await instead if you prefer:
beforeEach(async function() {
this.timeout(6000); // For 6 seconds.
await User.remove({});
await User.insertMany(users);
});
Related
I'm new to cypress and am trying to figure out how things work.
I have my own function (which calls a test controller server to reset the database). It returns a promise which completes when the DB have been successfully resetted.
function resetDatabase(){
// returns a promise for my REST api call.
}
My goal is to be able to execute it before all tests.
describe('Account test suite', function () {
// how can I call resetDb here and wait for the result
// before the tests below are invoked?
it('can log in', function () {
cy.visit(Cypress.config().testServerUrl + '/Account/Login/')
cy.get('[name="UserName"]').type("admin");
cy.get('[name="Password"]').type("123456");
cy.get('#login-button').click();
});
// .. and more test
})
How can I do that in cypress?
Update
I've tried
before(() => {
return resetDb(Cypress.config().apiServerUrl);
});
But then I get an warning saying:
Cypress detected that you returned a promise in a test, but also invoked one or more cy commands inside of that promise
I'm not invoking cy in resetDb().
Cypress have promises (Cypress.Promise), but they are not real promises, more like duck typing. In fact, Cypress isn't 100% compatible with real promises, they might, or might not, work.
Think of Cypress.Promise as a Task or an Action. They are executed sequentially with all other cypress commands.
To get your function into the Cypress pipeline you can use custom commands. The documentation doesn't state it, but you can return a Cypress.Promise from them.
Cypress.Commands.add('resetDb', function () {
var apiServerUrl = Cypress.config().apiServerUrl;
return new Cypress.Promise((resolve, reject) => {
httpRequest('PUT', apiServerUrl + "/api/test/reset/")
.then(function (data) {
resolve();
})
.catch(function (err) {
reject(err);
});
});
});
That command can then be executed from the test itself, or as in my case from before().
describe('Account', function () {
before(() => {
cy.resetDb();
});
it('can login', function () {
// test code
});
})
You can use cy.wrap( promise ), although there might still be a bug where it never times out (haven't tested).
Otherwise, you can use cy.then() (which is undocumented, can break in the future, and I'm def not doing any favors by promoting internal APIs):
cy.then(() => {
return myAsyncFunction();
});
You can use both of these commands at the top-level of spec like you'd use any command and it'll be enqueued into cypress command queue and executed in order.
But unlike cy.wrap (IIRC), cy.then() supports passing a callback, which means you can execute your async function at the time of the cy command being executed, not at the start of the spec (because expressions passed to cy commands evaluate immediately) --- that's what I'm doing in the example above.
When using supertest for testing async HTTP requests in JavaScript, what's the difference between these two snippets? Is one of them correct and the other one wrong?
request('http://localhost:8080/').get('/api/people')
.expect(res => res.body.should.have.length(5))
vs.
request('http://localhost:8080/').get('/api/people')
.then(res => res.body.should.have.length(5))
The only differences I could notice were:
expect returns a Test object and, when test fails, prints a large stack trace
then returns a Promise object and, when test fails,
prints a small stack trace
Depending on what test runner you're using will obviously affect the answer, but something like Mocha will allow you to return the Promise directly in your test and this will wait to be resolved before the test passes.
So if you having something like:
describe('Your test case', function () {
it('will wait for promise to resolve', function () {
return request('http://localhost:8080/').get('/api/people')
.then(res => res.body.should.have.length(5))
})
})
Whereas in the other instance you really should use a done callback as per https://www.npmjs.com/package/supertest docs.
I am reading some tutorials on promise tests in mocha. There is a piece of codes:
before(function(done) {
return Promise.resolve(save(article)).then(function() {
done();
});
});
Why done() called in the then() in the before()? What is the difference between the above codes and the following codes:
before(function(done) {
return Promise.resolve(save(article));
});
Thanks
UPDATE
My question is to compare with the following codes:
before(function() {
return Promise.resolve(save(article));
});
Sorry for the typo.
The first code snippet with the before hook returns a promise and calls done. In Mocha 3.x and over, it will result in this error:
Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
It used to be that it did not particularly matter if you used done and returned a promise, but eventually the Mocha devs figured that specifying both done and returning a promise just meant the test designer made a mistake and it was better to have Mocha pitch a fit rather than silently allow it.
In your 2nd snippet, you have the done argument and return a promise but Mocha will still wait for done to be called and will timeout. (It really should detect the argument and raise an error like in the 1st case, but it doesn't...)
Generally, if you are testing an asynchronous operation that produces a promise, it is simpler to return the promise than use done. Here's an example illustrating the problem:
const assert = require("assert");
// This will result in a test timeout rather than give a nice error
// message.
it("something not tested properly", (done) => {
Promise.resolve(1).then((x) => {
assert.equal(x, 2);
done();
});
});
// Same test as before, but fixed to give you a good error message
// about expecting a value of 2. But look at the code you have to
// write to get Mocha to give you a nice error message.
it("something tested properly", (done) => {
Promise.resolve(1).then((x) => {
assert.equal(x, 2);
done();
}).catch(done);
});
// If you just return the promise, you can avoid having to pepper your
// code with catch closes and calls to done.
it("something tested properly but much simpler", () => {
return Promise.resolve(1).then((x) => {
assert.equal(x, 2);
});
});
With regards to the completion of asynchronous operations, it works the same whether you are using it, before, beforeEach, after or afterEach so even though the example I gave is with it, the same applies to all the hooks.
I am not sure if I understood 100% the question, but the tests will not start until done is called.
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 1);
});
This test will not start until the done function is called in the call to beforeEach above. And this spec will not complete until its done is called.
it("should support async execution of test preparation and expectations", function(done) {
value++;
expect(value).toBeGreaterThan(0);
done();
});
You don't have to pass done in your example, just:
before(function() {
return Promise.resolve(save(article));
});
If you do pass done the test runner will expect to be called before continue, otherwise it will probably throw a timeout error.
In this particular case there is no functional difference. The callback, often called done, was introduced to handle asynchronous tests when using callbacks. Returning a Promise is sufficient, but note that you cannot define the done callback, because the test suite will wait until it's called. Use done when you can't easily return a Promise. In your case the second test will be infinite, because you define done, which you never actually call.
I want to get the result of promise in before
describe('unsubscribe', function() {
var arn;
this.timeout(10000);
before(function(done) {
sns.subscribe('param1', 'param2').then(
(result) => {
arn = result;
done();
},
(error) => {
assert.fail(error);
done();
});
});
it('("param") => promise returns object', function() {
const result = sns.unsubscribe(arn);
expect(result).to.eventually.be.an('object');
});
});
Similarly, in after I want to get result of promise in test
describe('subscribe', function() {
var arn;
this.timeout(10000);
it('("param1","param2") => promise returns string', function(done) {
sns.subscribe('param1', 'param2').then(
(result) => {
arn = result;
expect(result).to.be.a('string');
},
(error) => {
assert.fail(error);
done();
});
});
after(function(done) {
sns.unsubscribe(arn).then(
(result) => done());
});
});
Is this code properly written? Is there any better practice? What is the recommended way to do so?
Every place you want to have Mocha wait for a promise to be resolved you should just return the promise rather than use done. So your before hook can be simplified to:
before(() => sns.subscribe('param1', 'param2')
.then((result) => arn = result));
This is much more readable than having done here and there and having to do anything special for error conditions. If there is an error, the promise will reject and Mocha will catch it and report an error. There's no need to perform your own assertions.
You have a test and an after hook that could also be simplified by just returning the promises they use rather than using done. And if you test depends on a promise, remember to return it. You've forgotten it in one of your tests:
it('("param") => promise returns object', function() {
const result = sns.unsubscribe(arn);
// You need the return on this next line:
return expect(result).to.eventually.be.an('object');
});
Tip: if you have a test suite in which all tests are asynchronous, you can use the --async-only option. It will make Mocha require all tests to call done or return a promise and can help catch cases where you forget to return a promise. (Otherwise, such cases are hard to if they don't raise any error.)
Defining a variable in the callback to describe and setting it in one of the before/beforeEach hooks and checking it in the after/afterEach hooks is the standard way to pass data between hooks and tests. Mocha does not offer a special facility for it. So, yes, if you need to pass data which is the result of a promise you need to perform an assignment in .then like you do. You may run into examples where people instead of using a variable defined in the describe callback will set fields on this. Oh, this works but IMO it is brittle. A super simple example: if you set this.timeout to record some number meaningful only to your test, then you've overwritten the function that Mocha provides for changing its timeouts. You could use another name that does not clash now but will clash when a new version of Mocha is released.
Say I have a Component that renders a simple div containing an integer that starts at 0 and ticks up 1 every second. So after 5 seconds, the component should render "5" and after 30 seconds, it should render "30" and so on. If I wanted to test this component and make sure its rendering what it should after 5 seconds, I might write something like this.
it('should render <5> after 5 seconds', () => {
const time = mount(<Timer/>)
setTimeout(() => {
expect(time.text()).toEqual('5')
}, 5000)
})
However, this doesn't work as the test never actually runs the expect and returns a pass regardless of anything. And even if it did work, using a timeout like this would be extremely inefficient as the test would have to wait 5 seconds. And what if I wanted to simulate an even larger amount of time? After doing some searching, I found jest actually has a timer mock but I can't seem to figure out how to implement it for this case. Any help would be greatly appreciated. Thanks!
in order for Jest to know that your test is async, you need to either: 1) return a Promise, or 2) declare an argument in the test callback, like so:
it('should render <5> after 5 seconds', done => {
// test stuff
});
source: https://facebook.github.io/jest/docs/en/asynchronous.html
To get your test working:
it('should render <5> after 5 seconds', done => {
jest.useFakeTimers(); // this must be called before any async things happen
const time = mount(<Timer/>);
setTimeout(() => {
// Note the placement of this try/catch is important.
// You'd think it could be placed most anywhere, but nope...
try {
// If this assertion fails, an err is thrown.
// If we do not catch()...done.fail(e) it,
// then this test will take jasmine.DEFAULT_TIMEOUT_INTERVAL (5s unless you override)
// and then fail with an unhelpful message.
expect(time.text()).toEqual('5');
done();
} catch(e) {
done.fail(e);
}
}, 5000);
jest.runTimersToTime(5000); // This basically fast forwards 5s.
});
You must call jest.useFakeTimers(); before `require´ your component to mock setTimeout.
Here we enable fake timers by calling jest.useFakeTimers();. This
mocks out setTimeout and other timer functions with mock functions.
And to test async workflows Jest documentation says you have to return a Promise for each 'it' function callback.
To test an asynchronous function, just return a promise from it. When
running tests, Jest will wait for the promise to resolve before
letting the test complete. You can also return a promise from
beforeEach, afterEach, beforeAll or afterAll functions. For example,
let's say fetchBeverageList() returns a promise that is supposed to
resolve to a list that has lemon in it. You can test this with:
So you can write something like:
it('should render <5> after 5 seconds', () => {
jest.useFakeTimers();
//only after that, require your componenet
let Timer = require('./timer');
const time = mount(<Timer/>);
jest.runAllTimers();
expect(setTimeout.mock.calls.length).toBe(1);
expect(setTimeout.mock.calls[0][1]).toBe(5000);
expect(time.text()).toEqual('5');
})