Talks
Ambitious Capybara

Ambitious Capybara

by Eduardo Gutierrez

In this presentation titled 'Ambitious Capybara', Eduardo Gutierrez discusses best practices for leveraging Capybara for testing in complex applications. The focus is primarily on enhancing the confidence of developers in writing effective integration tests, particularly for JavaScript-heavy applications. Gutierrez begins with a personal narrative about the journey of preparing the talk, thanking supportive communities and highlighting the importance of sharing experiences in the developer community. He expresses his affection for Capybara, despite common frustrations developers face with integration tests, such as frequent failures and difficulties in maintaining them.

Key points discussed include:

  • Readability and Maintainability: Gutierrez emphasizes the significance of writing readable and maintainable feature tests that can act as documentation for stakeholders. He argues that tests should resemble user stories to enhance clarity.
  • Avoiding Raw Selectors: The speaker advises against using raw CSS selectors, which can complicate test maintenance. Instead, he advocates for using semantic HTML and reliable selectors, such as data attributes or titles, to improve readability and reduce coupling between styling and testing.
  • Accessibility: He highlights the importance of making tests accessible, advocating the inclusion of labels for inputs even if they are visually hidden, ensuring compatibility with screen readers.
  • Performance Optimization: To improve test performance, he recommends using the within helper to scope DOM searches, thus speeding up execution.
  • Comprehensive Feature Specs: Rather than creating isolated tests, Gutierrez encourages a QA script approach, which evaluates various functionalities holistically.
  • Multi-Application Testing: Capybara's ability to handle multiple applications in one session is showcased, particularly useful for scenarios involving integrated application testing.

Gutierrez concludes by sharing best practices drawn from his experiences, expressing hope that developers will feel empowered to apply these insights to enhance their testing strategies. His final message encourages developers to reconsider their use of Capybara, emphasizing its utility for ambitious web applications and the importance of community feedback in raising confidence in testing methodologies.

00:00:11.840 Hello everyone, my name is Eduardo Gutierrez. I'm going to be talking to you today about Ambitious Capybara.
00:00:19.720 This talk is brought to you by some very special people. I've been unemployed for most of the time while working on this talk for the past few months, so I don't have any actual companies sponsoring me. Instead, I'm grateful to these restaurants in the Boston area that allowed me to sit in their establishments for like six hours a day coding. It was getting a bit old sitting at home, especially with all the snow; I needed to get out.
00:00:32.520 Additionally, I'd like to give a huge thanks and shout-out to the Boston RB Ruby group. I presented an early version of this talk to them, and they provided a lot of really valuable feedback. They've also been a fantastic community that encourages individuals to share their voices. I wouldn't be here today presenting if it wasn't for them.
00:00:52.239 Now, I have a very deep confession I'd like to share with you all. It feels awkward to admit it, given my experience with various Ruby and Rails projects, but I'm in love with Capybara. This might not seem strange to you, but the number of times I've seen developers slump over features in a feature file is disheartening. They often express confusion over the test code, which is not even old production code. Many developers have very little faith in integration tests due to bad experiences or complexities they encountered in the past.
00:01:16.280 I've worked on a lot of projects where the quality of integration tests declined in favor of more unit tests, or where teams simply dealt with the burden of tests that intermittently fail. You find yourself on pins and needles, questioning whether a new feature will break something else in the application. My goal today is to dispel that fear for anyone here in the audience and to provide you with tips and tricks to reestablish your confidence.
00:01:45.119 When Capybara first came out, it changed the game for the types of ambitious applications we could build with Ruby on Rails and any Ruby-based frameworks. The ability to test JavaScript and make assertions without having to couple tests to specific parts of the DOM has been a significant contributor to the kind of applications we see today. These applications inspire us all to build bigger and better things.
00:02:25.360 I’d like to start with some little-known facts about Capybaras, or the Hydrochoerus. They originate from South America. In researching for this talk, I discovered that the pronunciation of 'Capybara' is up for heavy debate. I’ve heard it pronounced as 'Kappy-bar' versus 'Kappy-Bara,' and it has even caused me to lose some friends over this discussion! One interesting fact about Capybaras is that they are semi-aquatic. It makes sense, as Capybaras can navigate through the internet tubes underwater.
00:03:00.840 They can roam over an area spanning 25 acres, which tells me they're capable of handling very large applications. They are also very friendly animals; many people have them as pets. Capybara is an approachable tool. If you've had a bad experience, I hope to encourage you to give it another chance. I want to talk about balancing readability, maintainability, and performance, as this balance is core to what it means to build software.
00:03:47.760 This involves how readable the project is, meaning how easily anyone else can understand what is going on. Then there's maintainability—can someone easily make changes without compromising the rest of the application? And finally, how well does it perform? Some might argue that readability and maintainability are essentially the same, but I disagree. For instance, you might have a very readable DSL—like the Rails router—that makes sense, but if you look under the hood, you see the complexity required to maintain that neat structure. On the other hand, you could have well-structured, maintainable code that remains difficult to navigate due to a high learning curve.
00:04:39.360 Ideally, we want to find a sweet spot. When it comes to integration tests, I tend to prioritize readability over performance, aiming for a balance that lets my tests serve as documentation, potentially useful for stakeholders or juniors and seniors exiting the code for the first time.
00:05:37.080 So, how do we describe these things for Capybara? Readability means your feature test should be written like user stories, calling back to the days of Cucumber feature files. The aim is to ensure it's something a stakeholder can read and understand, with as few technical details as possible. You want it to embody the Ruby essence of highly readable code.
00:05:58.440 Maintainability is about creating feature tests that can grow and be easily refactored as your features and product expand. For performance, you want fast feedback on your CI server to know if any changes broke something else or when iterating on a single feature, where you want rapid feedback rather than waiting for everything to boot.
00:06:55.400 The goal for today is to address each of these aspects by discussing anti-patterns and best practices I’ve developed over the years, which have helped me regain confidence and excitement for writing feature tests.
00:07:23.360 Starting with readability, the primary piece of advice is to avoid using raw selectors in feature specs as much as possible, especially CSS classes. I recommend delineating CSS classes for styling only. Combining the two—using CSS classes as both test hooks and styling—can lead to conflicts. For example, if a designer changes a CSS class or completely refactors markup, they're likely to unexpectedly break tests.
00:08:08.240 The Capybara DSL works exceptionally well when you use proper HTML semantics, especially with forms. This means having labels associated with all your inputs. The summary of these points is that user stories should be described in a way that a user can read and understand it. Let’s take a look at a simple sign-in test to illustrate this concept.
00:08:55.960 In this test, we create a user, visit the sign-in page, and then fill in the sign-in form. However, I want to call out that we use the input IDs to sign in. Unfortunately, I don’t think that ID approach is very user-friendly. It makes more sense from the perspective of user stories if the code is more human-readable, rather than requiring someone to look at the DOM to find elements.
00:09:46.240 This method also lacks accessibility for users, particularly for those who might rely on screen readers. Instead of removing labels from the view for aesthetic purposes, we can hide them from view while making sure both browsers and screen readers can still read them.
00:10:24.960 An accessible way to do this is to use a CSS hack where the label itself is hidden from view but remains visible to assistive technology. Following this approach ensures that our tests pass while simultaneously making our application more usable by helping screen readers find associated inputs.
00:11:09.760 Now, we could introduce a potential curveball by making this a JavaScript test. Capybara defaults to ignoring hidden elements on the page since version 2.0. This mirrors the experience users have when using screen readers—where they cannot locate inputs if the elements are hidden. A valuable alternative could be using that CSS hack we discussed earlier to create accessible hidden labels visible to screen readers and JavaScript drivers.
00:12:49.120 Let’s examine another feature test which implements a user search in your contacts, allowing search by birth date through a jQuery calendar picker. We're omitting the functionality of interacting with the date picker for now, but I’ve taken a screenshot to show the expected behavior.
00:13:58.560 In our test, we see two violations: one for using a raw CSS class to find the button that opens the calendar, and another for using a complex Sizzle selector to assert content visibility. Capybara does understand Sizzle, but leveraging it can lead to overhead regarding understandability within your test code. Instead, we can utilize Capybara's methods to ensure our tests are less coupled and clearer.
00:15:40.400 Let’s address the first violation about using a raw CSS class. It is not effective to pass a CSS class directly to click a button without recognizing the defined parameters that Capybara provides for a button locator. We need to change the markup to include title attributes on the buttons for opening, closing, or resetting the calendar, which simplifies our selectors.
00:16:34.960 Next, we need to address the issue with the Sizzle selector. Capybara provides a built-in option to use the have_selector method, which allows assertions regarding content without adding unnecessary complexity. Instead of relying on CSS classes, let's define a useful pattern using data attributes for better readability and maintainability.
00:17:41.640 By adding custom data attributes, we clarify queries and facilitate matching tests to their respective elements without confusing CSS selectors. This results in improved overall code quality, as we decouple CSS from test hooks.
00:18:14.520 Now, let’s examine how to effectively interact with the jQuery date picker. To do this, we need to select from two dropdowns to change the year and month, followed by clicking the desired date on the calendar. Unfortunately, the header has two select dropdowns without any labels, making standard DSL methods ineffective.
00:19:02.880 If we consider the calendar further, the numbers listed within the calendar elements aren’t guaranteed to be unique, creating potential ambiguities when attempting to click on them. Diving deeper into Capybara’s internals, when we run a find query, we obtain a Capybara element instance, which acts as a wrapper around the corresponding DOM element, thus providing an interface for interaction.
00:20:43.840 For example, to interact with the year dropdown, we find the appropriate CSS class, select the option, and then carry out the same process for the month. Selecting a date requires extracting the right anchor tag based on its classes and ensuring the queried element is unique to avoid any ambiguity when dynamically generating dates.
00:21:32.720 This concludes how to implement a method for interacting with date pickers. Nonetheless, we should extract a helper method from this process to avoid repetition across our tests. I recommend defining a choose_date method in a shared module to maintain clarity and usability throughout the application.
00:22:20.240 It’s also important to check that when we reload the page, the value we entered in the input field remains consistent. Utilizing Capybara's DSL selectors, we aim for smoother testing execution. The selector method allows us to find elements based on their attributes, thus avoiding locked functionalities that result from hard-coded selectors.
00:23:35.520 Next, let’s talk about improving performance. One effective way to achieve quicker feedback is to use the within helper that scopes to the same area of the DOM. This speeds up performance astonishingly, as each call made while interacting with an element within that scope does not need to start searching from the top of the page.
00:24:36.960 Despite its advantages, it's essential to recognize when the within method might fail to find elements, like when working with inputs bound to the bottom of the DOM, such as jQuery date pickers. This helps developers avoid common pitfalls that could lead to failed tests, thus ensuring smooth test results.
00:25:41.200 An additional practice for faster and more effective tests is to compose your feature specs as QA scripts, which allows for large integration tests covering various functionalities instead of having separate tests for different paths. A comprehensive approach creates an efficient testing environment where functionality can be checked without redoing the setup for each test.
00:26:45.480 For example, one of the tests I worked on previously aimed to ensure that users could edit existing items, check form validations, and verify that user input correctly triggered updates. Structuring your tests this way ensures coherency and documentation that can guide future reference.
00:27:37.200 Furthermore, when working on service-oriented applications, Capybara allows you to manage two distinct applications in a single session through window handles. This is incredibly useful for testing scenarios where interactions span multiple apps without requiring extensive code changes or complex setups.
00:28:36.960 By employing Capybara's window feature, developers can simulate more complex application interactions seamlessly, confirming that actions taken in one application reflect appropriately in another. This flexibility in Capybara supports extensive and functional testing processes, promoting best practices for collaborative application environments.
00:29:39.680 In summary, I’ve shared various best practices and insights on how to leverage Capybara effectively in your testing environments. I'm thankful for your time and hope you leave here excited to apply these practices to enhance your own applications!