reactjs - 使用上下文和反应钩子测试组件
问题描述
我有一个简单的仪表板组件,它依赖于 React 上下文来管理身份验证。它包含一个自定义钩子useAuth
来提取当前用户以及与身份验证相关的功能:登录、注销等。
这是上下文文件AuthContext.js
::
import React, { createContext, useContext, useState, useEffect } from "react";
import { auth } from "../config/firebase";
const AuthContext = createContext();
export function useAuth() {
return useContext(AuthContext);
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
const [loading, setLoading] = useState(true);
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password);
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password);
}
function logout() {
return auth.signOut();
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setCurrentUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
const value = {
currentUser,
signup,
login,
logout,
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
这是Dashboard.js
组件:
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { useAuth } from "../context/AuthContext";
export default function Dashboard() {
const { currentUser, logout } = useAuth();
const [error, setError] = useState("");
const history = useHistory();
const handleLogout = async () => {
setError("");
try {
await logout();
history.push("/login");
} catch (e) {
setError(e.message);
}
};
return (
<div>
{error && <p>{error}</p>}
<h1>This is the Dashboard</h1>
<h5>Email: {currentUser.email}</h5>
<button onClick={handleLogout} type="button">
Logout
</button>
</div>
);
}
根据React 测试库的推荐,我创建了一个 test-utils.js 文件:
import React, { createContext } from "react";
import { render } from "@testing-library/react";
import { BrowserRouter as Router } from "react-router-dom";
const AuthContext = createContext();
const currentUser = {
email: "abc@abc.com",
};
const signup = jest.fn();
const login = jest.fn();
const logout = jest.fn();
const AllTheProviders = ({ children }) => {
return (
<Router>
<AuthContext.Provider value={{ currentUser, signup, login, logout }}>
{children}
</AuthContext.Provider>
</Router>
);
};
const customRender = (ui, options) => {
render(ui, { wrapper: AllTheProviders, ...options });
};
export * from "@testing-library/react";
export { customRender as render };
但是,运行时Dashboard.test.js
出现错误
TypeError: Cannot destructure property 'currentUser' of '((cov_5mwatn2cf(...).s[0]++) , (0 , _AuthContext.useAuth)(...))' as it is undefined.
4 |
5 | export default function Dashboard() {
> 6 | const { currentUser, logout } = useAuth();
| ^
7 | const [error, setError] = useState("");
8 | const history = useHistory();
import React from "react";
import Dashboard from "./Dashboard";
import { act, render, screen } from "../config/test-utils-dva";
beforeEach(async () => {
await act(async () => {
render(<Dashboard />);
});
});
test("displays dashboard", () => {
expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
});
我认为这是因为 Dashboard 组件正在尝试使用useAuth
from AuthContext.js
,如何强制渲染的 Dashboard 组件使用我在test-utils.js
文件中发送的模拟数据?
解决方案
不要创建新的上下文,而是使用AuthContext
from context/AuthContext
for <AuthContext.Provider>
,因为这是钩子使用的上下文。
因此,在 中AuthContext.js
,导出上下文实例:
export const AuthContext = createContext();
然后,在您的test-util.js
文件中,而不是再次调用createContext
(这将创建一个完全独立的上下文实例 - 即使它们存储在具有相同名称的变量中,上下文也不相同!),只需导入先前导出的实例:
import { AuthContext } from "../context/AuthContext";
const AllTheProviders = ({ children }) => {
return (
<Router>
<AuthContext.Provider value={{ currentUser, signup, login, logout }}>
{children}
</AuthContext.Provider>
</Router>
);
};
推荐阅读
- sql - 如果记录存在,我可以更新它,如果不存在,我可以在 SQL Server 的单个查询中为多行插入它吗?
- java - Jmeter - 使用 HTTP 请求在 Jmeter 中构造 URL
- r - 将特定行转换为 R 中的新列
- sql - 如何将 Oracle SQL 中的存储过程从一个模式移动到另一个模式?
- javascript - 如何使用 Nextjs 显示 mp4 文件格式?
- callback - 在 Slack 中传递没有附件的 callback_id
- angular - 动态改变显示的角度子组件
- python - 在 docker 上部署一个 REACT 和 Flask 应用程序
- python - 使用基于列表的视图时出现此错误。没有这样的表:first_app_theprofessionalresources
- javascript - Javascript 数组迭代器对象如何工作?