Ruby
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
132: System Tests with Capybara
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.
There are no comments for now.