Protractor - Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL - jasmine

My Protractor test fails with below error
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
This is my spec file.
let common=require('./Objects/common.js')
describe('Cloud testing', function() {
it('Cloudtest1', function() {
let EC=protractor.ExpectedConditions;
browser.waitForAngularEnabled(false);
browser.get(common.loginURL);
common.txtUserName.sendKeys('aqaasdas#hkm.com');
common.txtPword.sendKeys('asdasd##$');
common.btnLogin.click();
browser.wait(EC.visibilityOf(element(by.xpath("//a[#class='btn btn-success']"))));
element(by.xpath("//a[#class='btn btn-success']")).click();
common.btnCrtPcr.click();
});
});
Any help is appreciated, I tried answers to similar questions posted here but nothing works for me. I'm running the latest Protractor and Chrome versions.

Have you tried by asyn test? Sometimes even backend response or browser performance may affect the test cases.
Refer: https://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
describe("Your module", function() {
var originalTimeout;
beforeEach(function() {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
});
it("takes a long time", function(done) {
let EC=protractor.ExpectedConditions;
browser.waitForAngularEnabled(false);
browser.get(common.loginURL);
common.txtUserName.sendKeys('aqaasdas#hkm.com');
common.txtPword.sendKeys('asdasd##$');
common.btnLogin.click();
browser.wait(EC.visibilityOf(element(by.xpath("//a[#class='btn btn-success']"))));
element(by.xpath("//a[#class='btn btn-success']")).click();
common.btnCrtPcr.click();
});
afterEach(function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
});

Your callback was later than your Jasmins default timout time. You might want to use async/await in your it block even though you have used expected condition.
it('Cloudtest1', async () => {
let EC=protractor.ExpectedConditions;
browser.waitForAngularEnabled(false);
browser.get(common.loginURL);
await common.txtUserName.sendKeys('aqaasdas#hkm.com');
await common.txtPword.sendKeys('asdasd##$');
await common.btnLogin.click();
browser.wait(EC.visibilityOf(element(by.xpath("//a[#class='btn btn-success']"))));
element(by.xpath("//a[#class='btn btn-success']")).click();
await common.btnCrtPcr.click();
});
Suggestion: Perform action in page object or before each/all. Use it block for expect statement.
example:
describe('When user logged Into account ', () => {
beforeAll(async () => {
await browser.waitForAngularEnabled(false);
await loginPO.login();
});
it('Browser title should be displayed.', async () => {
expect(await browser.getTitle()).toBe('test');
});
});

Related

WebdriverIo For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves

I have already seen this solution, but it did not help.
I am trying to run webdriver.io tests using mocha, here I am using browser.waitUntil() method from webdriver.io, more details can be found here: https://webdriver.io/docs/api/browser/waitUntil.html
I have tried a different solution to the issue including adding 'done' to the method call and also I am giving max timeout in conf.js as well here 10000ms, but still, the page seems to get hang on the result page.
Here increase timeout:
mochaOpts: {
ui: 'bdd',
timeout: 100000
},
Changed default wait time of mocha to at 100000ms
Added done as promise resolution
it('should see product and version selected', () => {
browser.url('//some url');
browser.maximizeWindow();
browser.waitUntil(() => {
return $(ProductPage.productSelector()).isDisplayed()
}, 100000, 'expected page is loaded');
let productSelector = ProductPage.otherProductSelector();
let isEnabled = productSelector.isEnabled();
if(isEnabled == true){
const spanEle = $('//span[contains(text(),"text")]');
isDisplayed = spanEle.isDisplayed();
console.log(isDisplayed);
assert.equal(isDisplayed, true, "Passed");
}
})
Error:
Timeout of 100000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
it('should see product and version selected', (done) => {
browser.url('//some url');
browser.maximizeWindow();
browser.waitUntil(() => {
return $(ProductPage.productSelector()).isDisplayed()
}, 100000, 'expected page is loaded');
let productSelector = ProductPage.otherProductSelector();
let isEnabled = productSelector.isEnabled();
if(isEnabled == true){
const spanEle = $('//span[contains(text(),"text")]');
isDisplayed = spanEle.isDisplayed();
console.log(isDisplayed);
assert.equal(isDisplayed, true, "Passed");
}
done();
})
Only thing i can think of is that done was not passed in for the test call back at
it('should see product and version selected', (done) => {})
and then called at the very end. There isn't anything in your test that returns a promise.
Here I have removed browser.waitUntil(() => { .. } statement from the test and added different waits provided by the WebdriverIO. It seems there are some issues related to promise returning in this method was not able to resolve it by satifying promise or any other. I anyone knows please add a comment to this answer.
Here are more details with this: https://github.com/webdriverio/webdriverio/issues/2361
So what I have changed is as below:
it('should see product and version selected', () => {
browser.url('url');
browser.maximizeWindow();
let productSelector = $('#product-dropdown-toggle')
let isEnabled = productSelector.isEnabled();
if(isEnabled == true){
const spanEle = $('//span[contains(text(),"text")]');
isDisplayed = spanEle.isDisplayed();
console.log(isDisplayed);
assert.equal(isDisplayed, true, "Passed");
}
})
waitForElemenDisplayed(element,timeout){
element.waitForDisplayed(timeout);
}

Mocha .then(done) doesn't work as expected

This question is not about a problem which I can't solve, it is just a curiosity. I'm not very experienced with Mocha, but there's something interesting I've stumbled upon already.
What I want is to use done() to tell Mocha the promise has been resolved.
The following code DOESN'T work:
beforeEach((done) => {
user = new User({ name: 'Dummy' })
user.save()
.then(done)
})
I know I'm passing the result of the user.save() promise to done, but I think it shouldn't be a problem.
Instead this other code works:
beforeEach((done) => {
user = new User({ name: 'Dummy' })
user.save()
.then(() => done())
})
It seems to me that Mocha done() has some kind of control flow which leads to: Error: done() invoked with non-Error: {"_id":"5b65b9d2669f7b2ec0a3d503","name":"Dummy","__v":0}
Is it because done() wants strictly an error as its argument?
Why done() does even care about what I pass to it?
Can you make some example showing why done() argument to be an Error is useful?
Thanks in advance ;)
It is because done() in Mocha only accepts Error argument. In your case, your save() method returns json object not an Error ie new Error('failed save').
If we take a look at mocha test file, we can see that it won't accept other type of arguments.
// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L358
describe('when done() is invoked with a string', function () {
it('should invoke the callback', function (done) {
var test = new Runnable('foo', function (done) {
done('Test error'); // specify done with string/text argument
});
test.run(function (err) {
assert(err.message === 'done() invoked with non-Error: Test error');
done();
});
});
});
But if we see the test when the argument is Error, it works
// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L345
describe('when an error is passed', function () {
it('should invoke the callback', function (done) {
var test = new Runnable('foo', function (done) {
done(new Error('fail'));
});
test.run(function (err) {
assert(err.message === 'fail');
done();
});
});
});
Btw, I suggest that you avoid using done since mocha supports promise by specifying return statement. So, we change the code into
beforeEach(() => {
user = new User({ name: 'Dummy' })
return user.save().then(user => {
// antyhing todo with user
});
});
Hope it helps.

mocha tests Is it possible to reuse the same before() and after() hooks in all my tests?

I use the same before() and after() root level hooks in all my tests to setup and clear my test-database ...
Is there any way to move them into a file and export/import that file ?
Yes. I was able to achieve this behavior by taking advantage of mocha's this context, discussed in their Wiki article about shared behaviors. I am using ts-mocha which accounts for the async/await functionality.
So I wrote functions to login and logout using supertest-session and it looks something like this:
export function authHooks()
{
const email = UsersSeed[0].email;
const password = UsersSeed[0].password;
before(`login ${email}`, async function()
{
await this.session.post('/api/account/login')
.send({ email, password })
.expect(201);
});
after(`logout ${email}`, async function()
{
await this.session.get('/api/account/logout')
.expect(200);
});
}
Inside of my describe I set up the this.session and in my it-statements I can reuse it. It looks a little like this:
import { expect } from 'chai';
import * as Session from 'supertest-session';
import { authHooks } from './authHooks';
describe('Some Suite', () =>
{
before(function()
{
this.session = new Session(SomeApp);
});
after(function()
{
this.session.destroy();
});
describe('when not authenticated', () =>
{
it('returns 403', async function()
{
await this.session.get('/api/jobs')
.expect(403)
.expect({ statusCode: 403, message: 'Forbidden resource' });
});
});
describe('when authenticated', () =>
{
authHooks();
describe('when finding jobs', () =>
{
it('returns all jobs', async function()
{
await this.session.get('/api/jobs')
.expect(200)
.then((response) =>
{
expect(response.body).to.deep.eq(SomeThing);
});
});
});
});
});
I'm not sure if this is the best way to achieve it (I'm not a fan of using function over () => {} personally), but I have confirmed it works.
The above code will not run mainly because I'm protecting code specifics, but hopefully this will provide at least one option for you and maybe someone else can show a better way to do this.

Back-end tests with elasticsearch fails without setTimeout

I am writing tests for back-end which uses MongoDB and Elasticsearch. The problem is that without wrapping test with setTimeout test fails, and it looks like elasticsearch can't index mock data into db before test. Here is the code:
let elasticSearch = require('elasticsearch');
let elasticClient = new elasticSearch.Client({
host: 'localhost:9200'
});
let app = require('./dist/app'); //path to my application
let supertest = require('supertest');
before((done) => {
elasticClient.index(elasticMockData, function() {
done();
});
});
beforeEach(() => {
request = supertest(app);
});
it('should get data from elastic', () => {
setTimeout(() => { // if I comment this timeout, test will fail
request.get('/api/elastic')
.end((err, res) => {
expect(res.body.hits.hits.length).not.to.equal(0);
})
}, 1000); // if I comment this timeout, test will fail
});
I think you will agree that timeout is not an elegant and nice solution, which slows every test to 1 second or more. Maybe, am I missing something?
Found a solution, maybe it will be useful for someone.
According to Elasticsearch docs:
By default, the document will be available for get() actions immediately, but will only be available for searching after an index refresh (which can happen automatically or manually).
So, in this case, done() should be called within another callback function:
before((done) => {
elasticClient.index(elasticMockData, function() {
elasticClient.indices.refresh(function (err: any, res: any) {
if (err) {
return;
}
done();
});
});
});

How to test redux-thunk middleware async functions?

I'm trying to test my asyn thunk middleware function using mocha, chai and sinon (my first time!).
Please consider my files:
ayncActionCreators.js
export const fetchCurrentUser = () => {
return (dispatch) => {
setTimeout(dispatch, 100);
}
};
ayncActionCreators.spec.js
//...
it('Should work', () => {
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch);
expect(dispatch.called).to.be.true;
});
I did not yet implement the fetchCurrentUser function - just assumed it will take some "server" time and then it will call 'dispatch()'.
The spec fails, due to the async flow. If I add a setTimeout of 101 ms before the expect - it passes.
My code will use some DB API that returns promise, so the async function will eventually look like:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
So I tried to require dbAPI and create a sinon.stub().returns(Promise.resolve()) inside the test and it didn't work as well (I thought that since the stub returns a resolved promise - the async function will act like a synchronous function).
Any ideas how should I test async functions like that?
Thank,
Amit.
Don't mock dispatch with sinon, write your own and call Mocha's done() in that when it's done.
it('Should work', (done) => {
const dispatch = () => {
// Do your tests here
done();
};
const action = fetchCurrentUser();
action(dispatch)
// Also allow quick failures if your promise fails
.catch(done);
})
If you're just wanting to ensure that the dispatch is called, then mocha will time out. The catch on the returned promise from your async action creator allows errors to be shown in the right place and for the test to fail rather than time out.
Well, I think I've found a solution:
Assuming my async function looks like this:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
Then I can write the spec as follows:
it('Should work', () => {
dbAPI.fetchUser = sinon.stub().returns(Promise.resolve({username: 'John'}));
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch).then(() => {
expect(dispatch.called).to.be.true;
});
});
I don't know if this is a workaround or not, but it works. I would appreciate your opinions of a better way of doing this...
Thanks,
Amit.

Resources