Search code examples
jquerytestingrspeccapybaraacceptance-testing

Using jQuery in Capybara tests


I'd like to ask your opinion about using jQuery in Capybara specs. Is it really simulating the real user interaction, or is it faking it?

  • Is using find("#my_checkbox[value='1']").set(true)

    the same as page.execute_script("$('#my_checkbox').prop('checked', true);") ?

  • Or find("#my_button").click

    the same as page.execute_script("$('#my_button').click();") ?

I know that the spec result will be the same, but I'm really wondering:

  • the real user won't use the JS browser's console to click on a button, so should we just replicate that without using jQuery in the specs?
  • what about the spec's performance and speed? Is there any advantage on using jQuery?

Solution

  • Using execute_script/evaluate_script to interact with the page in your tests is NOT simulating real user interaction and in a lot of cases can make your tests pointless. The main reason for this is that it allows you to do things a user never could (changing the values of hidden/readonly/disabled fields, etc). It also doesn't generate the same events a user interacting with elements would generate, so the JS in your page may not be reacting the same way. execute_script does have its place in writing tests but it's limited and usually to get values (as opposed to changing things) or to work around problems in browsers/drivers (once you fully understand the issue you're trying to work around and are sure it isn't a situation where the user couldn't actually do what you're trying to do).

    As far as speed goes the execute_script may be slightly faster in some cases but that's only because it's not verifying that a user could actually do what it's doing. Also a slightly faster but meaningless test isn't really saving you anything.

    That covers using execute_script with JS which I believe is what your question is really asking, although you specifically mention jQuery. There is also a reason not to use jQuery in any execute_script calls you do have in your tests which is that if you ever refactor your app to remove jQuery and just go with plain JS your tests will break. ie - you could prefer document.getElementById('abc') over $('#abc'). This may not be a big concern to you since there really shouldn't be that many instances of execute_script in your tests.

    TLDR -

    check('my_checkbox', option: 1) # best
    find("#my_checkbox[value='1']").set(true) # valid but too verbose
    page.execute_script("$('#my_checkbox').prop('checked', true);") # Don't use - not replicating a user
    
    click_on('my_button') # best if element is a link or button
    find("#my_button").click # valid
    find("#my_button").trigger('click') # Only supported on some drivers - don't use in tests unless you REALLY understand why you're using it - basically the same as using `execute_script`
    page.execute_script("$('#my_button').click()") # Don't use - not replicating a user