"Element is not currently visible and so may not be interacted with" but another is?
Asked Answered
C

5

8

I've created another question which I think is the cause for this error: Why does the Selenium Firefox Driver consider my modal not displayed when the parent has overflow:hidden?

Selenium version 2.33.0
Firefox driver

The code that causes the error:

        System.Threading.Thread.Sleep(5000);
        var dimentions = driver.Manage().Window.Size;
        var field = driver.FindElement(By.Id("addEmployees-password")); //displayed is true
        field.Click(); //works fine
        var element = driver.FindElement(By.Id(buttonName)); //displayed is false
        element.Click(); //errors out

The button that its trying to click:

<div id="addEmployees" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="addEmployeesLabel" aria-hidden="true">

    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
        <h3>Add Employee</h3>
    </div>

    <div class="modal-body">
        <p class="alert alert-info">
            <input name="addEmployees-username" id="addEmployees-username" />
            <input name="addEmployees-password" id="addEmployees-password" type="password" />
            <input name="addEmployees-employee" id="addEmployees-employee" />
        </p>
    </div>

    <div class="modal-footer">
        <button name="addEmployees-add" id="addEmployees-add" type="button" class="btn" data-ng-click="submit()">Add</button>
    </div>

</div>
  • If I change the call to FindElements then I get ONE element, so there isn't anything else on the page.
  • If I FindElement on a field that occurs right before the button, say addEmployees-employee, then addEmployees-employee is displayed
  • In the browser itself, it shows up fine, all i need to do is actually click the button and the desired behavior executes, but the webdriver refuses to consider the element displayed

How is it that one field can be considered displayed and the other is not?

enter image description here

The modal with the add button in the bottom right, all the other elements are displayed = true

The window size is 1200x645 per driver.Manage().Window.Size;
The element location is: 800x355y per driver.FindElement(By.Id(buttonName)).Location
The element dimentions are: 51x30 per driver.FindElement(By.Id(buttonName)).Size
The password element location is: 552x233y per driver.FindElement(By.Id("addEmployees-password")).Size

Chilcote answered 11/7, 2013 at 19:58 Comment(13)
We use something similar to this: waitUntil(Waits.elementDisplayed(web element goes here)); here at work. Do you have a mechanism like that in your automation framework?Olathe
@Olathe the c# driver has implicit waits, which I have configured for 10 seconds, the thing is, the element that occurs right before it is marked as displayed, but the button is not, the kicker is that another modal that is the same but edit instead of add works fine!Chilcote
Are both elements always visible in the DOM when you look at it?Olathe
Umm.. I'm not sure what you mean by that, but they are visible on the browser viewport, and if I go into firebug, its not marked as hidden. Does that answer your question?Chilcote
Yes, that does. It means that they are present in the DOM (Document Object Model). It also means you should be able to see them with your code. Have you tried any other mechanism to locate them? Like by CSS (slow) or XPath (faster)?Olathe
I tried by name, and I was able to find it, the element is found, but the displayed property is false, whether by ID or by Name. The problem is selenium seems to think that the button is either not visible or off the viewport. Can you join a stackoverflow chat room?Chilcote
@ton.yeung: Could you debug a bit for location and size? Maybe also the browser viewport size. is it close the edge of the window?Jodhpur
This needs a bit more debugging. Q1: What about other browsers? Q2: Tried JS click? Q3: Tried click input first?Jodhpur
@user1177636 I've added the dimensions and a screenshot as requested, I have not tried 1 or 2, and not sure what 3 means?Chilcote
@ton.yeung: Maybe also post the dimension of addEmployees-password, however I don't think it matters in your case after seeing the screenshot. For Q3, I mean click one of the inputs first, e.g. addEmployees-password, then click button.Jodhpur
@user1177636 I've added the dimensions for the password field, and clicked as well as send keys to it, and still the button is displayed = falseChilcote
@ton.yeung: Yes, if it works fine on other browsers, yet another mysterious case for Firefox. Try JS click or Actions class click (which I doubt it's gonna work though)Jodhpur
@user1177636 One thing that Brian hinted at was that the modal is divided into 3 different divs, I tried moving the button up, and it works! Funny thing is, that a different modal called edit has the same structure, but the button is in the footer and it still works?Chilcote
C
4

Selenium WebDriver does not just check for opacity != 0, visibility = true, height > 0 and display != none on the current element in question, but it also searches up the DOM's ancestor chain to ensure that there are no parent elements that also match these checkers. (UPDATE After looking at the JSON wire code that all the bindings refer back to, SWD also requires overflow != hidden, as well as a few other cases.)

I would do two things before restructuring the code as @Brian suggests.

  1. Ensure that the "div.modal_footer" element does not have any reason for SWD to consider it to not be visible.

  2. Inject some Javascript to highlight the element in question in your browser so you know absolutely you have selected the right element. You can use this gist as a starting point. If the button is highlighted in a yellow border, then you know you have the right element selected. If not, it means that the element selected is located elsewhere in the DOM. If this is the case, you probably don't have unique IDs as you would expect, which makes manipulation of the DOM very confusing.

If I had to guess, I would say that number two is what you are running into. This has happened to me as well, where a Dev reused an element ID, causing contention in which element you're supposed to find.

Cheney answered 16/7, 2013 at 14:42 Comment(4)
I think its number one. I've added my other question in the OP to demonstrate why.Chilcote
Ah! I see. Well, after looking at your other post, I found in the SWD code where Overflow: hidden items are also considered not displayed github.com/SeleniumHQ/selenium/blob/…Cheney
it must firefox specific, since the chrome driver doesn't have that problem.Chilcote
want to answer my other question? #17624812Chilcote
S
5

Brian's response was right: use an explicit wait versus Thread.Sleep(). Sleep() is generally brittle, you're losing five seconds needlessly, and moreover it's just a really rotten practice for automated testing. (It took me a long, LONG time to learn that, so you're not alone there.)

Avoid implicit waits. They generally work for new items being added to the DOM, not for transitions for things like a modal to become active.

Explicit waits have a great set of ExpectedConditions (detailed in the Javadox) which can get you past these problems. Use the ExpectedCondition which matches the state you need for your next action.

Also, see Ian Rose's great blogpost on the topic, too.

Scevo answered 15/7, 2013 at 22:34 Comment(1)
My code is in C#, the docs are in java (-1). Did research on explicit waits (+1) and found this: docs.seleniumhq.org/docs/04_webdriver_advanced.jsp so I neither up or down voted.Chilcote
C
4

Selenium WebDriver does not just check for opacity != 0, visibility = true, height > 0 and display != none on the current element in question, but it also searches up the DOM's ancestor chain to ensure that there are no parent elements that also match these checkers. (UPDATE After looking at the JSON wire code that all the bindings refer back to, SWD also requires overflow != hidden, as well as a few other cases.)

I would do two things before restructuring the code as @Brian suggests.

  1. Ensure that the "div.modal_footer" element does not have any reason for SWD to consider it to not be visible.

  2. Inject some Javascript to highlight the element in question in your browser so you know absolutely you have selected the right element. You can use this gist as a starting point. If the button is highlighted in a yellow border, then you know you have the right element selected. If not, it means that the element selected is located elsewhere in the DOM. If this is the case, you probably don't have unique IDs as you would expect, which makes manipulation of the DOM very confusing.

If I had to guess, I would say that number two is what you are running into. This has happened to me as well, where a Dev reused an element ID, causing contention in which element you're supposed to find.

Cheney answered 16/7, 2013 at 14:42 Comment(4)
I think its number one. I've added my other question in the OP to demonstrate why.Chilcote
Ah! I see. Well, after looking at your other post, I found in the SWD code where Overflow: hidden items are also considered not displayed github.com/SeleniumHQ/selenium/blob/…Cheney
it must firefox specific, since the chrome driver doesn't have that problem.Chilcote
want to answer my other question? #17624812Chilcote
O
1

After discussing this with you in chat, I think the best solution (for now, at least) is to move the button out of the footer for your modal and into the body of it.

This is what you want (for now):

<div class="modal-body">
   <p class="alert alert-info">
      <input name="addEmployees-username" id="addEmployees-username" />
      <input name="addEmployees-password" id="addEmployees-password" type="password" />
      <input name="addEmployees-employee" id="addEmployees-employee" />
      <button name="addEmployees-add" id="addEmployees-add" type="button" class="btn" data-ng-click="submit()">Add</button>
   </p>
</div>

And not this:

<div class="modal-body">
   <p class="alert alert-info">
      <input name="addEmployees-username" id="addEmployees-username" />
      <input name="addEmployees-password" id="addEmployees-password" type="password" />
      <input name="addEmployees-employee" id="addEmployees-employee" />
   </p>
</div>

<div class="modal-footer">
   <button name="addEmployees-add" id="addEmployees-add" type="button" class="btn" data-ng-click="submit()">Add</button>
</div>
Olathe answered 11/7, 2013 at 22:40 Comment(0)
M
1

I had the same issue of element not visible so cannot be interacted with. it just got solved. i updated my selenium stand alone server. previous version was 2.33.0 and now it is 2.35.0

Moorer answered 28/10, 2013 at 5:23 Comment(4)
excuse me, I want to know how to resolve this. I use latest protractor, chromedriver 2.32, selenium version is 3.5.3.When I want to test button in the modal-footer, it still 'element not visible'. When I move the button from footer to modal-body, everything is ok.Eddi
Can you check if this works for any of the Browsers ? Can you check if the element is correctly identified?Moorer
I found it! The reason is so funny, because protractor launch a browser only half width of normal, so it's not visible of course! I add " browser.driver.manage().window().maximize();" in the test start, so protractor launch a full screen mode browser to test, resolved!Eddi
Awesome. I thought you already launched it in full screen mode. That's a preReq :). My advice : in your method to instantiate the browser, do below steps in the same order :. 1) if else condition on browser selection and based on that browser instantiation. 2) maximize the browser 3) navigation to the url 4) return back the driver instantiation. The return type of this method would be webDriverMoorer
I
0

In my case the element was already present in the page but it was disabled, so this didn't work (python):

wait.until(lambda driver: driver.find_element_by_id("myBtn"))
driver.find_element_by_id("myBtn").click()

it failed with error:

“Element is not currently visible and so may not be interacted with"

To solve my problem, I had to wait a couple of seconds ( time.sleep(5) ) until the element became visible.

You can also enable the element using JavaScript, a python example:

driver.execute_script("document.getElementById('myBtn').disabled='' ")
driver.execute_script("document.getElementById('myBtn').click() ")
Incase answered 26/3, 2015 at 8:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.