video-ad-sdk
Version:
VAST/VPAID SDK that allows video ads to be played on top of any player
265 lines (195 loc) • 6.48 kB
text/typescript
const mockObserve = jest.fn()
const mockDisconnect = jest.fn()
let simulateIntersection: any
jest.mock('../helpers/IntersectionObserver', () => {
let mockHandler: any
class MockIntersectionObserver {
observe = mockObserve
disconnect = mockDisconnect
constructor(handler: any) {
mockHandler = handler
}
}
simulateIntersection = (
target: HTMLElement,
intersectionRatio: number
): IntersectionObserver =>
mockHandler([
{
intersectionRatio,
target
}
])
return {IntersectionObserver: MockIntersectionObserver}
})
import {onElementVisibilityChange} from '../onElementVisibilityChange'
const once = (
context: Window | Document | Element,
eventName: string,
listener: (...args: any[]) => void
): void => {
const handler = (...args: any[]): void => {
context.removeEventListener(eventName, handler)
listener(...args)
}
context.addEventListener(eventName, handler)
}
const waitForEvent = (
eventName: string,
context: Window | Document | Element = window
): Promise<Event> =>
new Promise<Event>((resolve) => {
once(context, eventName, resolve)
})
let origHidden: boolean
jest.mock('lodash.debounce', () => (callback: any) => callback)
beforeEach(() => {
origHidden = document.hidden
Object.defineProperty(document, 'hidden', {
writable: true
})
})
afterEach(() => {
Object.defineProperty(document, 'hidden', {
value: origHidden,
writable: true
})
mockObserve.mockReset()
mockDisconnect.mockReset()
})
test('onElementVisibilityChange must be a function', () => {
expect(onElementVisibilityChange).toEqual(expect.any(Function))
})
test('onElementVisibilityChange must complain if the passed target is not an Element', () => {
expect(onElementVisibilityChange).toThrow(TypeError)
})
test("onElementVisibilityChange mut complain if you don't pass a callback function", () => {
expect(() =>
onElementVisibilityChange(document.createElement('div'), undefined as any)
).toThrow(TypeError)
})
test('onElementVisibilityChange must call callback with true if the element is visible', () => {
const target = document.createElement('DIV')
const mock = jest.fn()
const disconnect = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
simulateIntersection(target, 1)
expect(mock).toHaveBeenCalledWith(true)
disconnect()
})
test('onElementVisibilityChange must call callback with true if the element becomes visible on intersection', () => {
const target = document.createElement('div')
const mock = jest.fn()
const disconnect = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
simulateIntersection(target, 0)
expect(mock).not.toHaveBeenCalled()
simulateIntersection(target, 1)
expect(mock).toHaveBeenCalledWith(true)
disconnect()
})
test('onElementVisibilityChange must call callback with false if the element becomes hidden on intersection', () => {
const target = document.createElement('div')
const mock = jest.fn()
const disconnect = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
simulateIntersection(target, 1)
expect(mock).toHaveBeenCalledWith(true)
simulateIntersection(target, 0)
expect(mock).toHaveBeenCalledWith(false)
disconnect()
})
test('onElementVisibilityChange must call callback with true if the element becomes visible on visibilitychange', async () => {
const target = document.createElement('div')
const mock = jest.fn()
Object.defineProperty(document, 'hidden', {
value: true,
writable: true
})
const disconnect = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
simulateIntersection(target, 1)
expect(mock).not.toHaveBeenCalled()
const waitPromise = waitForEvent('visibilitychange', document)
Object.defineProperty(document, 'hidden', {
value: false,
writable: true
})
document.dispatchEvent(new Event('visibilitychange'))
await waitPromise
expect(mock).toHaveBeenCalledWith(true)
disconnect()
})
test('onElementVisibilityChange must call callback with false if the element becomes hidden on visibilitychange', async () => {
const target = document.createElement('div')
const mock = jest.fn()
Object.defineProperty(document, 'hidden', {
value: false,
writable: true
})
const disconnect = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
simulateIntersection(target, 1)
expect(mock).toHaveBeenCalledWith(true)
const waitPromise = waitForEvent('visibilitychange', document)
Object.defineProperty(document, 'hidden', {
value: true,
writable: true
})
document.dispatchEvent(new Event('visibilitychange'))
await waitPromise
expect(mock).toHaveBeenCalledWith(false)
disconnect()
})
test('onElementVisibilityChange on element removed must remove the all the listeners if there are no more elements to check', () => {
const target = document.createElement('div')
const mock = jest.fn()
document.removeEventListener = jest.fn()
const disconnect = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
expect(mockDisconnect).not.toHaveBeenCalled()
expect(document.removeEventListener).not.toHaveBeenCalledWith(
'visibilitychange',
expect.any(Function)
)
disconnect()
expect(mockDisconnect).toHaveBeenCalled()
expect(document.removeEventListener).toHaveBeenCalledWith(
'visibilitychange',
expect.any(Function)
)
})
test('onElementVisibilityChange on element remove must not remove the all the listeners if there other checkeed elements use the same target', () => {
const target = document.createElement('DIV')
const mock = jest.fn()
document.removeEventListener = jest.fn()
const disconnect = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
const disconnect2 = onElementVisibilityChange(target, (...args) =>
mock(...args)
)
expect(mockDisconnect).not.toHaveBeenCalled()
expect(document.removeEventListener).not.toHaveBeenCalledWith(
'visibilitychange',
expect.any(Function)
)
disconnect()
expect(mockDisconnect).not.toHaveBeenCalled()
expect(document.removeEventListener).not.toHaveBeenCalledWith(
'visibilitychange',
expect.any(Function)
)
disconnect2()
expect(mockDisconnect).toHaveBeenCalled()
expect(document.removeEventListener).toHaveBeenCalledWith(
'visibilitychange',
expect.any(Function)
)
})