When you’re learning to become a front-end web developer, there comes a time when you’ll want to gain experience building web apps using a popular library or framework. But there are many front-end web technologies to choose from — including...
I can guess what you are thinking: another React testing library? So many have already been covered here on CSS-Tricks (heck, I’ve already posted one covering Jest and Enzyme) so aren’t there already enough options to go around?
But react-testing-library is not just another testing library. It’s a testing library, yes, but one that’s built with one fundamental principle that separates it from the rest.
The more your tests resemble the way your software is used, the more confidence they can give you.
It tries to address tests for how a user will use your application. In fact, it’s done in such a way that tests won’t break even when you refactor components. And I know that’s something we’ve all run into at some point in our React journey.
We’re going to spend some time writing tests together using react-testing-library for a light to-do application I built. You can clone the repo locally:
In case you’re wondering why Jest is in there, we’re using it for assertion. Create a folder called __test__ inside the src directory and create a new file called App.test.js.
Taking snapshots
Snapshot tests keep a record of tests that have been performed on a tested component as a way to visually see what’s changes between changes.
When we first run this test, we take the first snapshot of how the component looks. As such, the first test is bound to pass because, well, there’s no other snapshot to compare it to that would indicate something failed. It only fails when we make a new change to the component by adding a new element, class, component, or text. Adding something that was not there when the snapshot was either created or last updated.
The snapshot test will be the first test we will be writing here. Let’s open the App.test.js file and make it look like this:
This imports the necessary packages we are using to write and run the tests. render is used to display the component we want to test. We make use of cleanup to clear things out after each test runs — as you can see with the afterEach(cleanup) line.
Using asFragment, we get a DocumentFragment of the rendered component. Then we expect it to match the snapshot that had been created.
Let’s run the test to see what happens:
## yarn
yarn test
## npm
npm test
As we now know, a snapshot of the component gets created in a new folder called __snapshots__ inside the __tests__ directory if this is our first test. We actually get a file called App.test.js.snap in there that will look like this:
Our app includes two to-do items that display by default the first time the app runs. We want to make sure that they do, in fact, show up by default on the first app run so, to test this, we have to target the unordered list (<ul>) and check the length. We expect the length to be equal to two — the number of items.
We’re making use of getByTestId in that snippet to extract the test IDs from the App component. We then set todoList to target the todos-ul element. That’s what should return as two.
Using what we’ve learned so far, see if you can write a test to assert that a user can enter values in the input field. Here are the things you’ll want to do:
Get the input field
Set a value for the input field
Trigger a change event
Assert that the input field has its value as the one you set for it in Step 2
Don’t peek at my answer below! Take as much time as you need.
Still going? Great! I’ll go grab some coffee and be right back.
Mmm, coffee. ☕️
Oh, you’re done! You rock. Let’s compare answers. Mine looks like this:
Using getByTestId, I am able to extract the test IDs in the application. Then I create a variable which is set to the string Learn React, and make it the value of the input field. Next, I obtain the input field using its test ID and fire the change event after setting the value of the input field. With that done, I assert that the value of the input field is indeed Learn React.
Does that check out with your answer? Leave a comment if you have another way of going about it!
Next, let’s test that we can add a new to-do item. We’ll need to get the input field, the button for adding new items and the unordered list because those are all of the elements needed to create an new item.
We set a value for the input field and then trigger a button click to add the task. We’re able to do this by obtaining the button using getByText — by triggering a click event on the DOM element with the text Add Task, we should be able to add a new to-do item.
Let’s assert that the number of children (list items) in unordered list element is equal to three. This assumes that the default tasks are still in tact.
That said, this is just one testing resource for React. There are others, of course, but hopefully this is one you’re interested in trying out now that you’ve seen a bit of it but use what’s best for your project, of course.
The Airtable web app is pretty neat. You can use it like a spreadsheet but it’s useful for all sorts of other things too. The neatest thing about it for me is that it has an API so that you can treat it like a database.
I’ve been thinking about making weekly notes for the different teams I work with at Gusto to read about what the design systems team is working on, things we've fixed, and any bugs we've encountered during that might impact other designers and engineers across our organization. I’ve spent a couple of hours thinking about how we might use Airtable to collect a whole bunch of data and then use its API to extract that info and show it in a web app.
Here’s an example of what we’ll end up building, which is basically a React web app that’s using Airtable as a nifty sorta CMS:
To get started, we have to head on over to the command line and run the following (but first make sure npm is installed):
npx create-react-app airtable-test
This will create a new directory called airtable-test which is where we’ll be making our little React app. If we run yarn start in the command line after that’s finished installing, then we’ll see the default page for the project:
And, if we open up src/App.js in that airtable-test directory, we can see how this page is being rendered with React:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit src/App.js and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</header>
</div>
);
}
}
export default App;
Now that we have React up and running, we can go ahead and install airtable in the command line which will let us interact with the Airtable API:
npm i airtable
Once we’ve done that, we’ll need to create an Airtable account and create a project. We should wind up with something like this spreadsheet:
Now we can then head to airtable.com/api and select our project so that is serves as data we're pulling from. In this case, I selected “Design Systems Projects” which you can see right at the bottom here:
This will send us to a handy docs website that gives us an incredibly easy to read API for our specific project! Scrolling down we’ll find our API key which we’ll need to access this data as well as a ton of examples that we can use to manipulate the data we get back:
Let's head back to App.js in our airtable-test directory, delete all the code in that file, and replace it with the following:
import React, { Component } from 'react';
import Airtable from 'airtable';
const base = new Airtable({ apiKey: 'XXXXXXXXXXX' }).base('XXXXXXXXXXX');
Make sure to replace those Xs with the details that you can see in that Airtable API doc we just opened. But now that we’ve done all the setup, we can finally get around to creating our interface by calling data from our spreadsheet.
In App.js we can start to construct the App component:
All this will do for now is setup the app’s state and then render “Hello” on the page. Next up, we’ll be add each record from Airtable to that state.
First thing that’s important to note below: in componentDidMount() we’ll be selecting Updates which is just a way of telling Airtable that we want the spreadsheet called Updates. Make sure that this name is the same name as the spreadsheet. We’ll also be looping through all the records, or rows, of our table in that function too:
fetchNextPage() is the Airtable API’s way of giving us the next record in our spreadsheet and it’s neat that it will keep going until there are no more records. Again, we’re not doing anything with that data yet; we only want to make sure everything is working correctly at this point.
Open up the console in DevTools and we should see something like this:
Array(4) [ {…}, {…}, {…}, {…} ]
And if we dive through each of the objects in this array, then we should find all the data from the spreadsheet! Doing this bit always feels like magic to me.
Anyway, next up we can update our render() function like so:
We’re going to be looping through the state that we setup earlier and then rendering the record.fields[] for each column in our spreadsheet. We have a Date, UI Kit, and Component Library column, and once we’ve updated our App.js with the code above, we should see all the content from our spreadsheet!
It’s like magic! But why does this data look so weird? Well, it’s because I wanted to write Markdown in each cell, so now we’ll need to use a parser to convert that data into good ol’ fashioned HTML. First, we need to head back to the command line though:
npm i showdown
showdown will help us parse all that Markdown we’ve written in our Airtable spreadsheet. After installing it, we only need to import it at the top of our App.js file, like this:
import showdown from 'showdown';
const markdownConverter = new showdown.Converter();
After the componentDidMount() function, we can create another function that will create our HTML using showdown:
We’re doing a couple of new things here: we’re using dangerouslySetInnerHTML in each div which, in turn, uses our createHTML function to convert the data from each column (specifically, the UI Kit and Component Library columns). We’re also converting the dates of each row into headings to make things a bit easier to read.
And with that we’re pretty much done! Here’s the final App.js:
There’s still a ton of updates we could make to improve things. I took a first pass at styling, but we probably want to do things like improve the date format and maybe have some kind of indication as to which updates refer to which rows in the spreadsheet. Maybe we could even toggle showing which information to show depending on whether you’re a designer or engineer.
Anyway! I think this is a good start to getting to grips with the Airtable API and I’d love to hear about how you use it in the comments below.