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.