如何测试从 firestore 获取数据的 React 组件?

How can I test react component that fetches the data from firestore?

有人告诉我,我们应该使用模拟数据,而不是与我们的真实数据库资源交互。

我也被告知我应该“模拟 firebase 对象和 return 假结果”,但是我在哪里模拟 firebase 对象,是我的吗实际组件还是在我的测试文件中以及我如何实际模拟它?

这是我的代码:

// just a hook that fetches current user data

export const useGetCurrentUsersProfile = () => {
  const userInfoRef = doc(firestore, "users", auth.currentUser?.uid ?? "_STUB_");
  return useFirestoreDocument(
    ["userInfo"],
    userInfoRef,
    {
      subscribe: false,
    },
    {
      select: (data) => {
        const currentUsersProfile = data.data() as UserInfo;
        return currentUsersProfile;
      },
      enabled: !!auth.currentUser?.uid,
    }
  );
};

我使用该钩子获取数据的 React 组件:

import React from "react";
import { useGetCurrentUsersProfile } from "../app/utilityfunctions";

function Siuu() {
  const { data: currentUser } = useGetCurrentUsersProfile();
  return (
    <div>
      <div>{currentUser?.name}</div>
    </div>
  );
}

export default Siuu;
/** @jest-environment jsdom */

import { render, screen } from "@testing-library/react";
import Siuu from "./siuu";

test("renders component", () => {
  render(<Siuu />);
  const randomElement = screen.getByText(/Jack/i);
  expect(randomElement).toBeInTheDocument();
});

如果我只是想 return 从我的钩子中获取这些数据,我在哪里以及如何模拟它:

{姓名:“杰克”,电子邮件:“杰克@gmail.com”}

模拟是在测试代码中完成的,而不是在真正的应用程序代码中。

意思是:你创建了一个东西的假版本,这样当测试让应用程序做事时,就不会使用真实的东西。 Jest 有工具可以帮助您做到这一点。

在您的情况下,您应该模拟的似乎是 doc and/or useFirestoreDocument 函数。您的代码示例没有说明这两个东西来自哪里,而且我不知道 firestore,所以我假设它们都是从单个“some-firestore-pkg”包中导入的,如下所示:import { doc, useFirestoreDocument } from 'some-firestore-pkg'

最简单的方法是专门为这个测试创建一个 one-off 模拟,但是如果这个 firestore 东西是通过应用程序使用的,而你想为其余部分编写测试,你会想要阅读了解 Jest 提供的用于创建可重用模拟的工具和模式。对于这个答案,我将使用 one-off 模拟来完成。

/*
    STEP 1: Import some-firestore-pkg package so we can manipulate it during the
    tests. This will be the real firestore package.
*/
import firestorePkg from 'some-firestore-pkg'

// ...skipping down to your test

test("renders component", () => {
    /*
        STEP 2: replace the real `doc` function with a fake version that returns a
        hard-coded value.
        
        We MUST replace it to prevent the real one from doing any real work,
        although we may not need to make the fake version return anything. But,
        let's do so, in order to miminize the chance that this test will stop
        working when the hook is modified in the future to verify the results of
        each operation.
    */
    let docSpy = jest.spyOn(firestorePkg, 'doc').mockReturnValue(
        'A_FAKE_USER_INFO_REF'
    )
    // now, when the real hook calls the doc(...) function, it will get that value
    
    /*
        STEP 3: replace the real useFirestoreDocument with a fake version that
        returns the hard-coded fake data that you want the app to receive during the
        test. You can probably guess what this will look like:
    */
    let useDocSpy = jest.spyOn(firestorePkg, 'useFirestoreDocument').mockReturnValue(
        { data: { name: "jack", email: "jack@gmail.com" } }
    )
    
    /*
        STEP 4: now that we've "arranged," let's "act" and then "assert"
    */
    let app = render(<Siuu />)
    let randomElement = app.getByText(/Jack/i)
    expect(randomElement).toBeInTheDocument()
    
    // STEP 5: completely remove our fake versions so other tests aren't impacted
    docSpy.mockRestore()
    useDocSpy.mockRestore()
})