如何使用 Jest 和 react-testing-library 测试 useRef?

Posted

技术标签:

【中文标题】如何使用 Jest 和 react-testing-library 测试 useRef?【英文标题】:How to test useRef with Jest and react-testing-library? 【发布时间】:2020-03-22 18:33:17 【问题描述】:

我正在使用 create-react-app、Jest 和 react-testing-library 来配置聊天机器人项目。

我有一个使用 useRef 挂钩的功能组件。当有新消息出现时,会触发 useEffect 挂钩并通过查看 ref 的当前属性来引发滚动事件。

const ChatBot = () => 
  const chatBotMessagesRef = useRef(null)
  const chatBotContext = useContext(ChatBotContext)
  const  chat, typing  = chatBotContext

  useEffect(() => 
    if (typeof chatMessagesRef.current.scrollTo !== 'undefined' && chat && chat.length > 0)  
       chatBotMessagesRef.current.scrollTo(
         top: chatMessagesRef.current.scrollHeight,
         behavior: 'smooth'
       )
    
    // eslint-disable-next-line
  , [chat, typing])

   return (
    <>
      <ChatBotHeader />
      <div className='chatbot' ref=chatBotMessagesRef>
        chat && chat.map((message, index) => 
          return <ChatBotBoard answers=message.answers key=index currentIndex=index + 1 />
        )
        typing &&
        <ServerMessage message='' typing isLiveChat=false />
        
      </div>
    </>
  )

我想测试一下当有新的聊天项目或输入时是否触发了scrollTo功能,你有什么想法吗?我找不到测试 useRef 的方法。

【问题讨论】:

你可以模拟 scrollTo 函数(使用 jest.fn()),添加一个新的聊天项目并检查是否调用了模拟。 但是 scrollTo 函数是当前对象的实例,它是 ref 的方法,如何在不模拟 ref 的情况下模拟 scrollTo? 啊,是的,这可能很困难,您是否尝试过使用以下方法模拟它:Element.prototype.scrollTo = jest.fn() 我试过了,但是如何在渲染之前对元素做出反应?我需要在渲染之前以某种方式模拟 ref 以便我可以测试它,我猜这是一个非常奇怪的情况,我也使用了 jest.spyOn 但这也不起作用 【参考方案1】:

您可以将您的 useEffect 移出您的组件,并将 ref 作为参数传递给它。类似的东西

const useScrollTo = (chatMessagesRef, chat) => 
    useEffect(() => 
    if (typeof chatMessagesRef.current.scrollTo !== 'undefined' && chat && chat.length > 0)  
       chatBotMessagesRef.current.scrollTo(
         top: chatMessagesRef.current.scrollHeight,
         behavior: 'smooth'
       )
    
  , [chat])

现在在你的组件中

import useScrollTo from '../..'; // whatever is your path

const MyComponent = () => 
  const chatBotMessagesRef = useRef(null);
  const  chat  = useContext(ChatBotContext);

  useScrollTo(chatBotMessagesRef, chat);

  // your render..

你的 useScrollTo 测试:

import useScrollTo from '../..'; // whatever is your path
import  renderHook  from '@testing-library/react-hooks'

it('should scroll', () => 
  const ref = 
    current: 
      scrollTo: jest.fn()
    
  
  const chat = ['message1', 'message2']

  renderHook(() => useScrollTo(ref, chat)) 

  expect(ref.current.scrollTo).toHaveBeenCalledTimes(1)
)

【讨论】:

如果我通过使用 const ref = React.createRef() 创建一个 ref 作为道具,它会给我错误,但如果我像 const 一样模拟它ref = current: scrollTo: jest.fn() 并给出一个模拟聊天数组而不是从真实的上下文对象中获取它,测试有效,而且似乎我涵盖了所有条件ChatBot 组件使用 useScrollTo 钩子,所以你的回答有点让我纠正我的测试! 谢谢,非常实用的方法,对我很有帮助:)

以上是关于如何使用 Jest 和 react-testing-library 测试 useRef?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Jest 和 Proxyquire 存根模块?

如何在 React 和 Webpack 中使用 Jest

如何使用 jest.mock 模拟 useRef 和反应测试库

如何在 TypeScript 中使用 Jest 和 Knex 进行测试?

如何使用 NodeJS 解决 Supertest 和 jest 中的 ECONNREFUSED 错误?

如何使用 jest 和酶测试 onClick() 函数和 useState 钩子