Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to isolate tests in React Testing Library?

My tests are affecting each other. I'm using the default create-react-app setup with Typescript. All tests run fine individually but when I run all tests the last one fails (both in IntelliJ and npm test). The assertion that fails finds a value that was caused by the previous test. failing test

Now I have read articles such as Test Isolation with React but I am not sharing any values between my tests. I also read about the cleanUp function and tried adding beforeEach(cleanup) and beforeAll(cleanUp), but I didn't found a working solution yet besides putting each test in a separate file. I feel the solution should be pretty simple.

I've quickly generated a create-react-app with TypeScript to reproduce the issue in a small as possible project: https://github.com/Leejjon/breakingtests

My App.tsx

import React from 'react';
import './App.css';
import {BrowserRouter, Link, Route} from 'react-router-dom';

const About: React.FC = () => {
    return (
        <div>
            <h1 id="pageHeader">About page</h1>
            <p>This is the about page</p>
        </div>
    );
};

const Home: React.FC = () => {
    return (
        <div>
            <h1 id="pageHeader">Home page</h1>
            <p>This is the home page</p>
        </div>
    );
};

const News: React.FC = () => {
    return (
        <div>
            <h1 id="pageHeader">News page</h1>
            <p>This is the news page</p>
        </div>
    );
};

const App: React.FC = () => {
    return (
        <div className="App">
            <BrowserRouter>
                <Link id="linkToHome" to="/">Home</Link><br/>
                <Link id="linkToNews" to="/news">News</Link><br/>
                <Link id="linkToAbout" to="/about">About</Link>

                <Route exact path="/" component={Home}/>
                <Route exact path="/news" component={News}/>
                <Route exact path="/about" component={About}/>
            </BrowserRouter>
        </div>
    );
};


export default App;

My App.test.tsx:

import React from 'react';
import {render, fireEvent, waitForElement} from '@testing-library/react';
import App from './App';

describe('Test routing', () => {
    test('Verify home page content', () => {
        const {container} = render(<App/>);
        const pageHeaderContent = container.querySelector("#pageHeader")
            ?.firstChild
            ?.textContent;
        expect(pageHeaderContent).toMatch('Home page');
    });

    test('Navigate to news', async () => {
        const {container} = render(<App/>);

        const pageHeaderContent = container.querySelector("#pageHeader")
            ?.firstChild
            ?.textContent;
        expect(pageHeaderContent).toMatch('Home page');

        const linkToNewsElement: Element = (container.querySelector('#linkToNews') as Element);
        fireEvent.click(linkToNewsElement);
        const pageHeaderContentAfterClick = await waitForElement(() => container.querySelector('#pageHeader')?.firstChild?.textContent);
        expect(pageHeaderContentAfterClick).toMatch('News page');
    });

    test('Navigate to about', async () => {
        const {container} = render(<App/>);

        const pageHeaderContent = container.querySelector("#pageHeader")
            ?.firstChild
            ?.textContent;
        expect(pageHeaderContent).toMatch('Home page');

        const linkToAboutElement: Element = (container.querySelector('#linkToAbout') as Element);
        fireEvent.click(linkToAboutElement);
        const pageHeaderContentAfterClick = await waitForElement(() => container.querySelector('#pageHeader')?.firstChild?.textContent);
        expect(pageHeaderContentAfterClick).toMatch('About page');
    });
});
like image 887
Leejjon Avatar asked Dec 23 '19 12:12

Leejjon


People also ask

How do I select options in React testing library?

Here's how you can do it: // highlight-start jest. mock("react-select", () => ({ options, value, onChange }) => { function handleChange(event) { const option = options. find( (option) => option.

Do you need Jest for React testing library?

However, there are some things you can do when configuring your testing framework to reduce some boilerplate. In these docs we'll demonstrate configuring Jest, but you should be able to do similar things with any testing framework (React Testing Library does not require that you use Jest).

Is React testing library same as Jest?

React Testing Library is not an alternative to Jest. Each performs a clear task, and you need them both to test your components. Jest is a test runner that finds tests, runs the tests, and determines whether the tests passed or failed. Additionally, Jest offers functions for test suites, test cases, and assertions.


1 Answers

I found out by adding console.log(document.location.href); that the location is not reset. Which makes sense.

The code below resets the url. I could enter any domain to fix my tests, for example http://blabla/ will also work.

beforeEach(() => {
    delete window.location;
    // @ts-ignore
    window.location = new URL('http://localhost/');
});

In TypeScript this gives an error: TS2739: Type 'URL' is missing the following properties from type 'Location': ancestorOrigins, assign, reload, replace. I didn't know how to fix this so I suppressed it it for now.

like image 117
Leejjon Avatar answered Sep 28 '22 05:09

Leejjon