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!