12

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');
    });
});

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

1 Comment

You may want to go with window.location.href = 'https://localhost/';
2

EDIT:

cleanup Unmounts React trees that were mounted with render, but doesn't reset state from stores/reducers. The solution I took for this situation was to create a reset function in my store and call it at the beginning of each test.

resetStore: () => {
   set(initialState);
},

and call it in your test file

beforeEach(() => {
   resetStore();
});

If you're using mocha, Jest, or Jasmine, the cleanup will be done automatically, but you need to put your render in a beforeEach to recreate it for every test.

let container;

beforeEach(() => {
  const app = render(<App/>);
  container = app.container
});

If you use another testing framework, you'll need to cleanup manually like so

import { cleanup, render } from '@testing-library/react'
import test from 'ava'

test.afterEach(cleanup)

3 Comments

I have tried your solution (pastebin.com/hxwCHVPm) but I am still getting the same error. About the second thing, I don't use 'ava'
Cleanup happens automatically and you don't need to worry about it kentcdodds.com/blog/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.