Search code examples
jestjsreact-testing-library

Test function inside useEffect


I am testing my components using Jest and React Testing Library. The current code is updating a title in the TopBar component based on scroll position and current collection title:

    const [currentTitle, setTitle] = useState<string>(defaultProps.collectionName)

    useEffect(() => {
        const collections = document.getElementsByClassName('cc-look-collection')
        const childNodes = collections[0].childNodes

        const updateCurrentTitle = () => {
            const currentPosition = window.scrollY
            let accumulatedHeight = 0

            for (let i = 0; i < childNodes.length; i++) {
                const collection = childNodes[i]
                const collectionHeight = (collection as HTMLInputElement)?.offsetHeight
                accumulatedHeight += collectionHeight

                if (currentPosition < accumulatedHeight) {
                    const title = collection.childNodes[0].textContent!
                    setTitle(title)
                    break
                }
            }
        }

        window.addEventListener('scroll', updateCurrentTitle)
    }, [collections])

I want to test this updateCurrentTitle function but I am not able to figure it out how to make it work, since it doesn't seems to simulate the scroll event. Here is my test case:

it('should update TopBar collectionName based on scroll position', () => {
    // Given
    const props = lookCollectionProps
    const { container } = render(<LookCollection {...props} />)

    // eslint-disable-next-line testing-library/no-node-access
    const content = container.firstChild as HTMLElement

    jest.useFakeTimers()
    window.dispatchEvent(new Event('scroll'))
    const baseText = within(content).getByText('Collection n°1')
    expect(baseText).toBeInTheDocument()

    act(() => {
        jest.advanceTimersByTime(1500)
    })

    const expectedText = within(content).getByText('Collection n°2')
    expect(expectedText).toBeInTheDocument()
})

I am getting this error: Unable to find an element with the text: Collection n°2.


Solution

  • I think the problem is that you are running your app/component in a js-dom environment which doesn't support things like scrolling. In such cases, the best approach from my experience is this: make sure it works manually, then write a test using an e2e library like Cypress or Playwright.

    P.S. Here is the answer to a very similar question given by the creator of React Testing Library: https://github.com/testing-library/react-testing-library/issues/671