1
votes

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.

1
You can do anything with minitest you can do with RSpec - just the assertion/expectation syntaxes are different. Cocoons nested forms require JS on the page, so you need to be using a driver with Capybara that supports JS - github.com/teamcapybara/capybara#drivers. Are you actually using capybara-webkit as the driver like your tags indicate (It's obsolete, equivalent to a 7 or 8 year old browser and won't run modern JS)? If so - switch to selenium with chrome so you can actually see what is happening in the browser when the test runs.Thomas Walpole
"But, my test keeps failing at this step:" what's the error there? you should show your test too.arieljuod
@ThomasWalpole Thanks. capybara-webkit was indeed the problem. Going to post all the changes required to get the test working. Appreciate you pointing this out.Lee McAlilly
@LeeMcAlilly you’re welcome - you may also want to look at the Apparition driver which has most of the Capybara-WebKit extra features - but it isn’t yet at V1 so there are a few rough edgesThomas Walpole

1 Answers

1
votes

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