WithForm

Your System Test's counterpart to form_with

Usage

Leverage Rails-generated <label> values to submit <form> elements in System Tests.

To add coverage to a form's fields that are generated by ActionView's form_with helper, fill them using with_form:

class UserInteractsWithFormsTest < ApplicationSystemTestCase
  include WithForm::TestHelpers

  test "user signs in" do
    visit new_session_path
    with_form(scope: :session) do |form|
      form.fill_in :email, with: "[email protected]"
      form.fill_in :password, with: "secr3t"
      form.check :remember_me
      form.click_button
    end

    assert_text "Welcome back, [email protected]."
  end

  test "user makes a post" do
    post = Post.new(title: "My First Post", tags: ["ruby", "testing"])

    visit new_post_path
    with_form(model: post) do |form|
      form.fill_in :title
      form.check :tags
      form.click_button
    end

    assert_text "Created Post: My First Post."
  end

  test "user updates their profile" do
    profile = Profile.create!

    visit profile_path
    with_form(model: profile) do |form|
      form.fill_in :email, with: "[email protected]"
      form.select "NY", from: :state
      form.click_button :update
    end

    assert_text "Your profile has been updated."
  end
end

with_form Options

The with_form helper method accepts two styles of options:

  • scope: - the internationalization scope key to use when translating Capybara's locator values
  • model: - an instance of an ActiveModel::Model or ActiveRecord::Base to be used to translate Capybara's locator values, and to populate the fields with an attribute's value.

For example, assuming that a Post record has a title attribute:

  post = Post.new(title: "The Title")

  form_with(model: post) do |form|
    form.fill_in :title
  end

The call to form.fill_in will search for an <input> element or a <textarea> element that is labelled by a <label> element whose value is translated from the helpers.label.post.title internationalization key. If that element exists, set its value to the value of post.title (in this case, "The Title").

An attribute's value can be overridden by providing a different value. For instance, assuming that a Post record has a title attribute:

  post = Post.create!(title: "Old Title")

  form_with(model: post) do |form|
    form.fill_in :title, with: "New Title"
  end

The call to form.fill_in will work much like the example above, with the exception that the provided with: option's value (in this case, "New Title") will take precedence over the post.title attribute's value (in this case, "Old Title").

With the exception of #click_link and #click_link_or_button, the argument yielded to with_form supports all helper methods made available by Capybara::Node::Actions.

Those include:

  • attach_file(locator = nil, paths, make_visible: nil, **options)
  • check(locator, **options)
  • choose(locator, **options)
  • click_button(locator, nil, **options)
  • fill_in(locator, with: nil, **options)
  • select(value = nil, from: nil, **options)
  • uncheck(locator, **options)
  • unselect(value = nil, from: nil, **options)

Installation

Add this line to your application's Gemfile:

gem 'with_form'

And then execute:

$ bundle

Then, include the WithForm::TestHelpers into your project testing framework.

MiniTest

# test/application_system_test_case.rb
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  include WithForm::TestHelpers
end

RSpec

# spec/support/with_form.rb
RSpec.configure do |config|
  config.include(WithForm::TestHelpers, type: :system)
end

FAQ

I want to call a Capybara helper with that input's id attribute or name attribute. How can I do that?

  • You can mix the object that you invoke the helper methods on within the with_form block. For instance:
  with_form(scope: :post) do |form|
    form.fill_in :title, with: "The Post's Title"
    fill_in "another-field-id", with: "Another Value"
    fill_in "post[special-field]", with: "Special Value"
  end

I've used the formulaic gem before. How is this gem different?

License

The gem is available as open source under the terms of the MIT License.