Skip to content

Add utility for testing custom hooks #261

Closed
@kentcdodds

Description

@kentcdodds

Describe the feature you'd like:

I think it would be great to add a utility to make testing custom hooks easier. Right now, I recommend making a render prop component out of the hook and testing that component. I think we could do the same from within react-testing-library.

Suggested implementation:

Here's a working implementation/example

import React, {useState} from 'react'
import {render, cleanup} from 'react-testing-library'

afterEach(cleanup)

function useCounter({initialCount = 0, step = 1} = {}) {
  const [count, setCount] = useState(initialCount)
  const increment = () => setCount(c => c + step)
  const decrement = () => setCount(c => c - step)
  return {count, increment, decrement}
}

function testHook(useHook, props) {
  const RenderProp = ({children, ...rest}) => children(useHook(rest))
  const returnVal = {}
  render(
    <RenderProp {...props}>
      {val => {
        // may need some special treatment if the
        // return value is not an object of values...
        Object.assign(returnVal, val)
        return null
      }}
    </RenderProp>,
  )
  return returnVal
}


// how to use this:
test('renders counter', () => {
  const data = testHook(useCounter)
  data.increment()
  expect(data.count).toBe(1)
  data.decrement()
  expect(data.count).toBe(0)
})

Describe alternatives you've considered:

  • Not providing the utility at all.
  • Calling it renderHook rather than testHook, or just about anything else. I'm not sure I like testHook...

Teachability, Documentation, Adoption, Migration Strategy:

One really important consideration is that with render we recommend that people destructure just what they need rather than assigning the return value an actual variable name. With testHook however, if you destructure the return value it can have some pretty confusing issues (relating to the way JavaScript closures work, I explain it in the video I linked above). So all docs will need to call this out specially and all examples should not destructure anything from testHook.

We should also make sure to document the fact that this should typically only be used for hooks that either have a lot of edge cases that need special unit testing or highly reused hooks. Typically custom hooks should just be covered by testing the components that use them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions