Skip to Content
Course content

132: System Tests with Capybara

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've spent a lot of time in unit and functional tests. Those are great for checking if a specific method works or if a controller returns the right status code, but they don't actually tell you if your user can actually use the site. That's where Capybara comes in. It's essentially a way to automate a browser, allowing us to simulate a real human clicking buttons and filling out forms.

Setting the Stage for the Contact Form

Let's build a test for a simple "Contact Support" feature. In a real app, this would hit a mailer and save a record to the database, but for our system test, we only care about the user's experience: they land on the page, they enter their details, they hit submit, and they see a success message. I prefer writing these tests first because it forces me to think about the UI from the user's perspective before I get bogged down in the implementation.

class ContactSupportSystemTest < ActionDispatch::SystemTestCase
  test "user can submit a support request" do
    visit contact_support_path
    
    fill_in "Email Address", with: "dev@example.com"
    fill_in "Message", with: "I can't figure out why my CSS is overlapping!"
    click_on "Send Request"

    assert_text "Your message has been sent!"
  end
end

Fixing my "Link vs Button" blunder

When I first ran this, the test failed. Capybara complained that it couldn't find the "Send Request" element. Now, I looked at my HTML and realized I had used a stylized link <a class="btn"> instead of an actual <button> element to make it look fancy. I had originally used click_button in a previous draft of this test, which failed because it specifically looks for <button> or <input type="submit">.

I could have changed the HTML, but in this case, I decided to use click_on. It's a more flexible helper that finds either a link or a button. I've learned the hard way that being too specific with click_button or click_link leads to brittle tests that break the moment a designer changes a tag for styling reasons. click_on is my go-to for keeping tests resilient.

Verifying the Success State

The last part of the test is assert_text. One thing you'll notice is that I'm not checking for a specific CSS ID or a hidden data attribute. I'm checking for the actual text the user sees. This is the philosophy of system testing: if the user can't see the success message, it doesn't matter if the database record was created perfectly.

One quick tip: if you find your tests failing because the page hasn't finished loading an AJAX request, don't reach for sleep(5). That's a cardinal sin in Capybara. Instead, use a finder like assert_selector or have_text. Capybara has built-in "waiting" logic that will keep retrying the check for a few seconds before giving up, which makes your tests much faster and less flaky.

  • visit: Navigates to a URL.
  • fill_in: Finds a field by its label text or ID and enters text.
  • click_on: Clicks a button or link by its text.
  • assert_text: Ensures the given string is visible anywhere on the page.



📋 Practical Task

Build a "Newsletter Subscription" System Test

You are tasked with adding a newsletter subscription footer to a website. Your goal is to write a system test using Capybara that verifies the entire subscription flow.

Requirements:

  • The test should navigate to the root path.
  • It should locate an email input field labeled "Subscribe to our newsletter" and enter a valid email address.
  • It should click a button labeled "Join".
  • It should verify that the page displays the message: "Thank you for joining our mailing list!"

Write the full test class and method. Ensure you use the most resilient Capybara helpers (like click_on) to avoid the brittle tag issues discussed in the lesson.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.