发布于 2026-01-06 1 阅读
0

测试 React 上下文提供程序

测试 React 上下文提供程序

简要背景:我被要求修改一个名为 ` <ContextProvider><AuthProvider /> ` 的现有上下文提供程序及其关联的上下文AuthContext
没有测试用例。因此,我决定在进行任何操作之前先编写一些测试用例。

我当时就在想,我该如何测试上下文提供程序呢🤔?


我们来做个白板讨论:

  • 上下文提供程序是一个组件……
    render(
      <MyContextProvider />
    );
Enter fullscreen mode Exit fullscreen mode
  • 包含子元素……
    render(
      <MyContextProvider>
        <Child />
      </MyContextProvider>
    );
Enter fullscreen mode Exit fullscreen mode
  • ……它可以访问上下文提供程序提供的值。
    render(
      <MyContextProvider>
        <Child /> /* test that Child may access the expected value */
      </MyContextProvider>,
    );
Enter fullscreen mode Exit fullscreen mode

太棒了!我们可以把它转换成更实际的代码!

$> touch src/contexts/auth-context.test.js
Enter fullscreen mode Exit fullscreen mode
import { render } from '@testing-library/react';
import AuthContext, { AuthProvider } from './auth-context';

describe('<AuthProvider />', () => {
  test('provides expected AuthContext obj to child elements', () => {
    render(
      <AuthContext>
        < ?? />
      </AuthContext>,
    );
    // expect()
  }
})
Enter fullscreen mode Exit fullscreen mode

我们在这里取得了进展👩‍⚕️。


接下来,我们将测试上下文和提供程序组件(我省略了我们项目的具体细节)。

const AuthContext = createContext<{
  user?: AuthUser | undefined;
  isAdmin?: boolean;
}>({});

export function AuthProvider({ children }: Props): JSX.Element {
  const [user, setUser] = useState<AuthUser | undefined>();

  useEffect(() => {
    /* API calls */ 
    setUser( ... )
  }, []);

  const isAdmin = () => /* some logic */

  return (
    <AuthContext.Provider value={{ user, isAdmin: isAdmin() }}>
      {children}
    </AuthContext.Provider>
  );
}

export default AuthContext;
Enter fullscreen mode Exit fullscreen mode

好的,我们确实想测试子元素是否可以{user, isAdmin}使用类似这样的方法访问这些值React.useContext()

const TestingComponent = () => {
  const { user, isAdmin } = useContext(AuthContext);
  return (
    <>
      <p>{user?.name}</p>
      <p>{isAdmin?.toString()}</p>
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

这似乎就是缺失的那一块:

import { render } from '@testing-library/react';
import AuthContext, { AuthProvider } from './auth-context';

+
+ const TestingComponent = () => {
+  const { user, isAdmin } = useContext(AuthContext);
+  return (
+    <>
+      <p>{user?.name}</p>
+      <p>{isAdmin?.toString()}</p>
+    </>
+  );
+};
+
describe('<AuthProvider />', () => {
  test('provides expected AuthContext to child elements', () => {
    render(
      <AuthContext>
-        < ?? />
+        <TestingComponent />
      </AuthContext>,
    );
-    // expect()
+    // expected name
+    // expected isAdmin
  }
})
Enter fullscreen mode Exit fullscreen mode

现在我们已经有了所有部件;AuthContext获取用户并发出一些 HTTP 请求,然后公开用户 + 一个已处理的属性(isAdmin)。

我们针对此React 上下文提供程序的最终单元测试如下所示。(我省略了与模拟 API 相关的代码行,这些代码行取决于您使用的请求库。)

import { render } from '@testing-library/react';
import AuthContext, { AuthProvider } from './auth-context';

const TestingComponent = () => {
  const { user, isAdmin } = useContext(AuthContext);
  return (
    <>
      <p>{user?.name}</p>
      <p>{isAdmin?.toString()}</p>
    </>
  );
};

const regularUser = {
  name: 'Jhon Doe',
  /* fields that resolve as not admin */
};

const adminUser = {
  name: 'Jane Doe',
  /* fields that resolve as admin user */
};

describe('<AuthProvider />', () => {
  test('provides expected AuthContext to child elements', () => {
   [
     {
       scenario: 'regular user',
       user: regularUser,
       expectedName: 'Jhon Doe',
       expectedAdmin: 'false',
     },
     {
       scenario: 'admin user',
       user: adminUser,
       expectedName: 'Jane Doe',
       expectedAdmin: 'true',
     }
   ].forEach(({ scenario, user, expectedName, expectedAdmin }) => {

    test(scenario, () => {
      /* mock the HTTP request */

      const { getByTestId } = render(
        <AuthProvider>
          <TestingComponent />
        </AuthProvider>,
      );

      const userName = getByTestId('user-name');
      const isAdminValue = getByTestId('is-admin');
      expect(userName.textContent).toEqual(expectedName);
      expect(isAdminValue.textContent).toEqual(expectedAdmin);
    });

  });
});
Enter fullscreen mode Exit fullscreen mode

横幅图片:Storyset 提供的教育插图

感谢阅读💚。

文章来源:https://dev.to/manuartero/testing-a-react-context-provider-5cfg