Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 69 additions & 3 deletions packages/usehooks-ts/src/useScript/useScript.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useScript } from './useScript'

describe('useScript', () => {
it('should handle script loading error', () => {
const src = 'https://example.com/myscript.js'
const src = 'https://example.com/test-error.js'

const { result } = renderHook(() => useScript(src))

Expand All @@ -21,7 +21,7 @@ describe('useScript', () => {
})

it('should remove script on unmount', () => {
const src = '/'
const src = 'https://example.com/test-remove-on-unmount.js'

// First load the script
const { result } = renderHook(() =>
Expand Down Expand Up @@ -63,7 +63,7 @@ describe('useScript', () => {
})

it('should have a `id` attribute when given', () => {
const src = '/'
const src = 'https://example.com/test-id.js'
const id = 'my-script'

const { result } = renderHook(() => useScript(src, { id }))
Expand All @@ -80,4 +80,70 @@ describe('useScript', () => {
expect(document.querySelector(`script[id="${id}"]`)).not.toBeNull()
expect(document.querySelector(`script[src="${src}"]`)?.id).toBe(id)
})

it('should have a `crossOrigin` attribute when given', () => {
const src = 'https://example.com/test-crossorigin.js'
const crossOrigin = 'use-credentials'

const { result } = renderHook(() => useScript(src, { crossOrigin }))

act(() => {
document
.querySelector(`script[src="${src}"]`)
?.dispatchEvent(new Event('load'))
})

expect(result.current).toBe('ready')

const script = document.querySelector<HTMLScriptElement>(
`script[src="${src}"]`,
)
expect(script).not.toBeNull()
expect(script?.crossOrigin).toBe(crossOrigin)
})

it.each([
{
scenario:
"defaults crossOrigin to 'anonymous' when integrity is set and crossOrigin is not supplied",
integrity: 'integrity-hash-1',
crossOrigin: undefined,
expectedCrossOrigin: 'anonymous',
},
{
scenario:
"uses supplied crossOrigin 'anonymous' when both integrity and crossOrigin are set",
integrity: 'integrity-hash-2',
crossOrigin: 'anonymous',
expectedCrossOrigin: 'anonymous',
},
{
scenario:
"uses supplied crossOrigin 'use-credentials' when both integrity and crossOrigin are set",
integrity: 'integrity-hash-3',
crossOrigin: 'use-credentials',
expectedCrossOrigin: 'use-credentials',
},
])('$scenario', ({ integrity, crossOrigin, expectedCrossOrigin }) => {
const src = `https://example.com/file-${integrity}.js`

const { result } = renderHook(() =>
useScript(src, { integrity, crossOrigin }),
)

act(() => {
document
.querySelector(`script[src="${src}"]`)
?.dispatchEvent(new Event('load'))
})

expect(result.current).toBe('ready')

const script = document.querySelector<HTMLScriptElement>(
`script[src="${src}"]`,
)
expect(script).not.toBeNull()
expect(script?.integrity).toBe(integrity)
expect(script?.crossOrigin).toBe(expectedCrossOrigin)
})
})
23 changes: 22 additions & 1 deletion packages/usehooks-ts/src/useScript/useScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ type UseScriptOptions = {
removeOnUnmount?: boolean
/** Script's `id` (optional). */
id?: string
/**
* Script's [`integrity` property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement/integrity) (optional).
*
* _Note:_ As a side effect of this being set the `crossOrigin` property will be set to `'anonymous' unless explicitly configured differently.
*/
integrity?: string
/** Script's [`crossOrigin` property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement/crossOrigin) (optional). */
crossOrigin?: string
}

// Cached script statuses
Expand Down Expand Up @@ -92,6 +100,12 @@ export function useScript(
if (options?.id) {
scriptNode.id = options.id
}
if (options?.integrity) {
scriptNode.integrity = options.integrity
}
if (!!options?.crossOrigin || !!options?.integrity) {
scriptNode.crossOrigin = options?.crossOrigin ?? 'anonymous'
}
scriptNode.setAttribute('data-status', 'loading')
document.body.appendChild(scriptNode)

Expand Down Expand Up @@ -136,7 +150,14 @@ export function useScript(
cachedScriptStatuses.delete(src)
}
}
}, [src, options?.shouldPreventLoad, options?.removeOnUnmount, options?.id])
}, [
src,
options?.shouldPreventLoad,
options?.removeOnUnmount,
options?.id,
options?.integrity,
options?.crossOrigin,
])

return status
}