capybara Inconsistent behavior when attempting to find a conditionally-rendered react component Ruby

Dear all, After struggling for a few days and a fair amount of research, I am writing here in hopes of finding a solution to my issue. I apologize if this is not the right place for submitting this issue or if it is not clear enough. Thank you so much for your time !


Capybara Version: 3.32.2 Driver Information: Selenium 3.142.7 with headless_chrome and Chrome browser.


I created a system tests suite running on a React page. The tests fail on one of the page's forms, where some radio buttons (generated by a custom RadioButton component) are rendered conditionally if other radio buttons are true.

This is what the React code looks like (using pseudo-code and dummy button1 and button2 names) :

<RadioButton name="button1" />
{button1True && 
  <RadioButton name="button2" />

where button1True results from a watcher on the 1st radio button.

This is the HTML associated to an instance of a particular RadioButton component :

<label for="name-true"><input class="hidden" id="name-true" type="radio" value="true"><span>Yes</span></label>
<label for="name-false"><input class="hidden" id="name-false" type="radio" value="false"><span>No</span></label>

To click these radio buttons, I created a generic Capybara method :

def click_radio_button(radio_name, value)
  using_wait_time(10) {
    expect(page).to have_selector("label[for='#{radio_name}-#{value}']")

Here is the stack trace I get :

Failure/Error: expect(page).to have_selector("label[for='#{radio_name}-#{value}']")
expected to find css "label[for='button2-true']" but there were no matches

Now, I realize I cannot immediately click on the button2 radio right after the button1 radio was clicked as there might be slight latency with the watcher. The React page is not particularly slow, but to be safe I added using_wait_time to allow for the radio to be rendered before clicking on it. What I noticed is that these tests fail or succeed inconsistently, due to uncertainty regarding the rendering of the radio.

I attempted other things, such as using sleep instead of using_wait_time, with different durations (I am aware these workarounds are not clean but I am quite new to Capybara and would be happy for now to just make these tests work consistently). I also tried using choose instead of find and clicking on the label, or simply clicking on the input (using visible: false). At the end of the day, I always have the same result. Do you notice something wrong in my code ? Is there a way to make sure that the element is present before clicking it ?

Don't hesitate to ask for more details regarding anything I have said. I can also give more accurate pieces of code instead of pseudo code if needed.

Kind regards, Jonathan

Asked Oct 07 '21 03:10
avatar samjalas

1 Answer:

These issues are for bugs in Capybara, not "how to" type questions. In the future please ask "how to" question in the mailing list or on stackoverflow rather than creating an issue.

As for issues with your code

  1. usingwaittime just changes the the maximum amount of time Capybara methods will wait for their conditions to be met within that block - if it's really taking your page 10 seconds to re-render there's something else wrong.
  2. Calling expect to have selector and then find for the same element makes no sense because find will already wait
  3. rather than your click_radio_button method just call choose("#{radio_name}-#{value}", allow_label_click: true) to allow Capybara to make the click button or label determination

Beyond that, the fact that button2-name isn't being rendered within 10 seconds tells me that button1True is never being set to true - without seeing the actual test code you're running the most likely cause of that is you're clicking the button1-true label either before the react behavior has been attached - put a sleep(5) before that click to test - or while the page is re-rendering so the click is being lost - in which case you need to expect something that would indicate the page is ready for interaction.

Answered Aug 17 '21 at 22:32
avatar  of twalpole