Long long time ago (aka in August of 2020) one curious reader named Guillermo Rauch in a moment of contemplation asked on Twitter what books people (re)read:
This short question has prompted lots of responses. People on Twitter are really helpful, aren't they? Then Guillermo has collected the feedback in one single Notion table with book links, cover images, and number of votes for every book. How do I know about it? Because he has blogged about it on his blog!
That blog is open source and available at github.com/rauchg/blog. It is a great example of an application based on Next.js React framework. We can look at the source for the post - it is fetching the reading list data, then renders a number of Book
components on the page:
1 | import { |
Let's play with this source.
Testing The Book Component
How does the Book
component render when there is no image? Or no votes? Or a single vote? Or lots of votes? Answering all this questions might be hard by just looking at the source code. I know this is not an application meant to be money-making enterprise, but if we cannot easily test a non-production piece of code, would we know how to test the production code? Practice makes perfect, so let's practice.
I have forked the blog repo to github.com/bahmutov/blog-1 and cloned it locally. To write the tests I have installed cypress and cypress-react-unit-test. Recently we have added Next.js support, thus I wanted to export the Book
component and start testing.
1 | export function Book({ URL, Name, Image, ASIN, Votes }) { |
The test needs to mount the component and pass props - I grabbed them from the published blog post page.
1 | import { mount } from "cypress-react-unit-test"; |
The component renders in the browser controlled by Cypress and I can see it. The test can validate the result using all standard Cypress commands. Cypress is watching the spec file and every file it includes, thus every time I save the changed test the test reruns automatically. I can change the component's source code and the test reruns too. Thus I can play with the look and behavior of the component to verify it does its thing as expected. The video below shows the component rendering different vote tallies while I change the props; then I change the component's style to see how the votes badge looks in different colors.
Tip: since Cypress bundles the spec and the component, there is no server to start to run these component tests, unlike with the full end-to-end tests that need an url to load. Thus we run tests using simply yarn cypress open
to open Cypress GUI, or with yarn cypress run
to execute all tests headlessly.
Testing The Page Component
If we can mount the Book component and test it "live" like a real mini web application, what about the Page component? Why not? Let's write a component test to see how multiple books are displayed on the page. All we need is feed the exported Page (that's the default export) a list of books and let the test run.
1 | import { mount } from "cypress-react-unit-test"; |
The test loads and shows the blog post
Note: ignore the error message - I have opened an issue to find a way to fix this.
Do you see the tiny user interface problem with our Book component? The votes badge can split across the lines, and it should not. Here is a video of me fixing the issue using Cypress live reload to see the results.
Before you wave away the badge issue as an artifact of the test runner - no, it is real, you just need to find a browser width that shows it.
Test Realistically
A while ago someone named Guillermo Rauch (must be a namesake of that Guillermo who loves reading) tweeted the following about testing:
I have thought about this message for a while, and even responded in my conference talk at AssertJS, slides. Of course, my response is a lot less popular - I love my friends, who help me keep low profile by not trending my tweets too much 😋.
Let me explain the naming "unit" tests I used above.
In my opinion, the component tests in a web application are really exercising units of a web app interface, thus I called my library for mounting the component inside a real browser cypress-react-UNIT-test
, same for cypress-vue-unit-test
, cypress-svelte-unit-test
, etc. Now we are moving away from this nomenclature, since it is confusing the users, now we explicitly call such tests the "component tests". Still, with this in mind you can see the logic of my tweet above.
Today I would like to amend my response. Yes, test the application's behavior using end-to-end tests to verify the code has been built, configured, and deployed correctly. Testing the full preview deploys using Vercel is a good example I have described in the blog post develop-preview-test. By the way, Vercel is run by someone named Guillermo Rauch too - is this a super common name or what?!
The component testing I have shown in this blog post is not that different from end-to-end tests. The component is running as a mini web application in a real browser. You interact with the component using Cypress commands that use user interface without any knowledge of the underlying framework - similar to the way a real user would.
These e2e and component tests are realistic. And that's a very good thing.