Diego
Diego

Reputation: 472

Can I detect if an element (button) is "clickable" in my rspecs?

Context: In my rspec (using Ruby and Capybara)

  1. I click on a link to test an action in my app: adding a branch to my app.
  2. A modal window opens, where I select the branch, and then I click a "submit" button to add the branch to my app. After clicking "submit" the modal window is closed.
  3. The rspecs continues by clicking "Save" in the main screen, to save the state of the application (and effectively saving adding the branch).

Problem: The rspec is failing because (seemingly) it is trying to click the "Save" button on the main screen while the modal window that is used to select the branch is still present. The test doesn't complain that it can't find the "Save" button component, but that it can't be clicked.

The error in the log is:

[...]Save</button> is not clickable at point (692, 23). Other element would receive the click[...]

A gotcha: this rspec passes correctly on some environments, like when it is run against my local server, but it fails when it is executed by our automation server. Thus, this test has been tagged as "flaky".

Potential solutions: Things we have tried so far:

The while condition checks if the "submit" button of the modal window exists. The element_visible function uses

find(method,element).visible?

but I'm not sure if find should already take into account that the button may exist and be visible but not be clickable.

Since this still fails, in spite of all our effort to make sure that the modal is gone before we attempt to click on the "save" button, I want tot ask:

Is there a proper way to detect if an element behind a modal window is clickable or not using rspecs?

Upvotes: 1

Views: 2156

Answers (2)

Timitry
Timitry

Reputation: 2915

I had a similar problem and solved it by writing my own click_on_with_wait helper function:

def click_on_with_wait(text, wait_time: Capybara.default_max_wait_time)
  success = false

  (wait_time * 10).round.times do
    click_on text
    success = true
    break
  rescue Selenium::WebDriver::Error::WebDriverError
    sleep(0.1)
  end

  # Try clicking one last time, so that the error will get raised if it still doesn't work
  click_on text unless success
end

This will try to click on the element. If it's still hidden by the modal, the function will wait 100ms and then try again, until the given wait_time is reached.

Using Rails, I put it in system_spec_helpers.rb so that I can simply replace click_on 'Submit Form' with click_on_with_wait 'Submit Form'.

Upvotes: 2

Thomas Walpole
Thomas Walpole

Reputation: 49920

find only cares about "visibility", not "clickability" (and different drivers may have slightly different interpretations of "visibility"). The reason for the flakiness you're seeing is most likely speed of the machine running the tests which affects the timing of the modal animating away. The best way to solve this issue is to disable animations in the test mode (how you do that is dependent on exactly what library and/or CSS you're using for the animations). The other way is to do as you're doing - checking that the modal has disappeared before clicking the 'Save' button, however you should just be using the Capybara provided methods (which include waiting/retrying behavior) rather than writing your own loop for that.

 expect(page).not_to have_css('css selector of the modal') # RSpec version
 assert_no_css('css selector of the modal') # minitest version

After looking at the mouse position from your error, one other potential issue you may be having is with screen size and scrolling. If the page requires to be scrolled to get to the 'Save' button and (692, 23) would put the button behind a fixed header (you should be able to verify that by taking a screenshot before the button click attempt) then it may not be possible for whatever driver you're using to click the button. In that case you'd need to use execute_script to scroll the page to a different location so the button is not covered on the page and/or increase the "browser" size so scrolling isn't necessary in the test.

Upvotes: 2

Related Questions