"Failed: Error while waiting for Protractor to sync with the page" while executing Protractor tests - javascript

I try to execute some Protractor tests on a web application that consists of both Angular and non-angular components.
My code looks like so:
describe("Test Name", function() {
it("Test case", function() {
// first execute steps on a non-Angular component
browser.waitForAngularEnabled(false);
// some test steps
// then execute tests on an Angular component, which opens in a new browser tab
browser.waitForAngularEnabled(true);
// some more test steps
});
});
The problem is that after the above test is run, the browser launches and immedietaly closes with the following error:
Failed: Error while waiting for Protractor to sync with the page: "both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test
involves client-side navigation, which can interfere with Protractor's bootstrapping. See https://github.com/angular/protractor/issues/2643 for details"
When I remove browser.waitForAngularEnabled(true); from the code, the steps for the non-Angular component are executed successfully, then the Angular component of the application is opened in the new browser tab, nothing happens for 10 seconds (no steps are executed) and the browser closes with the following error:
Failed: Wait timed out after 10007ms

You should probably account for asynchronous code and wait for promises to resolve. Also, add Jasmine's done parameter to the test function to let selenium know when the test is finished.
Another thing that might cause this is activating waitForAngularEnabled before you're actually in an angular page. I suggest you prefix that call with a call to check that something on the page already got loaded so you know angular is ready to be hooked by protractor before waiting for angular activities.
It's important to note that protractor waits for the next action after waitForAngularEnabled(true) to trigger the check, relying on that might make the problem unclear if sometime later someone changes the code.
describe("Test Name", function() {
it("Test case", function(done) {
// first execute steps on a non-Angular component
browser.waitForAngularEnabled(false)
.then(() => /* step1 */)
.then(() => /* step2 */)
// ...
// 👇 this one is very important to make sure
// we're in an angular page 👇
.then(() => ensurePageTitleIsVisible())
.then(() => browser.waitForAngularEnabled(true))
.then(() => done())
.catch((err) => done.fail(err));
});
});
function ensurePageTitleIsVisible() {
return browser.wait(ExpectedConditions.visibilityOf(PAGE_TITLE_SELECTOR), jasmine.DEFAULT_TIMEOUT_INTERVAL, 'Title does not exist after timeout');
}
This might give you a better error message as well.
and of course, you can do the same with async \ await syntax.
describe("Test Name", function() {
it("Test case", function(done) {
try {
// first execute steps on a non-Angular component
await browser.waitForAngularEnabled(false)
await step1();
await step2();
// ...
await browser.waitForAngularEnabled(true);
done();
} catch(err) {
done.fail(err);
}
});
});
Basically, your problem happens because you continue with the test steps before the browser.waitForAngularEnabled function actually finishes.

use browser.ignoreSynchronization = true; when interacting with non angular ui since it makes protractor not to wait for Angular promises
and browser.ignoreSynchronization = false; followed by browser.waitForAngular(); when interacting with angular ui

Related

How can I run tests in sequential order with Mocha?

I am using Mocha and Chai to test my async js code.
I need to wait for previous tests to complete before starting the next test.
ex] create account -> update account -> delete account
Here is a simplified version of the test code:
describe('Account Tests', function() {
this.timeout(30000);
// I want to run this 1st
it('should create account', async function() {
let account = await api.acount.create();
expect(account).not.to.be.null;
})
// I want to run this 2nd
it('should update account', async function() {
let accountUpdate = await api.account.update();
expect(accountUpdate.status).to.equal(204);
})
// I want to run this last
it('should delete account', async function() {
let result = await api.account.remove();
expect(result).to.be.true;
})
})
Since I am using promises with async & await, the promise is inherently returned to 'it'
The problem I am encountering is sometimes the account is created then deleted before the update test can run. So, the update test fails while the create & delete tests pass. Sometimes the delete test tries to run before the create test is finished and so fails. I know I can add a sleep in between these tests, but I don't want to use a 'hack' when there is a real solution.
I'm new using Mocha and Chai, and I must be missing something here, but shouldn't the promise make the creating an account test wait until that is finished before running the update test?

Why do I keep facing a Mocha "timeout error"; Also node keeps telling me to resolve my promise?

I keep getting a timeout error, it keeps telling me to enusre I have called done(), even though I have.
const mocha = require('mocha');
const assert = require('assert');
const Student = require('../models/student.js');
describe('CRUD Tests',function(){
it('Create Record',function(done){
var s = new Student({
name: "Yash"
});
s.save().then(function(){
assert(s.isNew === false);
done();
});
});
});
Result is -
CRUD Tests
1) Create Record
0 passing (2s) 1 failing
1) CRUD Tests
Create Record:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it
resolves.
(/home/yash/Documents/Development/Node/MongoCRUD/test/CRUD_test.js)
Note that as written, your unit test ignores the fact that save() might reject instead of resolving. Whenever you use this done construct, make sure your unit test handles an error scenario, like this:
s.save().then(function() {
assert(s.isNew === false);
done();
}).catch(error => {
done(error);
});
Alternatively, since Mocha has built-in support for promises, you can remove the done parameter and return the promise directly, like this:
it('Create Record', function() {
// ...
return s.save().then(function() {
assert(s.isNew === false);
});
});
The advantage with this approach is a reject promise will automatically fail the test, and you don't need any done() calls.
I guess that your mocha runs without being connected to your database. So .save() is waiting for a connection which it never get and your mocha timeout.
You can initialize your software system before to run any Mocha test.
For example, connect a database.
// ROOT HOOK Executed before the test run
before(async () => {
// connect to the database here
});
// ROOT HOOK Excuted after every tests finished
after(async () => {
// Disconnect from the database here
});

Jest unit testing - Async tests failing Timeout

I got the following error message "Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL." On top of that, I also received an error message stating that 0 assertions were executed while expecting 2 assertions.
I've tried extending the timeout to 10 seconds using jest.setTimeout(10000), which should be more than sufficient time to execute that code, but the problem persisted.
I know m.employeeGetAll() works because when I test my web app using the browser, I can see the list of employees in the view.
Here's how my test looks like
it('Lists all employees successfully', () => {
expect.assertions(2);
return m.employeeGetAll().then(result => { //m.employeeGetAll() returns a promise
expect(result).toBeDefined();
expect(result.length).toBe(3);
});
});
The problem I've discovered, was the way async code works.
What cannot be seen in the code snippet was the call to mongoose.connection.close(); at the very end of my test file.
This call must be done inside afterEach() or afterAll() function for Jest unit testing framework. Otherwise, the connection to the database will be closed before the tests could complete since all of the calls in my controller methods are asynchronous; This leads to no promise ever being returned and the code goes into timeout.
Since I'm using beforeAll() and afterAll(), to load data from database once before the start of all tests and to clear the database at the end of all tests, I've included the call to connect to DB using mongoose inside beforeAll() as well.
Hope this helps someone who's also stuck in my situation.
with async you have to call done
it('Lists all employees successfully', (done) => {
expect.assertions(2);
return m.employeeGetAll().then(result => { //m.employeeGetAll() returns a promise
expect(result).toBeDefined();
expect(result.length).toBe(3);
done();
});
});

How can I bypass the redirection in Protractor

I use Angular 2 and I am writing Protractor tests. My problem is that when user puts the username and the password and click the login button page redirects to a middle page and that middle page redirects to another page that gives and validate the JWT (after login button user doesn't need to do anything till the page reaches to the dashboard) but protractor cannot do the redirection. Is there a way to put Protractor in sleep till I reach out the dashboard? or is there a way that you can suggest?
browser.sleep(10000) didn't work. Because as browser sleeps protractor stays on the login page till it fail.
Error message:
Expected Function to equal 'http://localhost:4200'.
Expected :"http://localhost:4200"
Actual :{}
You need to use .then on every promise or else promises will resolve after all the synchronous tasks are complete.
browser.sleep(10000).then(() => {
browser.getCurrentUrl().then(url => {
expect(url).toEqual('http://localhost:4200');
});
})
Ideally, you want to use browser.wait() to wait until the url is as expected before moving on. This way, it won't wait 10000ms, but it will complete the wait right when the url matches.
let timeout = 10000;
browser.wait(() => {
return browser.getCurrentUrl().then(url => {
return url === 'http://localhost:4200';
});
}, timeout).thenCatch(err => {
throw err;
});
Of course, this is just speculation on what you haven't done/need to do since you need to post your code.
Edit: Further explaination. If you run this:
console.log('Got here 1');
browser.sleep(0).then(() => {
console.log('Got here 2');
]);
console.log('Got here 3');
You would probably expect the output to be:
Got here 1
Got here 2
Got here 3
But the output would actually be:
Got here 1
Got here 3
Got here 2
Because "promises will resolve after all the synchronous tasks are complete"

Async Mocha: `done` called, but next test never runs

I have an unconventional setup I can't change. It looks something like this:
test POSTs to server
server POSTs to blockchain
blockchain updates
syncing script updates the database
It is absolutely imperative that I do not run the next test until the test before it has completed that entire workflow, which typically takes 2-3 seconds. Here is an example of a test written for that flow with supertest and chai:
it('should create a user', done => {
request(server)
.post(`${API}/signup`)
.set('Content-Type', 'application/json')
.send(`{
"email":"${USER_EMAIL}",
"password":"${USER_PASSWORD}"
}`)
.expect(200)
.expect(res => {
expect(res.body.role).to.equal('user');
expect(res.body.id).to.match(ID_PATTERN);
})
.end(_wait(done));
});
That _wait function is the key issue here. If I write it very naively with a setTimeout, it will work:
const _wait = cb => () => setTimeout(cb, 5000);
However, this isn't a great solution since the blockchain is very unpredictable, and can sometimes take much more than 2-3 seconds. What would be much better is to watch the database for changes. Thankfully the database is written in Rethink, which provides cursor objects that update on a change. So that should be easy, and look something like this:
var _wait = cb => () => {
connector.exec(db => db.table('chain_info').changes())
.then(cursor => {
cursor.each((err, change) => {
cb(err);
return false;
});
});
};
This setup breaks the tests. As near as I can tell done does get called. Any console logs in and around it fire, and the test itself is logged as completed, but the next test never starts, and eventually everything times out:
Manager API Workflow:
Account Creation:
✓ should create a user (6335ms)
1) should login an administrator
1 passing (1m)
1 failing
1) Manager API Workflow: Account Creation: should login an administrator:
Error: timeout of 60000ms exceeded. Ensure the done() callback is being called in this test.
Any assistance would be greatly appreciated. I am using Mocha 3.1.2, Chai 3.5.0, Supertest 2.0.1, and Node 6.9.1.

Categories