使用上下文和反应挂钩测试组件

Test component with context and react hook

我有一个简单的仪表板组件,它依赖 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 Testing Library的推荐,我创建了一个测试-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 组件正在尝试使用 AuthContext.js 中的 useAuth,我如何才能强制呈现的 Dashboard 组件使用我在 [=21] 中发送的模拟数据=]文件?

不要创建新的上下文,而是使用 context/AuthContext 中的 AuthContext 作为 <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>
  );
};