For what reason(s) could this code fail (no element found)...
element(by.id('loginButton')).click(); // triggers route change
browser.wait(element(by.tagName('myComponent')).isPresent(), 10000, 'timeout');
element(by.tagName('myComponent')).click();
...while this code works ?
element(by.id('loginButton')).click(); // triggers route change
const eC = protractor.ExpectedConditions;
browser.wait(eC.visibilityOf(element(by.tagName('myComponent'))), 10000, 'timeout');
element(by.tagName('myComponent')).click();
I'm working with Angular 5.2.5, Protractor 5.3.0 and Jasmine 2.8.0.
May be related: I could also have asked why I need to add a browser.wait()
while element(by())
is supposed to be automatically added in the ControlFlow by Protractor, but there are already lots of related questions (here, here, there, there,...), with no clear answer unfortunately.
There is a not-so obvious difference between the two . But the webdriver docs are clear about this.
eC.visibilityOf(...)
- Returns a function. browser.wait() repeatedly evaluates functions until they return true.
isPresent()
- Returns a promise. browser.wait() does not / cannot repeatedly evalute promises(!) browser.wait() will continue immediately when the promise resolves , regardless of whether it returns true or false.
If you want to use isPresent() you can wrap it in a function. This allows webdriver to call it over and over.
browser.wait(() => element(by.tagName('myComponent')).isPresent(), 10000, 'timeout');
Works exactly as you expect.
The two statements are not equivalent as such. I created a simple page like below
<html>
<body>
<div id="first_name">Tarun</div>
<script type="text/javascript">
var div = document.createElement('div');
div.innerText = 'lalwani';
div.id = 'last_name';
setTimeout( () => document.body.appendChild(div), 3000);
</script>
</body>
</html>
And a simple test like below
describe('angularjs homepage todo list', function() {
it('should add a todo', async function() {
browser.waitForAngularEnabled(false);
browser.get('http://0.0.0.0:8000');
const eC = protractor.ExpectedConditions;
browser.wait(element(by.id('last_name')).isPresent(), 10000, 'timeout');
});
});
When you run you will find the output is
Started
...
1 spec, 0 failures
Finished in 0.617 seconds
Now if you change the code to
describe('angularjs homepage todo list', function() {
it('should add a todo', async function() {
browser.waitForAngularEnabled(false);
browser.get('http://0.0.0.0:8000');
const eC = protractor.ExpectedConditions;
browser.wait(eC.visibilityOf(element(by.id('last_name'))), 10000, 'timeout');
});
});
The output of the same is below
Started
...
1 spec, 0 failures
Finished in 3.398 seconds
As you can see the visibilityOf
actually waited for the object to appear while the previous one didn't.
This is because the controlFlow will make isPresent
get executed and return the promise returning value of true/false to the wait. While visibilityOf
will return a function that the wait
can check by calling again and again.
You can verify this by adding below in the test
console.log(typeof eC.visibilityOf(element(by.id('last_name'))))
console.log(typeof element(by.id('last_name')))
The output of same is
function
object
So the assumption your below two statements are same is wrong and that is why you don't get the correct results with the first one
browser.wait(element(by.tagName('myComponent')).isPresent(), 10000, 'timeout');
browser.wait(eC.visibilityOf(element(by.tagName('myComponent'))), 10000, 'timeout');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With