Protractor: browser.element(locator) not find element which dynamically added into dom

Created on 25 Jul 2018  路  15Comments  路  Source: angular/protractor

Hi there!
I have a case where some html elements are being added to DOM when some actions are made so when protractor trying to find those newly added elements during the execution it failed to locate.
I am using browser.element(ele) which is not working but browser.driver.findElement(locator) is working but browser.driver.findElement() gives WebElement, i need to convert to protractor.element for further verifications.
How do i proceed? Any help would be greatly appreciated.

Most helpful comment

is this thread still open?
ok so Im completelly lost atm.

Angular 6, Protractor 5.4.0, Jasmine 2.99.1

The page structure:

< body > <app-root> <div class="app-container"> <app-loader class="global-loader"> </app-loader> </div> </app-root> <!-- CONDITIONAL TOAST --> <div id="toast-container"></div> < /body >

(had to add the extra space in < body > or it would simply render as actual html) ^^

The issue:

Load site -> submit login form -> wait for next page to render.
Next page renders -> spends time loading -> injects toast into DOM if error.

regardless if the toast is displayed/injected into DOM or not this is the results.

protractor.ExpectedConditions.invisibilityOf(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.visibilityOf(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.presenceOf(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.elementToBeClickable(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.stalenessOf(element(by.css('#toast-container'))) = true
element(by.css('#toast-container')).isPresent() = false
element(by.css('#toast-container')).isDisplayed() = No element found using locator: ...
browser.driver.findElement(by.css('#toast-container')).isDisplayed(); = no such element
browser.findElement(by.css('#toast-container')).isDisplayed(); = No element found using locator

wrapping every method in browser.wait doesnt change anything.
browser.ignoreSynchronization = true; Assertion() -> browser.ignoreSynchronization = false; does nothing.
Any amount of browser waiting/sleeping doesnt change anything.
the loader displays as an overlay taking 100% of height and width. Removing the loader entirelly doesnt change anything either.
The exact same applies using by.xpath or any other viable selector.

any help would be greatly appreciated.

All 15 comments

Hi, @MuraliMolluru ! Please provide your config file and test example.

@IgorSasovets
I am using rootElement: 'body' in protractor config, during test execution there was a popover to be shown when mouse click on a button. This popover added to html dom only when button clicked and then protractor should check the popover as a verification. Now when this popover(div) added to html dom i was checking expect(element(by.css('div.scs-notifications-popover'))).isDisplayed()
here i am getting No element found using locator: By(css selector, div.scs-notifications-popover)
but when i use browser.driver.findElement(by.css('div.scs-notifications-popover')) i could able to find the actual element.

Please check the screenshot where the new div element added to html dom during test execution.
snip20180726_1

Try to use isPresent function

isPresent is giving false but when i check in developer tools i can see the element as shown in screenshot.

Then please provide test example with link to the app if it possible. It'll be more effective way to solve your issue.

+1 here @IgorSasovets @MuraliMolluru
Not sure if this got fixed - seeing the same thing.
Working on a toast element in an Angular page, dynamically added to the page after some successful operation.

Using pure element(by.css('.my-class') does not find it - even with changed (increased showing timing). But using browser.driver.findElement(by.css('.my-class') finds it (also another hint that the selector is fine).

Hi, @MuraliMolluru ! I have similar experience and managed to successfully handle this case using protractor. Could you please provide application example (that uses toasts). Maybe I could help you to deal with it.

@IgorSasovets The case is to create a user in an angular page. Once it is saved, it gets rendered in a div container in the page - the notification element is just some set of texts (in paragraphs and headers). It stays there for some seconds and vanishes.

If I increase the time, it still can't find it with element(by.css()) . Even with a reduced time, browser.driver.findElement gets it correctly (so the selectors are fine, and it is not a time issue).
For other page elements it is grand - so wondering if this is related to the fact that this element is dynamically added to the page

@YuriBarssi , I meant link to test app with similar behavior as this one. There is button "Show snack-bar" and when you click on it, toast message will appear in the bottom of the page. Try to write test for mentioned flow and please notify about the results. Or provide link to the app with similar to your case behavior.

@IgorSasovets I have other tests running for the same type of elements and they run well when the element does not have a time to vanish. Also, this particular element shows behind a spinner layer, a slideout and some other elements. So I think this was adding complexity to it.
FYI - I could get around the issue in two ways.
The first was to use browser.driver.findElement instead of element from protractor.
The other one as use browser.ignoreSynchronization = true before running the method to find the toast - and turning it to false after it. So it was not waiting for all the promises in the spinner, loading the elements on the page nor waiting for angular in general. It did the job.

is this thread still open?
ok so Im completelly lost atm.

Angular 6, Protractor 5.4.0, Jasmine 2.99.1

The page structure:

< body > <app-root> <div class="app-container"> <app-loader class="global-loader"> </app-loader> </div> </app-root> <!-- CONDITIONAL TOAST --> <div id="toast-container"></div> < /body >

(had to add the extra space in < body > or it would simply render as actual html) ^^

The issue:

Load site -> submit login form -> wait for next page to render.
Next page renders -> spends time loading -> injects toast into DOM if error.

regardless if the toast is displayed/injected into DOM or not this is the results.

protractor.ExpectedConditions.invisibilityOf(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.visibilityOf(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.presenceOf(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.elementToBeClickable(element(by.css('#toast-container'))) = true
protractor.ExpectedConditions.stalenessOf(element(by.css('#toast-container'))) = true
element(by.css('#toast-container')).isPresent() = false
element(by.css('#toast-container')).isDisplayed() = No element found using locator: ...
browser.driver.findElement(by.css('#toast-container')).isDisplayed(); = no such element
browser.findElement(by.css('#toast-container')).isDisplayed(); = No element found using locator

wrapping every method in browser.wait doesnt change anything.
browser.ignoreSynchronization = true; Assertion() -> browser.ignoreSynchronization = false; does nothing.
Any amount of browser waiting/sleeping doesnt change anything.
the loader displays as an overlay taking 100% of height and width. Removing the loader entirelly doesnt change anything either.
The exact same applies using by.xpath or any other viable selector.

any help would be greatly appreciated.

I'm experiencing the exact same issue described by @YuriBarssi . As he suggested setting browser.ignoreSynchronization = true before the check does work, as this is deprecated I have been using waitForAngularEnabled(false) with success.

This is not desirable, because we lose the benefits on waitForAngularEnabled(true).

Is there any more information about this, is this an issue with protractor. Is there a better work around than simply waitForAngularEnabled(false). I've attempted using waitForAngularEnabled(true), however the majority of our app lies behind this problematic check.

I also tried to use browser.driver.findElement(by.css('.my-class') but I wasn't sure how to use this in conjunction with browser.wait. Do you have any example of this?

I believe this is happening due to events occurring outside of angular. In my scenario some UI changes are triggered by websocket messages occurring from an external package. I've tried using change detection and manually calling detectChanges() from my component, but this does not solve the problem.

try $('app-root').$('tagName or .(dot) className')

Same issue here not find element ngb-toast message which is dynamically added.

For anyone hitting this page via Google.

I had similar issues with Protractor being unable to find a random element on the page, which definitely existed.

As it turned out, the problem was caused by ngb-toast with autohide=true. This causes the toast to call setTimeout(), which, as we know, makes Protractor stop and wait until the timeout lapses:

Before performing any action, Protractor waits until there are no pending asynchronous tasks in your Angular application. This means that all timeouts and http requests are finished.

I resolved this by disabling autohiding during the e2e tests.

Was this page helpful?
0 / 5 - 0 ratings