"The more your tests resemble the way your software is used, the more
confidence they can give you".
– Kent C. Dodds
This is
the guiding principle of Testing Library.
By following this principle, your tests will give you much needed confidence
(which is why they exist in the first place).
There's no better way to make automated tests resemble the way the user will use
your software than to program an actual browser to interact with your
application the same way a user would. Without access to any internals, without
mocking the backend, etc. This is called an "End-to-End" test (or E2E).
So far, our tests have been much more granular and have mocked out HTTP
requests. In this case we're trading some confidence for some
convenience/practicality. When a failure happens in our unit test, it's normally
pretty straightforward to know what went wrong. Contrast that with an E2E test
which is sometimes very difficult to triage the root of the issues.
This is why we spend most of our time with integration tests because
they give us the most bang for our buck.
That said, a single E2E test can give us a HUGE amount of confidence and
confidence that we can't reasonably have any other way. For example, we have
nothing giving us automatic confidence that the application works with the
real backend. So having a single E2E test can give us confidence that we've
wired things up properly.
Often these kinds of tests will run with a local instance of the backend or
perhaps referencing a "staging" server that's run for development. An
alternative approach is to actually run tests in production (with the use of
feature flags). Listen to a super interesting take on this kind of testing on
the Chats with Kent podcast:
Talia Nassi on Testing in Production
However you configure things to run, E2E tests can give you a great deal of
confidence. There are various tools you can use to accomplish this browser
automation. We'll be using Cypress which has a
Testing Library Implementation so things
should feel pretty familiar to you. The biggest difference is that you'll be
using the cypress cy
utility for queuing up commands that cypress will execute
and you'll use the find*
variant of the queries exclusively.
Here's a quick example of how to write a cypress test:
describe('smoke', () => {it('should allow a typical user flow', () => {// 📜 https://docs.cypress.io/api/commands/visit.htmlcy.visit('/some-app-route')// 📜 https://github.com/testing-library/cypress-testing-library/tree/17c11b47d2649dc3eb5ff62f66dea566030f4613#usagecy.findByRole('button', {name: /click me/i}).click()// imagine clicking the button opens a modal window. If we want to scope our// queries to that dialog, we can search for it, and then use `within`:// 📜 https://docs.cypress.io/api/commands/within.html#Syntaxcy.findByRole('dialog').within(() => {// 📜 https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Assertionscy.findByRole('alert').should('contain', 'Oh no! You clicked the button!')})})})
We have cypress configured for you in the cypress/plugins/index.js
file, we
have @testing-library/cypress
setup in the cypress/support/index.js
file,
and we have the following scripts for you to run in the package.json
:
npm run test:e2e
- locally, this will run the app dev server and startnpm run cy:open
- If you're already running the dev server, then you can runFor unit tests, we're often testing a single function. For integration tests,
we're normally testing a single screen. For E2E tests, we're putting it all
together and testing the application as a whole. This means that typically the
E2E test follows a typical user flow which results in a longer, more
comprehensive test that allows you to cover a lot of the most important use
cases for your application.
Just be careful to avoid "repeat testing" as described in
Common Testing Mistakes.
Production deploys:
For this exercise, we're going to test the following user flow:
The emoji will be around to help you know what to do! Good luck!
cypress/e2e/smoke.js
After the instruction, if you want to remember what you've just learned, then
fill out the elaboration and feedback form:
https://ws.kcd.im/?ws=Build%20React%20Apps&e=14%3A%20E2E%20Testing&em=
Kent C. Dodds: 0:00 End-to-end testing is really great because it gives you a clear picture of your application, working as it should in production. You're using a real browser interacting with it exactly as the user would be interacting with it.
0:16 Here I give you a little bit of background on end-to-end testing and some things to think about with where you should focus most of your time. I'll also give you a couple of references and things to think about and interesting ideas like testing in production, testing your actual production code.
0:33 For us, we're not going to be testing in production today, but we are going to be using an awesome tool called Cypress that you already have installed, and it's already been pre-configured for you to use cypress-testing-library. Lots of the things that you'll be doing today should feel pretty familiar to you.
0:49 Here's a quick example of how you write a Cypress test that you can look over with some inline links to different documentation that you might find useful, and some explanation of some of the things we have preconfigured for you already.
1:03 For us I already have the app up and running, so I'm going to run this npm run cy:open. That will get Cypress the app open on my desktop here. Then I can click on this test right here, and it will load up my tests, which right now are empty.
1:21 It's not going to run anything, and that's your job to fill this up with some awesome tests that will verify our application is in a working state. To verify that it's in a working state I've got this list of instructions for you to implement in a Cypress test.
1:37 I hope you have a good time with this one, and we'll see you on the other side of the exercise.