简体   繁体   English

如何使用jest和react-testing-library测试上下文提供的功能?

[英]How can I test functions that are provided by context using jest and react-testing-library?

I have a <UserProvider /> component that provides context which has a login method in its value. 我有一个<UserProvider />组件,该组件提供了上下文,该上下文的值具有login方法。 In my test I want to check if that method has been called. 在我的测试中,我想检查是否已调用该方法。 How can I check to make sure this method is being called in my test if it comes from context? 如果来自上下文,我该如何检查以确保此方法在我的测试中被调用? I've tried using the spyOn and mock methods but I can't get them to work. 我尝试使用spyOn模拟方法,但无法使其正常工作。

Here's my UserProvider component which provides the context. 这是提供上下文的我的UserProvider组件。

import React, { useState, useContext, createContext } from 'react'

const UserContext = createContext()

function UserProvider({ children }) {
  const [user, setUser] = useState(null)
  const login = user => setUser(user)

  return <UserContext.Provider value={{ user, login }}>{children}</UserContext.Provider>
}

const useUser = () => useContext(UserContext)

export { UserProvider, useUser }

Here's my Login component using the context from UserProvider (via useUser ) 这是我的Login组件,使用来自UserProvider的上下文(通过useUser

import React from 'react'
import { useUser } from './UserProvider'

function Login() {
  const { login } = useUser()

  const handleSubmit = async e => {
    e.preventDefault()

    // I need to make sure this method is being called in my test.
    login({ name: 'John Doe' })
  }

  return (
    <form onSubmit={handleSubmit}>
      <button>Login</button>
    </form>
  )
}

export default Login

Here's my Login test 这是我的Login测试

import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import Login from './Login'
import { UserProvider, useUser } from './UserProvider'

// Is this correct?
jest.mock('./UserProvider', () => ({
  useUser: jest.fn(() => ({
    login: jest.fn()
  }))
}))

it('should log a user in', () => {
  const { getByText } = render(
    <UserProvider>
      <Login />
    </UserProvider>
  )

  const submitButton = getByText(/login/i)
  fireEvent.click(submitButton)

  // How can I make this work?
  const { login } = useUser()
  expect(login).toHaveBeenCalledTimes(1)
})

I have a codesandbox but it's erroring out about jest.mock not being a function so I don't know if it's very useful. 我有一个codeandbox,但是它错误地显示jest.mock不是功能,所以我不知道它是否非常有用。

I can't get it to work without slightly change the source code a little bit. 如果不稍稍更改源代码,我将无法正常工作。

First, I have to export the actual context 首先,我必须导出实际上下文

export { UserProvider, useUser, UserContext }

We can re create provider with a mocked login function and the following test will serve you purpose. 我们可以使用模拟的login功能重新创建提供程序,以下测试将为您服务。

import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import Login from './Login'
import { UserProvider, useUser, UserContext } from './UserProvider'

it('should log a user in', () => {
  const login = jest.fn();
  const { getByText } = render(
    <UserContext.Provider value={{ login }}>
      <Login />
    </UserContext.Provider>
  );

  const submitButton = getByText('Login');
  fireEvent.click(submitButton);

  expect(login).toHaveBeenCalledTimes(1)
});

It is entirely possible that this is not the best approach. 这完全不是最佳方法。 I hope it helps. 希望对您有所帮助。

I see 2 more approaches here: 我在这里看到另外2种方法:

  1. Inject Context.Consumer alongside your component under test. 在要测试的组件旁边注入Context.Consumer Then so you would be able to verify against it 然后,您将可以对此进行验证
  const contextCallback = jest.fn();
  const { getByText } = render(
    <UserProvider>
      <Login />
      <UserContext.Consumer>{contextCallback}</UserContext.Consumer>
    </UserProvider>
  );

  const submitButton = getByText('Login');
  fireEvent.click(submitButton);

  expect(contextCallback.mock.calls[0][0]).toEqual({ 
    user: "John Doe"
  });
  1. Mock calls behind UserContext.Consumer (let it be speculative LoginAPI call in UserContext ) 背后模拟电话UserContext.Consumer (让它成为投机LoginAPI呼叫UserContext
jest.mock("../LoginAPI.js");
...
  const { getByText } = render(
    <UserProvider>
      <Login />
    </UserProvider>
  );

  const submitButton = getByText('Login');
  fireEvent.click(submitButton);

  expect(LoginAPI.login).toHaveBeenCalledTimes(1);

To me 2nd one is better while 1st rely on implementation details(context data's structure). 对我来说,第二个更好,而第一个则依赖于实现细节(上下文数据的结构)。

PS to 1st approach you may declare consumer component right in the test to avoid exporting UserContext : PS到第一种方法,您可以在测试中声明使用方组件,以避免导出UserContext

function ContextHelper({ spy }) {
  const contextData = useUser();
  spy(contextData);
  return null;
}

...
  const contextCallback = jest.fn();
  const { getByText } = render(
    <UserProvider>
      <Login />
      <ContextHelper spy={contextCallback} />
    </UserProvider>
  );

But keep in mind that spy may be called more times that you'd expect. 但是请记住, spy可能会被多次调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何测试与 Jest/react-testing-library 反应的上下文 - How can I test a context in react with Jest/react-testing-library 如何使用 React、Jest 和 React-testing-library 为带有令牌的 api 调用编写单元测试? - How can I write unit test for api call with token using React, Jest and React-testing-library? 如何使用 react-testing-library 和 jest 测试链接 - How to test link using react-testing-library and jest 如何使用 jest 和 react-testing-library 测试来自 sass 的 styles? - How can I test styles coming from sass with jest and react-testing-library? 如何使用 Jest 和 react-testing-library 测试 react-dropzone? - How to test react-dropzone with Jest and react-testing-library? 如何用 jest 和 react-testing-library 测试 react-toastify - How to test react-toastify with jest and react-testing-library 如何使用 React-Testing-Library 测试 mapDispatchToProps? - How can I test the mapDispatchToProps with React-Testing-Library? 带有 jest 和 react-testing-library 的测试方法 - test method with jest and react-testing-library 如何使用 Jest 和 react-testing-library 测试 useRef? - How to test useRef with Jest and react-testing-library? 如何使用 Jest 和 react-testing-library 测试 Websocket 客户端 - How to test Websocket Client with Jest and react-testing-library
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM