Woodlands Area Software Enthusiasts

woodlandstech.org

About me

Testing Frontend Applications

With React, Jest & react-testing-library

Tests

Programs that run small portions of our application

Increase confidence in your programs

Cheap way to prevent costly mistakes

Tests

    Represent additional code that we have to maintain

    Should increase developer productivity

    Should increase confidence in our code

    Should be easy to maintain

My situation

// square.js
const square = (n) => n * n;
// square.js
const square = (n) => n * n;
// square.test.js
describe("square", () => {
test("squares a number", () => {
expect(square(8)).toEqual(64);
});
});
let mockSquare;
describe("square", () => {
beforeEach(() => {
mockSquare = jest.fn(() => 64);
});
test("square of 8 equals 64", () => {
expect(mockSquare(8)).toEqual(64);
expect(mockSquare).toHaveBeenCalledTimes(1);
});
});

Now test this: <WikiSearch />

const square = (n) => n * n;
expect(square(8)).toEqual(64);

<WikiSearch />

react-testing-library

From Kent C. Dodds

Interact with frontend like a real user

Search through the DOM, don't take it apart

import React from 'react';
import { render } from 'react-testing-library';
import WikiSearch from './WikiSearch';
describe('WikiSearch', () => {
test('render', () => {
render(<WikiSearch />);
});
});
test('fetches search results from Wikipedia', async () => {
const { getByPlaceholderText, getByText } = render(<WikiSearch />);
const input = getByPlaceholderText('Enter search...');
fireEvent.input(input, { target: { value: 'George Washington' } });
const btn = getByText('Search Wikipedia');
fireEvent.click(btn);
await waitForElement(() => getByText('George Washington Carver'));
});
> jest --coverage

 PASS  ./WikiSearch.test.js
 PASS  ./square.test.js
---------------|----------|----------|----------|----------|-------------------|
File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files      |      100 |      100 |      100 |      100 |                   |
 WikiSearch.js |      100 |      100 |      100 |      100 |                   |
---------------|----------|----------|----------|----------|-------------------|

What we didn't care about

DOM structure

State & methods

Mocking

Mocking APIs: a little goes a long way

Don't mock frontend stuff, just actually use it

getByTestId

<div onClick={something} data-testid="my-div">

getByTestId('my-div');

That was a little contrived

React components are pretty testable

Unidirectional ↣ data ↣ flow

How this works in practice

Test:application code is at about 1:5

Coverage: 60%

Did this in about a week

Frontend testing principles

    Think of your components & tests in terms of inputs and outputs

    Try to interact with your components like a user

    Don't test implementation details

    Don't mock stuff when it's trivial to use the real thing

What questions do you all have?