ExpectedConditions.invisibilityOf cannot reliably be used to wait for an element to be removed from the DOM #3777
Description
Protractor build 4.0.11
invisibilityOf states the following in the API documentation:
An expectation for checking that an element is either invisible or not present on the DOM. This is the opposite of 'visibilityOf'
Please see the following stack trace that we get intermittently from our build server when using invisibilityOf with browser.wait to wait for an element to be removed from the DOM:
NoSuchElementError: No element found using locator: By(css selector, .new-position-modal)
at WebDriverError (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\error.js:27:5)
at NoSuchElementError (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\error.js:242:5)
at C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\element.js:698:27
at ManagedPromise.invokeCallback_ (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:1379:14)
at TaskQueue.execute_ (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:2913:14)
at TaskQueue.executeNext_ (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:2896:21)
at asyncRun (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:2775:27)
at C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:639:7
at process._tickCallback (internal/process/next_tick.js:103:7)Error
at ElementArrayFinder.applyAction_ (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\element.js:395:27)
at ElementArrayFinder._this.(anonymous function) [as isDisplayed] (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\element.js:97:30)
at ElementFinder._this.(anonymous function) [as isDisplayed] (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\element.js:721:22)
at C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\expectedConditions.js:86:20
at C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\expectedConditions.js:88:72
at ManagedPromise.invokeCallback_ (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:1379:14)
at TaskQueue.execute_ (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:2913:14)
at TaskQueue.executeNext_ (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:2896:21)
at asyncRun (C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:2775:27)
at C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\selenium-webdriver\lib\promise.js:639:7
The specific lines I would like to draw attention to are:
at C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\expectedConditions.js:86:20
at C:\BuildAgent\work\5d4c0dd4e428c81b\node_modules\protractor\built\expectedConditions.js:88:72
The call stack indicates that the error is being thrown when evaluating elementFinder.isDisplayed.bind(elementFinder)
in the following line of code:
return this.and(this.presenceOf(elementFinder), elementFinder.isDisplayed.bind(elementFinder));
I believe the reason this happened is that the element was removed from the DOM between the presenceOf(elementFinder)
and elementFinder.isDisplayed.bind(elementFinder)
I have since changed all our browser.wait statements where we were using invisibilityOf to wait for an element to be removed from the DOM to use stalenessOf instead. The problem has not reoccurred.
My suggestion is to update the API documentation as per this PR https://github.com/angular/protractor/pull/3775/files as I believe this might be easier than rewriting this check to be "atomic".