Search code examples
ruby-on-railsrubycapybaracapybara-webkitcocoon-gem

How to test Cocoon gem's nested forms with Capybara and Minitest in Rails


Is it possible to use Minitest and Capybara to test multi-step forms in Rails? All of the examples I've read online and in Stackoverflow are using Rspec. For instance, this question.

It seems like this should be something that is possible to do in Minitest though. I'm trying to test a nested form that uses the Cocoon gem and looks like this:

Before clicking the "New Option" button: first step in the cocoon gem form

After clicking the "New Option" button: Second step in the cocoon gem form

But, my test keeps failing at this step:

click_link 'New Option'

If I add 'save_and_open_page' after click_link 'New Option' the browser shows that field that should be revealed by click_link 'New Option'. It works when I test it manually on my development server though. This New Option button is generated by Cocoon with this:

<%= link_to_add_association 'New Option', f, :options %>

So that leads me to believe that it's not finding the field on the next step because javacript is not working in Capybara and Minitest. But I'm not sure.

I have Capybara.javascript_driver = :webkit in my test_helper.rb file, so the javascript driver should be working

Is this a problem with Minitest? Or am I doing something wrong in my test? If I view source on the page that is generated by save_and_open_page I can see the hidden fields in the New Option link tag. Here's what that looks like:

enter image description here

Based on this question, it seems like I need to do something like this:

click_link "New Option" first("input[name='product[options_attributes][new_options][name]']").set("New Option Name")

But that gives me the error:

Capybara::ExpectationNotMet: expected to find css "input[name='product[options_attributes][new_options][name]']" at least 1 time but there were no matches

It seems like there's something wrong with Minitest & Capybara testing Javascript because it seems to fail at the "New Option" link and not after that. I can't tell if it's a problem with Javascript related to Minitest and Capybara or if I'm not accessing the field properly in Minitest.


Solution

  • Thanks to Thomas Walpole for pointing out that capybara-webkit was the problem. Along with some help from this article, here's what I needed to change the test passing:

    Added these to my Gemfile:

    group :test do
      gem 'selenium-webdriver'
      gem 'webdrivers'
    end
    

    Added this to my test_helper.rb:

    class ActionDispatch::IntegrationTest
      Capybara.register_driver :selenium do |app|
        Capybara::Selenium::Driver.new(app, browser: :chrome)
      end
    
      Capybara.javascript_driver = :chrome
    
      Capybara.configure do |config|
        config.default_max_wait_time = 10 # seconds
        config.default_driver        = :selenium
      end
    end
    

    And then my test:

    test 'Account owners can add a new product as well as options and choices' do
      visit new_product_path(as: @account_owner)
      assert_title 'Add New Product'
      assert_selector 'h1', text: 'Add New Product'
      fill_in 'product_name', :with => @new_product.name
      # Users can add product options through the nested form
      click_link 'New Option'
      within('.product_options_name') do
        first('input.form-control').set("#{@t_shirt_colors.name}")
      end
      click_link 'Add Choice'
      within('.product-option-choice') do
        first('input.form-control').set("#{@red_color_choice.name}")
      end
      click_button 'Create Product'
      assert_selector '.alert', text: 'Product was successfully created.'
    end