What is browser.ignoreSynchronization in protractor?
JavascriptAngularjsTestingProtractorEnd to-EndJavascript Problem Overview
I have seen it so many times where people suggest to use:
browser.ignoreSynchronization=true; // or false
But I do not understand why do we need it?
Javascript Solutions
Solution 1 - Javascript
The simple answer is that it makes protractor not wait for Angular promises, such as those from $http
or $timeout
to resolve, which you might want to do if you're testing behaviour during $http
or $timeout
(e.g., a "loading" message), or testing non-Angular sites or pages, such as a separate login page.
For example, to test a button that sets a loading message during a request you can set it to true
when fetching an element + checking its contents
element(by.css('button[type="submit"]')).click();
browser.ignoreSynchronization = true;
expect(element(by.css('.message')).getText().toBe('Loading...');
browser.ignoreSynchronization = false;
expect(element(by.css('.message')).getText().toBe('Loaded');
A more involved answer is that setting it to true
means that subsequent additions/injections to the control flow don't also add browser.waitForAngular
. There are cases when an understanding of the control flow, and when/how things are added/injected into it is important. For example if you're using browser.wait
to test a multi-stage process, the function passed to wait
is injected into to the control flow after the rest of the functions in the test have added to the control flow.
element(by.css('button[type="submit"]')).click();
browser.ignoreSynchronization = true;
expect(element(by.css('.message')).getText().toBe('Stage 1');
browser.wait(function () {
// This function is added to the control flow after the final
// browser.ignoreSynchronization = false in the test
// so we need to set it again here
browser.ignoreSynchronization = true;
return element(by.cssContainingText('.message', 'Stage 2')).isPresent().then(function(isPresent) {
// Cleanup so later tests have the default value of false
browser.ignoreSynchronization = false;
return !isPresent;
});
});
expect(element(by.css('.message')).getText().toBe('Stage 2');
browser.ignoreSynchronization = false;
expect(element(by.css('.message')).getText().toBe('Stage 3');
An alternative to using browser.ignoreSynchronization
is to access the standard webdriver API directly
element(by.css('button[type="submit"]')).click();
expect(browser.driver.findElement(by.css('.message')).getText().toBe('Loading...');
expect(element(by.css('.message')).getText().toBe('Loaded');
Using the driver methods directly to find the elements means that the system will try to find them without waiting for any ongoing $http
requests to finish, much like setting browser.ignoreSynchronization = true
.
Solution 2 - Javascript
This setting controls whether protractor should wait for angular on a page or not. It is not properly documented, but here is the documentation string from the code:
/**
* If true, Protractor will not attempt to synchronize with the page before
* performing actions. This can be harmful because Protractor will not wait
* until $timeouts and $http calls have been processed, which can cause
* tests to become flaky. This should be used only when necessary, such as
* when a page continuously polls an API using $timeout.
*
* @type {boolean}
*/
In other words, if you are testing against a non-angular site - set ignoreSynchronization
setting to true
. As a real world example, see one of the challenges I had while opening a non-angular page from an angular page: https://stackoverflow.com/questions/28511013/non-angular-page-opened-after-a-click.
Solution 3 - Javascript
2021 answer
browser.ignoreSynchronization
is nothing these days. Literally
This command has been deprecated on Jan 25, 2018 when protractor v5.3.0
was released
Instead browser.waitForAngularEnabled()
should be used
But what it does and what ignoreSynchronization
used to do, it enables Protractor's built-in handling for waiting of angular applications. Imagine, you click login button, and you don't need to use 'sleep for 10 seconds' command, or 'wait until loading animation is gone' etc. All of that should in theory be handled by protractor out of the box
But in reality, there are too many edge cases when you can't rely on this, and have to disable this feature, because it makes the script to hang. And this is when await browser.waitForAngularEnabled(false)
comes into play. Or await browser.waitForAngularEnabled(true)
for enabling it back on
Read how it can be used