我有一个带有受保护路由组件的 React 应用程序:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AuthConsumer } from '../../Utils/contexts/AuthContext.js';
const ProtectedRoute = ({ component: Component, ...rest }) => {
return (
<AuthConsumer>
{({ currentUser }) => ( <Route {...rest} render={
props => {
if ({ currentUser }) {
return <Component {...rest} {...props} />
} else {
return <Redirect to={
{
pathname: '/unauthorized',
state: {
from: props.location
}
}
} />
}
}
} />)}
</AuthConsumer>
)
}
export default ProtectedRoute;
ProtectedRoute 使用授权上下文:
import React, { useEffect, useState } from 'react';
import firebase from '../firebase';
const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
const [ currentUser, setCurrentUser ] = useState(null);
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => setCurrentUser(user));
}, [currentUser]);
return (
<AuthContext.Provider
value={{
currentUser
}}
>
{children}
</AuthContext.Provider>
);
};
export const AuthConsumer = AuthContext.Consumer
我想用 jest 和 react-testing-library 测试当 currentUser 存在时路由是否有效,当一个不存在时路由是否有效。到目前为止,我的测试是:
import React from 'react'
import Info from '../../pages/Info/info'
import {
render,
screen,
fireEvent,
} from '../../Utils/test-utils/testing-library-utils'
import ProtectedRoute from './protectedRoute'
jest.mock('../../pages/Info/info', () => {
return jest.fn(() => null)
})
const AuthContext = React.createContext()
const currentUser = {
uid: 1,
}
describe('protected route works with authenticated users', () => {
test('can login when user is authenticated', () => {
render(
<AuthContext.Provider
value={{
currentUser,
}}>
<ProtectedRoute component={<Info />} />
</AuthContext.Provider>
)
const returnedRoute = screen.queryByTestId('currentuser-valid')
console.log('RETURNED ROUTE', returnedRoute)
expect(returnedRoute).toBeNull()
})
})
我似乎无法将伪造的 currentUser 对象传递给 ProtectedRoute - 我总是收到“类型错误:无法解构 'undefined' 或 'null' 的属性 currentUser
。”
如何模拟 AuthContext?我该怎么做才能将有效或无效的值作为 currentUser 传递给它,这样我才能使测试通过或失败?
答案 0 :(得分:0)
AuthContext
的提供者和消费者应该是一对。您不应在测试用例中创建新上下文。在 AuthContext
组件的文件和测试文件中继续使用相同的 ProtectedRoute
。
例如
ProtectedRoute.tsx
:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AuthConsumer } from './AuthContext';
const ProtectedRoute = ({ component: Component, ...rest }) => {
return (
<AuthConsumer>
{({ currentUser }) => (
<Route
{...rest}
render={(props) => {
console.log('currentUser: ', currentUser);
if (currentUser) {
return <Component {...rest} {...props} />;
} else {
return (
<Redirect
to={{
pathname: '/unauthorized',
state: {
from: props.location,
},
}}
/>
);
}
}}
/>
)}
</AuthConsumer>
);
};
export default ProtectedRoute;
AuthContext.tsx
:
import React, { useState } from 'react';
interface Context {
currentUser: { uid: number } | null;
}
export const AuthContext = React.createContext<Context>({ currentUser: null });
export const AuthProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
return <AuthContext.Provider value={{ currentUser }}>{children}</AuthContext.Provider>;
};
export const AuthConsumer = AuthContext.Consumer;
Info.tsx
:
import React from 'react';
export function Info() {
return <div>info</div>;
}
ProtectedRoute.test.tsx
:
import React from 'react';
import { render, screen } from '@testing-library/react';
import ProtectedRoute from './protectedRoute';
import { AuthContext } from './AuthContext';
import { MemoryRouter } from 'react-router-dom';
import { Info } from './Info';
const currentUser = { uid: 1 };
describe('protected route works with authenticated users', () => {
test('can login when user is authenticated', () => {
render(
<AuthContext.Provider value={{ currentUser }}>
<MemoryRouter initialEntries={['/']}>
<ProtectedRoute component={Info} />
</MemoryRouter>
</AuthContext.Provider>
);
expect(screen.queryByTestId('protected-component')).toBeDefined();
});
});
测试结果:
PASS examples/67184212/ProtectedRoute.test.tsx (7.628 s)
protected route works with authenticated users
✓ can login when user is authenticated (73 ms)
console.log
currentUser: { uid: 1 }
at render (examples/67184212/ProtectedRoute.tsx:12:21)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 86.96 | 50 | 80 | 85 |
AuthContext.tsx | 71.43 | 100 | 0 | 66.67 | 9-10
Info.tsx | 100 | 100 | 100 | 100 |
ProtectedRoute.tsx | 92.31 | 50 | 100 | 90.91 | 16
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.169 s
包版本:
"@testing-library/react": "^11.2.2",
"react": "^16.14.0",
"react-router-dom": "^5.2.0",