How test usestate and useEffect with click events using react testing library jest?

To give you an idea about what I mean by custom hook, we could do:

import React, {useState, useEffect, useCallback} from 'react'

const useDropdown = () => {
  const [showDropdown, setShowDropdown] = useState(false)

  const handler = useCallback(() => setShowDropdown(false), [setShowDropdown])

  useEffect(() => {
      window.addEventListener('click', handler)
      return () => {
          window.removeEventListener('click', handler)
      }
  }, [handler])
    
  const handleDropdownClick = (e) => {
    e.stopPropagation()
    setShowDropdown(showDropdown => !showDropdown)
  }

  return { showDropdown, setShowDropdown, handleDropdownClick }
}

// *************

const App = () => {
  const { showDropdown, handleDropdownClick } = useDropdown()

  return (
    <div>
      <h1>My App</h1>
      {showDropdown && (
        <div data-testid="dropdown">
          <h2>My Dropdown</h2>
        </div>
      )}
      <button type="button" onClick={handleDropdownClick} data-testid="toggle-dropdown-button">Toggle Dropdown</button>
    </div>
  )
}

export default App

Normally I would put that hook it a file like MyComponent.hooks.js or I would put it in a more general location if I wanted to use it in multiple places. It’s just really nice to clean up component files and any time I can pull logic out, I can - it makes it cleaner and easier to test and mock. It’s just a good practice to always be thinking - how can I logically break this apart.

In this case, you can still use the exact same test - since we were testing behaviors - the behaviors haven’t changed.

But with complicated hooks sometimes it’s nice to break things out like this so you can test the hook directly with things like react hooks testing library. And sometimes when testing the component, it’s helpful to mock the hook to easily set up different states to test the component and then test the hook separately.

1 Like