Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

ExpectedConditions.invisibilityOf cannot reliably be used to wait for an element to be removed from the DOM #3777

Closed
massimocode opened this issue Dec 1, 2016 · 3 comments

Comments

@massimocode
Copy link
Contributor

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".

@sjelin
Copy link
Contributor

sjelin commented Dec 1, 2016

We could actually probably solve this fairly easily by removing the presenceOf check, catching the error, and re-throwing if it's anything other than NoSuchElementError. I don't think doing anything atomically is possible, since the server isn't necessarily running on the same machine as you.

massimocode added a commit to massimocode/protractor that referenced this issue Dec 17, 2016
massimocode added a commit to massimocode/protractor that referenced this issue Dec 17, 2016
@heathkit heathkit self-assigned this Dec 22, 2016
@tilmanschweitzer
Copy link
Contributor

@massimocode @sjelin I have the same problem and wrote some tests to reproduce the problem.

https://github.com/tilmanpotthof/race-condition-in-expected-condition-visibility-of

I also added a workaround, which I use in a project that uses the promise error callback.

@tilmanschweitzer
Copy link
Contributor

@sjelin I opened a new PR with a test case the reproduces the bug and also a fix

#3958

heathkit pushed a commit that referenced this issue Jan 12, 2017
… a race condition (#3777)

Handle NoSuchElementError in the expected condition visibilityOf, which occurred when
an element disappears between the isPresent() and isDisplayed() check.
sjelin added a commit to sjelin/protractor that referenced this issue Jan 13, 2017
…lements

Expected conditions used `presenceOf` and `visibilityOf` to check that it's
referencing elements which actually exist on the page, but there is a race
condition with this strategy: an element could disappear after the
`presenceOf`/`visibilityOf` check but before other checks, causing an error
to be thrown.  This PR handles this race condition in two ways:

1. `ElementFinder`'s `isEnabled`, `isDisplayed`, and `isSelected` functions now
   return false if no such element exists, rahter than throwing an error
2. `ExpectedConditions`'s `textToBePresent` and `textToBePresentInElementValue`
   now check for errors and also return false in those cases

This is a general solution to the problem referenced in
angular#3777 and
angular#3958.
sjelin added a commit to sjelin/protractor that referenced this issue Jan 13, 2017
…lements

Expected conditions used `presenceOf` and `visibilityOf` to check that it's
referencing elements which actually exist on the page, but there is a race
condition with this strategy: an element could disappear after the
`presenceOf`/`visibilityOf` check but before other checks, causing an error
to be thrown.  This PR handles this race condition in two ways:

1. `ElementFinder`'s `isEnabled`, `isDisplayed`, and `isSelected` functions now
   return false if no such element exists, rahter than throwing an error
2. `ExpectedConditions`'s `textToBePresent` and `textToBePresentInElementValue`
   now check for errors and also return false in those cases

This is a general solution to the problem referenced in
angular#3777 and
angular#3958.
heathkit pushed a commit that referenced this issue Jan 27, 2017
…ibility (#4006)

Add test cases to reproduce the missing element race conditions possible in
expected condition methods `visibilityOf`, `textToBePresentInElement`,
`textToBePresentInValue` and `elementToBeClickable`.

Add error handler `falseIfMissing` to all expected conditions that depend
on the presence of an element.

Expected conditions check the presence of an element before other checks,
but when an element is removed exactly in the moment after the `isPresent`
and before `isDisplayed` in `visibilityOf` the condition used to fail.

This solution does not handle missing elements in (`isEnable`, `isDisplayed`, `isSelected`) and focused only on expected conditions (see
#3972)

This problem was also referenced in
#3578 and
#3777
igniteram pushed a commit to igniteram/protractor that referenced this issue Feb 21, 2017
… a race condition (angular#3777)

Handle NoSuchElementError in the expected condition visibilityOf, which occurred when
an element disappears between the isPresent() and isDisplayed() check.
igniteram pushed a commit to igniteram/protractor that referenced this issue Feb 21, 2017
…ibility (angular#4006)

Add test cases to reproduce the missing element race conditions possible in
expected condition methods `visibilityOf`, `textToBePresentInElement`,
`textToBePresentInValue` and `elementToBeClickable`.

Add error handler `falseIfMissing` to all expected conditions that depend
on the presence of an element.

Expected conditions check the presence of an element before other checks,
but when an element is removed exactly in the moment after the `isPresent`
and before `isDisplayed` in `visibilityOf` the condition used to fail.

This solution does not handle missing elements in (`isEnable`, `isDisplayed`, `isSelected`) and focused only on expected conditions (see
angular#3972)

This problem was also referenced in
angular#3578 and
angular#3777
bodyduardU pushed a commit to bodyduardU/protractor that referenced this issue Dec 5, 2022
…ibility (#4006)

Add test cases to reproduce the missing element race conditions possible in
expected condition methods `visibilityOf`, `textToBePresentInElement`,
`textToBePresentInValue` and `elementToBeClickable`.

Add error handler `falseIfMissing` to all expected conditions that depend
on the presence of an element.

Expected conditions check the presence of an element before other checks,
but when an element is removed exactly in the moment after the `isPresent`
and before `isDisplayed` in `visibilityOf` the condition used to fail.

This solution does not handle missing elements in (`isEnable`, `isDisplayed`, `isSelected`) and focused only on expected conditions (see
angular/protractor#3972)

This problem was also referenced in
angular/protractor#3578 and
angular/protractor#3777
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants