如何使用 Jest 模拟反应自定义挂钩 return 值作为模块
How to mock react custom hook return value as a module with Jest
我需要在对 React 组件进行单元测试时模拟我的自定义挂钩。我已经阅读了一些 Whosebug 的答案,但没有成功地正确实施它。
我不能在不模拟的情况下使用 useAuth,因为它取决于服务器请求,而且我目前只编写单元测试。
//useAuth.js - custom hook
const authContext = createContext();
function useProvideAuth() {
const [accessToken, setAccessToken] = useState('');
const [isAuthenticated, setAuthenticated] = useState(
accessToken ? true : false
);
useEffect(() => {
refreshToken();
}, []);
const login = async (loginCredentials) => {
const accessToken = await sendLoginRequest(loginCredentials);
if (accessToken) {
setAccessToken(accessToken);
setAuthenticated(true);
}
};
const logout = async () => {
setAccessToken(null);
setAuthenticated(false);
await sendLogoutRequest();
};
const refreshToken = async () => {
const accessToken = await sendRefreshRequest();
if (accessToken) {
setAccessToken(accessToken);
setAuthenticated(true);
} else setAuthenticated(false);
setTimeout(async () => {
refreshToken();
}, 15 * 60000 - 1000);
};
return {
isAuthenticated,
accessToken,
login,
logout
};
}
export function AuthProvider({ children }) {
const auth = useProvideAuth();
return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}
AuthProvider.propTypes = {
children: PropTypes.any
};
const useAuth = () => {
return useContext(authContext);
};
export default useAuth;
我写的测试
//mainPage.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import Main from '../main/mainPage';
describe('Main when !isAuthenticated', () => {
beforeEach(() => {
jest.mock('../auth/useAuth', () => {
const originalModule = jest.requireActual('../auth/useAuth');
return {
__esModule: true,
...originalModule,
default: () => ({
isAuthenticated: false,
login: jest.fn,
logout: jest.fn
})
};
});
});
afterEach(() => {
jest.resetModules();
});
it('displays image and login form', () => {
render(<Main />);
const image = screen.getByRole('img');
const form = document.querySelector('[data-testid=loginForm]');
expect(image).toBeInTheDocument();
expect(form).toBeInTheDocument();
});
});
但是,我得到了这个错误。
TypeError: Cannot read properties of undefined (reading 'isAuthenticated')
7 |
8 | function Main() {
> 9 | const isAuthenticated = useAuth().isAuthenticated;
| ^
10 | const location = useLocation();
11 |
12 | if (isAuthenticated)
at Main (src/main/mainPage.js:9:26)
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:14985:18)...
我也一直在尝试使用 spyOn,但没有任何帮助。我到底需要更改什么才能使模拟正常工作?
模拟应该发生在任何描述块之前:
import React from 'react';
import { render, screen } from '@testing-library/react';
import Main from '../main/mainPage';
jest.mock('../auth/useAuth', () => {
const originalModule = jest.requireActual('../auth/useAuth');
return {
__esModule: true,
...originalModule,
default: () => ({
isAuthenticated: false,
login: jest.fn,
logout: jest.fn
})
};
});
describe('Main when !isAuthenticated', () => {
我需要在对 React 组件进行单元测试时模拟我的自定义挂钩。我已经阅读了一些 Whosebug 的答案,但没有成功地正确实施它。
我不能在不模拟的情况下使用 useAuth,因为它取决于服务器请求,而且我目前只编写单元测试。
//useAuth.js - custom hook
const authContext = createContext();
function useProvideAuth() {
const [accessToken, setAccessToken] = useState('');
const [isAuthenticated, setAuthenticated] = useState(
accessToken ? true : false
);
useEffect(() => {
refreshToken();
}, []);
const login = async (loginCredentials) => {
const accessToken = await sendLoginRequest(loginCredentials);
if (accessToken) {
setAccessToken(accessToken);
setAuthenticated(true);
}
};
const logout = async () => {
setAccessToken(null);
setAuthenticated(false);
await sendLogoutRequest();
};
const refreshToken = async () => {
const accessToken = await sendRefreshRequest();
if (accessToken) {
setAccessToken(accessToken);
setAuthenticated(true);
} else setAuthenticated(false);
setTimeout(async () => {
refreshToken();
}, 15 * 60000 - 1000);
};
return {
isAuthenticated,
accessToken,
login,
logout
};
}
export function AuthProvider({ children }) {
const auth = useProvideAuth();
return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}
AuthProvider.propTypes = {
children: PropTypes.any
};
const useAuth = () => {
return useContext(authContext);
};
export default useAuth;
我写的测试
//mainPage.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import Main from '../main/mainPage';
describe('Main when !isAuthenticated', () => {
beforeEach(() => {
jest.mock('../auth/useAuth', () => {
const originalModule = jest.requireActual('../auth/useAuth');
return {
__esModule: true,
...originalModule,
default: () => ({
isAuthenticated: false,
login: jest.fn,
logout: jest.fn
})
};
});
});
afterEach(() => {
jest.resetModules();
});
it('displays image and login form', () => {
render(<Main />);
const image = screen.getByRole('img');
const form = document.querySelector('[data-testid=loginForm]');
expect(image).toBeInTheDocument();
expect(form).toBeInTheDocument();
});
});
但是,我得到了这个错误。
TypeError: Cannot read properties of undefined (reading 'isAuthenticated')
7 |
8 | function Main() {
> 9 | const isAuthenticated = useAuth().isAuthenticated;
| ^
10 | const location = useLocation();
11 |
12 | if (isAuthenticated)
at Main (src/main/mainPage.js:9:26)
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:14985:18)...
我也一直在尝试使用 spyOn,但没有任何帮助。我到底需要更改什么才能使模拟正常工作?
模拟应该发生在任何描述块之前:
import React from 'react';
import { render, screen } from '@testing-library/react';
import Main from '../main/mainPage';
jest.mock('../auth/useAuth', () => {
const originalModule = jest.requireActual('../auth/useAuth');
return {
__esModule: true,
...originalModule,
default: () => ({
isAuthenticated: false,
login: jest.fn,
logout: jest.fn
})
};
});
describe('Main when !isAuthenticated', () => {