使用带有 AuthContext 的 React 测试库测试组件

Testing components using react testing library with AuthContext

我有一个跟进问题:

最上面的答案说,不要创建新的上下文,而是使用 context/AuthContext 中的 AuthContext for ,因为这是挂钩使用的上下文。

我对这到底意味着什么感到困惑(本来可以发表评论,但还没有足够的代表发表评论)--有人可以通过代码沙箱向我展示吗?

谢谢!

这只是说要使用自定义 hook/component 正在使用的相同 React 上下文,而不是其他一些“随机”身份验证提供程序。

示例身份验证上下文:

export const useAuth = () =>  useContext(AuthContext);

export const AuthProvider = ({ children }) => {
  const [currentUser, setCurrentUser] = useState();
  const [loading, setLoading] = useState(true);

  const signup = (email, password) => {
    return auth.createUserWithEmailAndPassword(email, password);
  }

  const login = (email, password) => {
    return auth.signInWithEmailAndPassword(email, password);
  }

  const logout = () => auth.signOut();

  ...

  const value = {
    currentUser,
    signup,
    login,
    logout,
  };

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

消费组件示例:

import { useAuth } from "../context/AuthContext"; // <-- specific context

export default function Dashboard() {
  const { currentUser, logout } = useAuth(); // <-- specific context

  ...

  return (
    <div>
      ...
    </div>
  );
}

特定的 AuthProvider 组件需要出现在 React 树中的组件上方,以提供上下文和状态。

例如,如果您像单元测试一样创建另一个 React 上下文提供程序:

const AuthContext2 = createContext(); // AuthContext2 to disambiguate it here

并将组件包装在 AuthContext2.Provider 中,然后组件仍在导入和使用从上面的代码导出的 AuthProvider

答案是还要导入 AuthProvider 并为单元测试包装它,而不是创建一个全新的上下文。

import { AuthProvider } from "../context/AuthContext";

const AllTheProviders = ({ children }) => {
  return (
    <Router>
      <AuthProvider>
        {children}
      </AuthProvider>
    </Router>
  );
};

const customRender = (ui, options) => {
  render(ui, { wrapper: AllTheProviders, ...options });
};

更新

where would I feed in mock values?

重构上下文提供者,您必须使用一个“初始状态”道具,该道具用于设置上下文使用的初始状态。重构自定义测试渲染器以获取额外的参数并将它们传递给包装器。

@musicformellons

could you maybe make that refactor part of the answer...?!

当然,应该包括在内。

export const AuthProvider = ({ children, initialState }) => {
  const [currentUser, setCurrentUser] = useState(initialState.currentUser);
  
  ...

  const value = {
    currentUser,
    signup,
    login,
    logout,
  };

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

测试

import { AuthProvider } from "../context/AuthContext";

const AllTheProviders = ({ children }) => {
  return (
    <Router>
      <AuthProvider initialState={authState}>
        {children}
      </AuthProvider>
    </Router>
  );
};

const customRender = (ui, options, initialState) => {
  render(
    ui,
    {
      wrapper: props => (
        <AllTheProviders {...props} initialState={initialState} />
      ),
      ...options,
    },
  );
};