My team and I are working on a React project that runs in regular browsers, and we recently decided to use Cypress for end to end testing. It has an actually surprisingly nice you can use to write describe-it style test scripts that will load up a browser with any page on your site, click some things, interact with the dom, and then even do assertions that your page renders correctly. You can do "cypress run" to run your tests via the command line or "cypress open" to start this little application from which you can run all tests or just specific tests, and it creates this little sidebar that gives you a history of the commands it's running and details about what happened when things have failed. Anyway, yes Cypress is awesome, but that's not what thing blog post was supposed to be about...
Suppose you are writing a Cypress test that, among other things, clicks this "Get Started" button. We can easily right-click and inspect this button in a browser to see that it has a few css classes.
According to the Cypress docs for contains, it "specifies a selector to filter DOM elements containing the text". Consider again the button from the image above. You could select it by the class, "hero--fb--cta", but maybe it's not the only button with that class on the page. Maybe later that library changes to be called "hero-fb-cta", or it's there on the page with other buttons and you drill down to the nth button in your test but then later the test breaks when they add new buttons, but only when those new buttons are to the left, etc... The class name "hero--fb--cta" is pretty generic after all, and it's doesn't make for a good selector. When all you really have (from a e2e test engineer point of view) are id's and css classes then it kind of forces you to put pressure on the source code markup to have extra html properties (ie. throwing id's and classes on things that otherwise would not have had them there just force the sake of making it easy for e2e test selectors to latch onto things). In my opinion, it would make for a much less brittle and cryptic tests if we just say we wanted to click on some <a> tag on the page that contains the text "GET STARTED". Well thankfully friends, we got the contains selector!
The contains selector does exactly that- it grabs onto a DOM elements that contains the text (or other html element) you pass to it as an argument. So, for example, in our cypress test we could do something like this:
The above code is super easy to understand what it's doing (assuming you know how contains works), it doesn't rely on specific css class or id's to be there, and it doesn't rely on us having to change the source code at all! Also, it's just philosophically how a user would know to press it. You know this is a button that takes you to the getting started flow because it is a button which contains the text "GET STARTED"! Selecting an element by the text it contains is in my opinion the most thinking-as-a-user-would type of way to select things, and that's why I now almost always try to create my selectors using "contains" first. Also, note that selectors isn't e2e test specific- you can also use "contains" for selecting things in your enzyme unit tests. ?
Cypress is basically like Selenium but 100 (maybe more) times less shitty. When you have a nice api that makes it very easy to write nice code that works and actually gives you a fun development environment that watches for code changes out of the box and makes your life so nice then it becomes very easy to lead by example and set standards for how to write robust, useful tests that replace the need for lots of manually qa testing and allow you to ship software more quickly with high confidence every single time that it works as expected even if you're super drunk and / or sleeping- because you trust the tests. And if the tests do let you down and there's an error that's ok; it's the only way you can know that you are missing some tests. As long as we can then create a test to expose the edge case and a source code patch to fix it then life should be gravy.
Some people ask me, "why to do we even to frontend e2e testing at all?", and for me personally I think it is 1. because it's fun and 2. for peace of mind that your shipped shit works. Mocking all the things and having hunnits across the board for your unit tests is cool, but there is always a slight anxiety that it will all really work when you connect the pipes together and use it out in the world. I said back in the day when I was doing Protractor with AngularJs that end-to-end testing was great for making the final "are we really really ready to ship?" decision. By creating these end-to-end tests that we actually run against all the possibly os versions, browser version etc. we can keep our sanity while rapidly developing and iterating all while ensuring that the core user functionality is preserved at every point along the way.
The posts on this site are written and maintained by Jim Lynch. About Jim...