Search code examples
cucumbercapybara

Find hidden element in capybara


Learning 'capybara' and bumped into issue of finding the hidden elements through capybara.

In HTML, we have an file field which is 'display: none' by default. HTML element is:

<input class="some_class" id="some_id" name="some_name" type="file">

Now, while I was writing the test cases in capybara using cucumber, I could not find this element in my capybara script. My capybara script is finding the element just like this :

find(:xpath, "//input[@name='some_name']")

Read about the hidden elements and go to know that setting

Capybara.ignore_hidden_elements = false

should solve my problem. But I read somewhere else that above setting is by default. So, tried other option of passing it explicitly. Like:

find(:xpath, "//input[@name='some_name']", :visible => false)

That did not work too. Is there anything else I should try? Will be happy to share more details in case anyone is interested.


Solution

  • The visible option has a few potential values

    1. true or :visible => finds only visible elements
    2. false or :all => finds visible and non-visible elements
    3. :hidden => only find non-visible elements

    Therefore if your attempt of find(:xpath, "//input[@name='some_name']", :visible => false) isn't returning an element, there is no element matching that XPath in the page and you need to check that the contents of the page is what you think it is (page.html, page.save_screenshot, etc)

    Beyond that your example has a few issues. Firstly, you're falling into the XPath // trap. If (and it should be a big if) you're going to be using XPath queries a lot for finding your elements, get used to starting your queries with .// rather than just // - if you don't you are defeating all of Capybara's scoping on the page (within, chained find, etc). Using CSS selectors doesn't have that issue so makes more sense for most queries where you're not using one of Capybara's built-in selector types.

    find("input[name='some_name']", visible: false)
    

    Knowing we are looking for a file input we can go one better by using Capybara's built-in file_field selector and doing

    find(:file_field, 'some_name', visible: false)
    

    which is easier to read and explains exactly what you're looking for. Next, since you're finding a file field I assume you'll want to actually add a file to it. This can be problematic since non-visible elements can't generally be interacted with. However since file fields are so often hidden, to allow for styling, there is an option to help with that.

    attach_file('some_name', file_path, make_visible: true)
    

    The make_visible: true option will temporarily change the elements CSS to make it visible (you can set it to a hash of CSS values to set rather than true if the default CSS doesn't work on your page), attach the file to it, and then revert the CSS changes.

    As a final point, setting Capybara.ignore_hidden_elements = false is a terrible idea if you're testing an app (if just doing automation it's fine) since it leads to tests that aren't actually testing what a user can see/do.