My Protractor e2e tests are inconsistently passing and failing.
It seems this could be due to asynchronous javascript, as discussed here: Protractor : How to wait for page complete after click a button?.
However, here it's mentioned that Protractor tests automatically execute sequentially / synchronously: https://github.com/angular/protractor/issues/909
My test script:
describe('Login', function() {
var ptor;
beforeEach(function() {
browser.get('https://127.0.0.1:8443');
ptor = protractor.getInstance();
element(by.id('splash')).click();
browser.ignoreSynchronization = true; // <-- to proceed beyond splash screen
});
describe('with correct email and password', function() {
beforeEach(function() {
element(by.id('email')).sendKeys('admin@email.com');
element(by.id('password')).sendKeys('adminpassword');
element(by.id('loginButton')).click();
});
afterEach(function() {
ptor.findElement(by.id('logout')).then(function(elem) {
elem.click();
});
});
it('does not show alert', function() { // <-- sometimes passes, sometimes fails
expect(browser.isElementPresent(by.css('.alert-danger'))).toBe(false);
});
it('changes route to /admin', function() { // <-- sometimes passes, sometimes fails
expect(browser.getCurrentUrl()).toMatch(/\/admin/);
});
});
});
In the two tests above, either both tests will pass, or one/both of the tests will fail with these messages:
Failures:
1) Login with correct email and password does not show alert
Message:
NoSuchElementError: no such element
...
==== async task ====
WebDriver.findElement(By.id("logout"))
...
or
Failures:
1) Login with correct email and password changes route to /admin
Message:
NoSuchElementError: no such element
...
==== async task ====
WebDriver.findElement(By.id("logout"))
...
Thoughts / help much appreciated.
browser.ignoreSynchronization = true; has a global effect for all your tests. you may have to set it back to false, so protractor waits for angular to be finished rendering the page. e.g. in or before your second beforeEach function
I was able to resolve the issue based on the following:
Avishay's answer here about adding ptor.waitForAngular():
No element found using locator: by.model() error
Changing browser.get to ptor.get, as in Harri Siirak's answer here:
Protractor times out waiting for sync with page when using $resource
juliemr's comment here about ignoreSynchronization being an instance variable, and changing browser.ignoreSynchronization=true to ptor.ignoreSynchronization=true:
https://github.com/angular/protractor/issues/49
glepretre's answer here about using .then():
Protractor : How to wait for page complete after click a button?
As mentioned by Nguyen Vu Hoang's comment to the original question, I am testing a pure Angular app with what I think is pure Protractor (no webdriver calls). I know ptor.ignoreSynchronization=true should not be required in this case, but for some reason, the tests are not proceeding at button click without this setting.
My new spec:
There is also an another technique to make your tests more stable: Explicit Waits and Expected Conditions (docs).
I've found using Expected Conditions especially useful when testing against non-angular pages or angular applications that have a lot of animations involved.
For example, you can wait for an element to be clickable before making a click:
There are also other built-in Expected Conditions, such as:
presenseOf()
visibilityOf()
alertIsPresent()
textToBePresentInElementValue()
And, it is easy to write a custom Expected Condition, example use case:
You can also combine Expected Conditions using
and
,or
andnot
, e.g.: