jest enyzme useRef

#reactjs #jestjs #react-hooks #mocking #enzyme

Вопрос:

У меня есть компонент, который выглядит так:

 import React, { useRef } from 'react'
import Modal from '@example-component-library/modal'
import ModalHeader from '@example-component-library/modal/header'
import ModalFooter from '@example-component-library/modal/footer'

const ExampleModal = () => { 
  const headerRef = useRef(null)
  ...
  return (
    <Modal
      headerRef={headerRef}
      isOpen={showModal}
      header={
        <ModalHeader closeModal={handleCloseModal} headerRef={headerRef} content="Modal Header"/>
      }
      footer={<ModalFooter closeModal={handleCloseModal} />}
    >
      Modal body stuff
    </Modal>
  )
}
 

Тогда у меня будет тест:

 it('renders as expected', () => {
    const wrapper = mount(
      <TestWrapper>
        <ExampleModal />
      </TestWrapper>
    )

    expect(wrapper.exists()).toBe(true)
  })
})
 

и тут у меня возникает ошибка

 TypeError: Cannot read property 'style' of null

      28 |
      29 |   it('renders as expected', () => {
    > 30 |     const wrapper = mount(
         |                     ^
      31 |       <TestWrapper>
      32 |         <ExampleModal />
      33 |       </TestWrapper>
 

Если я изменю ExampleModal реквизит header на:

 <Modal header={<>HEADER</>} ...>
 

Тест работает без проблем — поэтому я считаю, что это как — то связано с headerRef тем, что я пробовал jest.spyOn , и несколькими другими решениями, — однако я всегда получаю одну и ту же ошибку.

Разметка модального Компонента

 const ModalHeader = ({ headerRef, content, ...}) => (
  <div>
    <h5 tabIndex={-1} ref={headerRef}> {content}</h5>
    ... 
  </div>
)

const Modal = ({ id, isOpen, header, headerRef, children, ...}) => {
  useEffect(() => {
    const selectorId = `#${id}`
    const selectedElement: HTMLElement = document.querySelector(selectorId)
    // set focus to the header when modal is opened
    if (isOpen amp;amp; headerRef.current) {
      headerRef.current.focus()

      // React Ref wasn't working for this case
      selectedElement.style.right = '0px'
      document.body.style.overflow = 'hidden'
      setPostAnimationState(true)
    }

    if (!isOpen amp;amp; document.querySelector(selectorId)) {
      // React Ref wasn't working for this case
      document.body.style.overflow = 'auto'
      selectedElement.style.right = '-768px'
      setTimeout(() => {
        setPostAnimationState(false)
      }, 400)
    }
  }, [isOpen, headerRef, id])

  return (
    <div>
      ...
      {!!header amp;amp; header}
      <div className="modal-content" ref={!header ? headerRef : null}>
       {children}
      </div>
      ...
    </div>
  )
}
 

Комментарии:

1. Почему вы переходите headerRef к обоим Modal и ModalHeader ? Где ты шпионишь за чем-нибудь в тестах? Можете ли вы обновить свой вопрос, включив в него весь соответствующий код? ( ModalHeader , ModalFooter , тестовый код и т. Д.)

2. @DrewReese — обновил свой пост с помощью разметки компонентов. Я не создавал компонент, не видел, как он работает и где его не хватает — я просто не уверен, как это сделать или как протестировать его без использования . style shallow Я бы хотел использовать mount

Ответ №1:

На самом деле это не имело никакого отношения ref , это было связано с тем document.body . Итак, вот мой тест, который работает сейчас:

 it('renders as expected', () => {
    const wrapper = mount(
      <TestWrapper>
        <ExampleModal />
      </TestWrapper>,
      { attachTo: document.body }
    )

    expect(wrapper.exists()).toBe(true)
  })
})