React Testing Library: Test onload callback of script loaded in React hook

Viewed 231

I'm writing a library for React supporting Google identity services. Sign In With Google requires a script be loaded in a script tag in the document. This script is not available as a package. I'm adding the script tag to the document head in a React hook that passes in onload and onerror callbacks. I need to test that these callbacks are being called when the script loads or doesn't load successfully. Unfortunately, in my tests, neither callback is called and I don't know why.

This is the function that the React hook calls to add the <script> tag to the document head:

const loadGapiScript = (document, src, onLoad, onError) => {
  const script = document.getElementsByTagName('script')[0]

  let js = document.createElement('script')
  js.id = 'google-auth'
  js.src = src
  js.async = true
  js.defer = true

  js.onerror = onError
  js.onload = onLoad

  if (script && script.parentNode) {
    script.parentNode.insertBefore(js, script)
  } else {
    document.head.appendChild(js)
  }
}

And this is my test code:

import { renderHook, waitFor } from '@testing-library/react'
import useGoogleLogin from './use-google-login'

describe('useGoogleLogin', () => {
  const clientId = 'somestring'
  const onLoad = jest.fn(() => {})

  it('calls the onLoad callback', async () => {
    renderHook(() => useGoogleLogin({ clientId, onLoad }))

    await waitFor(() => expect(onLoad).toHaveBeenCalled())
  })
})

This is the output when I run the test:

    expect(jest.fn()).toHaveBeenCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

    Ignored nodes: comments, <script />, <style />
    <html>
      <head />
      <body>
        <div />
      </body>
    </html>

      30 |               renderHook(() => useGoogleLogin({ clientId, onLoad }))
      31 |
    > 32 |               await waitFor(() => { expect(onLoad).toHaveBeenCalled() })
         |                                                       ^
      33 |             })
      34 |           })
      35 |         })

      at toHaveBeenCalled (__tests__/use-google-login-test.js:32:55)
      at runWithExpensiveErrorDiagnosticsDisabled (node_modules/@testing-library/dom/dist/config.js:50:12)
      at checkCallback (node_modules/@testing-library/dom/dist/wait-for.js:141:77)
      at checkRealTimersCallback (node_modules/@testing-library/dom/dist/wait-for.js:133:16)
      at Timeout.task [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:514:19)

I suspect the issue may have to do with the fact that <script> nodes are ignored, but I'm not sure how to change this as the only docs are vague and refer to a filterNode function passed into PrettyDOM, which I'm not using (at least not explicitly). The docs are also in TypeScript, which complicates things further since I don't know TypeScript.

Strategically placed console logging reveals that the entire loadGapiScript function does run in the course of the test.

0 Answers
Related