如何在 React 测试库中隔离测试?
How to isolate tests in React Testing Library?
我的测试相互影响。我在 Typescript 中使用默认的 create-react-app 设置。所有测试 运行 都很好,但是当我 运行 所有测试最后一个失败时(在 IntelliJ 和 npm test
中)。失败的断言找到了由先前测试引起的值。
现在我已经阅读了 Test Isolation with React but I am not sharing any values between my tests. I also read about the cleanUp function 等文章并尝试添加 beforeEach(cleanup) 和 beforeAll(cleanUp),但是除了将每个测试放在一个单独的文件中之外,我还没有找到可行的解决方案。我觉得解决方案应该很简单。
我已经使用 TypeScript 快速生成了一个 create-react-app 以在尽可能小的项目中重现该问题:https://github.com/Leejjon/breakingtests
我的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;
我的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');
});
});
编辑:
cleanup 卸载使用渲染安装的 React 树,但不会从 stores/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)
我通过添加 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
。我不知道如何解决这个问题,所以我暂时抑制了它。
我的测试相互影响。我在 Typescript 中使用默认的 create-react-app 设置。所有测试 运行 都很好,但是当我 运行 所有测试最后一个失败时(在 IntelliJ 和 npm test
中)。失败的断言找到了由先前测试引起的值。
现在我已经阅读了 Test Isolation with React but I am not sharing any values between my tests. I also read about the cleanUp function 等文章并尝试添加 beforeEach(cleanup) 和 beforeAll(cleanUp),但是除了将每个测试放在一个单独的文件中之外,我还没有找到可行的解决方案。我觉得解决方案应该很简单。
我已经使用 TypeScript 快速生成了一个 create-react-app 以在尽可能小的项目中重现该问题:https://github.com/Leejjon/breakingtests
我的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;
我的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');
});
});
编辑:
cleanup 卸载使用渲染安装的 React 树,但不会从 stores/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)
我通过添加 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
。我不知道如何解决这个问题,所以我暂时抑制了它。