两个反冲反应测试基于渲染值发生冲突
Two recoil react tests conflicting based off of rendered value
我有一个原子,它存储一个带有 authToken
和 username
字符串的对象。如果存在 authToken
,我想显示受保护的内容。如果没有,我想将用户重定向到登录页面。
测试:
- 不填充“authToken”,我们希望在呈现的结果中包含登录内容。
- 填充“authToken”,我希望呈现的结果中包含受保护的内容。
按顺序执行2、1就成功了。当按顺序 1,2 执行时,它们会失败。
我想知道我是否遗漏了什么或者这是一个已知问题。任何帮助将不胜感激。
原子
import { atom } from 'recoil';
type AuthDetail = {
authToken?: string;
userName?: string;
};
const authStateAtom = atom<AuthDetail>({
key: 'auth-state',
default: {},
});
export { authStateAtom };
export type { AuthDetail };
私有路由
import React, { FC } from 'react';
import { authStateAtom } from './atom';
import { Redirect, Route, RouteProps } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
const PrivateRoute: FC<RouteProps> = ({ children, ...rest }) => {
const authState = useRecoilValue(authStateAtom);
return (
<Route
{...rest}
render={({ location }) =>
authState.authToken ? (
children
) : (
<Redirect
to={{
pathname: '/login',
state: { from: location },
}}
/>
)}
/>
);
}
export { PrivateRoute };
测试
import { act, render, RenderResult } from '@testing-library/react';
import React from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import { MutableSnapshot, RecoilRoot } from 'recoil';
import { authStateAtom } from './atom';
import { PrivateRoute } from './PrivateRoute';
describe('PrivateRoute:', () => {
const protectedComponent = 'protected-component';
const loginComponent = 'login-component';
it('redirects to login if not authenticated', async () => {
let result: RenderResult;
await act(async () => {
result = render(
<RecoilRoot>
<Switch>
<Route exact={true} path="/login">
<div data-testid={loginComponent}>LOGIN COMPONENT</div>
</Route>
<PrivateRoute path="/">
<div data-testid={protectedComponent}>PROTECTED COMPONENT</div>
</PrivateRoute>
</Switch>
</RecoilRoot>,
{ wrapper: HashRouter },
)
});
// @ts-ignore
expect(result.getByTestId(loginComponent)).toBeInTheDocument();
// @ts-ignore
expect(result.queryByTestId(protectedComponent)).not.toBeInTheDocument();
});
it('renders the component if authenticated', async () => {
const initialRecoilState = (snap: MutableSnapshot) => {
snap.set(authStateAtom, { authToken: '1234' });
};
let result: RenderResult;
await act(async () => {
result = render(
<RecoilRoot initializeState={initialRecoilState}>
<Switch>
<Route exact={true} path="/login">
<div data-testid={loginComponent}>LOGIN COMPONENT</div>
</Route>
<PrivateRoute path="/">
<div data-testid={protectedComponent}>PROTECTED COMPONENT</div>
</PrivateRoute>
</Switch>
</RecoilRoot>,
{ wrapper: HashRouter },
);
});
// @ts-ignore
expect(await result.findByTestId(protectedComponent)).toBeInTheDocument();
// @ts-ignore
expect(result.queryByTestId(loginComponent)).not.toBeInTheDocument();
});
});
https://codesandbox.io/s/vigilant-shamir-27s35?file=/src/PrivateRoute.test.tsx
当您使用 <Router>
进行测试时,您的环境中的 window.history
可能会受到污染。如果您只 运行 一项测试,则另一项将通过。但是当你 运行 它们在一起时,你的第一个测试会将 URL 设置为 "/login"
。您将在第二次测试中开始 URL。
根据 react-router's testing guide,您应该用 <MemoryRouter>
包装您的组件以保护全球环境。
这是两个测试都通过的 codesandbox link:https://codesandbox.io/s/frosty-rhodes-xxuwk?file=/src/PrivateRoute.test.tsx
我有一个原子,它存储一个带有 authToken
和 username
字符串的对象。如果存在 authToken
,我想显示受保护的内容。如果没有,我想将用户重定向到登录页面。
测试:
- 不填充“authToken”,我们希望在呈现的结果中包含登录内容。
- 填充“authToken”,我希望呈现的结果中包含受保护的内容。
按顺序执行2、1就成功了。当按顺序 1,2 执行时,它们会失败。
我想知道我是否遗漏了什么或者这是一个已知问题。任何帮助将不胜感激。
原子
import { atom } from 'recoil';
type AuthDetail = {
authToken?: string;
userName?: string;
};
const authStateAtom = atom<AuthDetail>({
key: 'auth-state',
default: {},
});
export { authStateAtom };
export type { AuthDetail };
私有路由
import React, { FC } from 'react';
import { authStateAtom } from './atom';
import { Redirect, Route, RouteProps } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
const PrivateRoute: FC<RouteProps> = ({ children, ...rest }) => {
const authState = useRecoilValue(authStateAtom);
return (
<Route
{...rest}
render={({ location }) =>
authState.authToken ? (
children
) : (
<Redirect
to={{
pathname: '/login',
state: { from: location },
}}
/>
)}
/>
);
}
export { PrivateRoute };
测试
import { act, render, RenderResult } from '@testing-library/react';
import React from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import { MutableSnapshot, RecoilRoot } from 'recoil';
import { authStateAtom } from './atom';
import { PrivateRoute } from './PrivateRoute';
describe('PrivateRoute:', () => {
const protectedComponent = 'protected-component';
const loginComponent = 'login-component';
it('redirects to login if not authenticated', async () => {
let result: RenderResult;
await act(async () => {
result = render(
<RecoilRoot>
<Switch>
<Route exact={true} path="/login">
<div data-testid={loginComponent}>LOGIN COMPONENT</div>
</Route>
<PrivateRoute path="/">
<div data-testid={protectedComponent}>PROTECTED COMPONENT</div>
</PrivateRoute>
</Switch>
</RecoilRoot>,
{ wrapper: HashRouter },
)
});
// @ts-ignore
expect(result.getByTestId(loginComponent)).toBeInTheDocument();
// @ts-ignore
expect(result.queryByTestId(protectedComponent)).not.toBeInTheDocument();
});
it('renders the component if authenticated', async () => {
const initialRecoilState = (snap: MutableSnapshot) => {
snap.set(authStateAtom, { authToken: '1234' });
};
let result: RenderResult;
await act(async () => {
result = render(
<RecoilRoot initializeState={initialRecoilState}>
<Switch>
<Route exact={true} path="/login">
<div data-testid={loginComponent}>LOGIN COMPONENT</div>
</Route>
<PrivateRoute path="/">
<div data-testid={protectedComponent}>PROTECTED COMPONENT</div>
</PrivateRoute>
</Switch>
</RecoilRoot>,
{ wrapper: HashRouter },
);
});
// @ts-ignore
expect(await result.findByTestId(protectedComponent)).toBeInTheDocument();
// @ts-ignore
expect(result.queryByTestId(loginComponent)).not.toBeInTheDocument();
});
});
https://codesandbox.io/s/vigilant-shamir-27s35?file=/src/PrivateRoute.test.tsx
当您使用 <Router>
进行测试时,您的环境中的 window.history
可能会受到污染。如果您只 运行 一项测试,则另一项将通过。但是当你 运行 它们在一起时,你的第一个测试会将 URL 设置为 "/login"
。您将在第二次测试中开始 URL。
根据 react-router's testing guide,您应该用 <MemoryRouter>
包装您的组件以保护全球环境。
这是两个测试都通过的 codesandbox link:https://codesandbox.io/s/frosty-rhodes-xxuwk?file=/src/PrivateRoute.test.tsx