【问题标题】:How to isolate tests in React Testing Library?如何隔离 React 测试库中的测试?
【发布时间】:2019-12-23 12:15:56
【问题描述】:

我的测试相互影响。我正在使用带有 Typescript 的默认 create-react-app 设置。所有测试单独运行良好,但是当我运行所有测试时,最后一个测试失败(在 IntelliJ 和npm test 中)。失败的断言会找到一个由先前测试引起的值。

现在我已经阅读了诸如Test Isolation with React 之类的文章,但我没有在我的测试之间共享任何值。我还阅读了the cleanUp function 并尝试添加 beforeEach(cleanup) 和 beforeAll(cleanUp),但除了将每个测试放在单独的文件中之外,我还没有找到可行的解决方案。我觉得解决方案应该很简单。

我已经使用 TypeScript 快速生成了一个 create-react-app,以便在一个尽可能小的项目中重现该问题:https://github.com/Leejjon/breakingtests

我的应用程序.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;

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

【问题讨论】:

    标签: reactjs typescript jestjs create-react-app react-testing-library


    【解决方案1】:

    我通过添加console.log(document.location.href); 发现该位置未重置。这是有道理的。

    下面的代码重置了 url。我可以输入任何域来修复我的测试,例如http://blabla/ 也可以。

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

    在 TypeScript 中,这会产生错误:TS2739: Type 'URL' is missing the following properties from type 'Location': ancestorOrigins, assign, reload, replace。我不知道如何解决这个问题,所以我暂时压制了它。

    【讨论】:

    • 你可以选择window.location.href = 'https://localhost/';
    【解决方案2】:

    编辑:

    cleanup 卸载使用 render 装载的 React 树,但不会从 store/reducers 重置状态。我针对这种情况采取的解决方案是在我的商店中创建一个重置函数,并在每次测试开始时调用它。

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

    并在您的测试文件中调用它

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

    如果您使用的是 mocha、Jest 或 Jasmine,清理工作将自动完成,但您需要将 render 放入 beforeEach 以便为每次测试重新创建它。

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

    如果你使用其他测试框架,你需要像这样手动cleanup

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 2011-09-12
    • 2018-12-04
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多