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

时间:2019-09-12 17:18:37

标签: reactjs jestjs react-testing-library

我有一个<UserProvider />组件,它提供了上下文,该上下文的值具有login方法。在我的测试中,我想检查是否已调用该方法。如果它来自上下文,我如何检查以确保此方法在我的测试中被调用?我尝试使用spyOnmock方法,但无法使其正常工作。

这是我的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 }

这是我的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

这是我的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)
})

我有一个codesandbox,但关于jest.mock不是功能的错误,所以我不知道它是否非常有用。

2 个答案:

答案 0 :(得分:1)

如果不稍稍更改源代码,我将无法使其正常工作。

首先,我必须导出实际上下文

export { UserProvider, useUser, UserContext }

我们可以使用模拟的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)
});

这可能不是最佳方法。希望对您有所帮助。

答案 1 :(得分:0)

我在这里看到另外2种方法:

  1. if __name__ == "__main__": width = 700 height = 700 scaller = 35 win = pygame.display.set_mode((width, height)) #here I'm getting the error apple = Apple(win, random(scaller - 1), random(scaller - 1), scaller) 注入待测组件旁边。然后,您将可以对此进行验证
Context.Consumer
  1. 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" }); 之后进行模拟通话(在UserContext.Consumer中进行推测性LoginAPI通话)
UserContext

对我来说,第二个更好,而第一个则依赖于实现细节(上下文数据的结构)。

第一种方法PS,您可以在测试中声明使用方组件正确,以避免导出jest.mock("../LoginAPI.js"); ... const { getByText } = render( <UserProvider> <Login /> </UserProvider> ); const submitButton = getByText('Login'); fireEvent.click(submitButton); expect(LoginAPI.login).toHaveBeenCalledTimes(1);

UserContext

但是请记住,function ContextHelper({ spy }) { const contextData = useUser(); spy(contextData); return null; } ... const contextCallback = jest.fn(); const { getByText } = render( <UserProvider> <Login /> <ContextHelper spy={contextCallback} /> </UserProvider> ); 的调用次数可能会超出您的预期。