@signalwire/js
Version:
934 lines (784 loc) • 31.6 kB
text/typescript
import { JSDOM } from 'jsdom'
import { actions } from '@signalwire/core'
import {
configureFullStack,
dispatchMockedCallJoined,
dispatchMockedRoomSubscribed,
} from './testUtils'
import { buildVideoElement, BuildVideoElementParams } from './buildVideoElement'
import {
FabricRoomSession,
createFabricRoomSessionObject,
} from './fabric/FabricRoomSession'
import {
createVideoRoomSessionObject,
VideoRoomSession,
} from './video/VideoRoomSession'
import { addOverlayPrefix, SDK_PREFIX } from './utils/roomSession'
describe('buildVideoElement', () => {
describe('with FabricRoomSession', () => {
let room: FabricRoomSession
let stack: ReturnType<typeof configureFullStack>
let store: any
let jsdom: JSDOM
const callId = 'call-id-1'
const mockPeer = {
uuid: callId,
onRemoteSdp: jest.fn(),
}
const setupRoomForTests = () => {
// @ts-expect-error
room.getRTCPeerById = jest.fn((_id: string) => mockPeer)
// @ts-expect-error
room.runRTCPeerWorkers(callId)
}
beforeEach(() => {
stack = configureFullStack()
store = stack.store
room = createFabricRoomSessionObject({
store,
})
setupRoomForTests()
jsdom = new JSDOM('<!doctype html><html><body></body></html>')
global.document = jsdom.window.document
global.HTMLDivElement = jsdom.window.HTMLDivElement
})
afterEach(() => {
jest.clearAllMocks()
// @ts-expect-error
delete global.document
// @ts-expect-error
delete global.HTMLDivElement
})
it('should take a video element and return it with unsubscribe function', async () => {
const mockRootEl = document.createElement('div')
const result = await buildVideoElement({ room, rootElement: mockRootEl })
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
expect(result.element).toBeInstanceOf(HTMLDivElement)
expect(result.unsubscribe).toBeInstanceOf(Function)
})
it('should create a video element and return it with unsubscribe function', async () => {
const result = await buildVideoElement({ room })
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
expect(result.element).toBeInstanceOf(HTMLDivElement)
expect(result.unsubscribe).toBeInstanceOf(Function)
})
it('should unsubscribe from all events on unsubscribe', async () => {
const mockVideoEl = document.createElement('div')
const result = await buildVideoElement({ room, rootElement: mockVideoEl })
// Mock the room.off function to spy on it
room.off = jest.fn()
result.unsubscribe()
expect(room.off).toHaveBeenCalledWith('track', expect.any(Function))
expect(room.off).toHaveBeenCalledWith(
'layout.changed',
expect.any(Function)
)
expect(room.off).toHaveBeenCalledWith(
'member.updated.videoMuted',
expect.any(Function)
)
expect(room.off).toHaveBeenCalledWith('destroy', expect.any(Function))
})
describe('with remoteVideoTrack', () => {
const layoutEventPayload = {
jsonrpc: '2.0',
id: '79996d32-aefd-4e37-b1c1-382144334122',
method: 'signalwire.event',
params: {
event_type: 'layout.changed',
event_channel: [
'signalwire_12fee1d5-b000-408f-8e3a-7cb3bbe9755e_1ad23ed0-18e0-4167-a953-a59f2976c02c_f15c5e3a-e5d6-4607-9a3d-c5af0aa9236a',
],
timestamp: 1716832047176777,
params: {
room_id: '8facb303-63da-41c5-9f6b-4c97255cdec2',
room_session_id: callId,
layout: {
layers: [
{
layer_index: 0,
z_index: 0,
member_id: 'member-id-1',
playing_file: false,
position: 'standard-1',
visible: true,
x: 0,
y: 0,
width: 100,
height: 100,
},
{
layer_index: 1,
z_index: 1,
playing_file: false,
position: 'playback',
visible: true,
x: 0,
y: 0,
width: 100,
height: 100,
},
{
layer_index: 2,
z_index: 2,
playing_file: false,
position: 'full-screen',
visible: true,
x: 0,
y: 0,
width: 100,
height: 100,
},
],
id: 'grid-responsive',
name: 'Grid',
},
},
},
}
const renderAndStartVideo = (
params?: Omit<BuildVideoElementParams, 'room'>
) => {
const { rootElement: element } = params || {}
let mockRootEl: HTMLElement
if (!element) {
mockRootEl = document.createElement('div')
mockRootEl.id = 'rootElement'
} else {
mockRootEl = element
}
document.body.appendChild(mockRootEl)
const promise = buildVideoElement({
room,
rootElement: mockRootEl,
...params,
})
const videoElement = mockRootEl.querySelector('video')
expect(videoElement).not.toBeNull()
// Create and dispatch the 'canplay' event using a more specific Event
const canplayEvent = document.createEvent('HTMLEvents')
canplayEvent.initEvent('canplay', true, true)
videoElement!.dispatchEvent(canplayEvent)
return promise
}
beforeEach(() => {
const newPeerMock = {
...mockPeer,
hasVideoSender: true,
// @ts-expect-error
remoteVideoTrack: new MediaStreamTrack('video'),
}
// @ts-expect-error
room.getRTCPeerById = jest.fn((_id: string) => newPeerMock)
// @ts-expect-error
room.localStream = new MediaStream([])
})
it('should make video element that contains a remote video track', async () => {
const result = await renderAndStartVideo()
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const videoElement = result.element.querySelector('video')
// Check if srcObject contains the remote video track
expect(videoElement!.srcObject).toBeInstanceOf(MediaStream)
const mediaStream = videoElement!.srcObject as MediaStream
// @ts-expect-error
expect(mediaStream.getTracks()).toContain(room.peer.remoteVideoTrack)
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(0)
})
it('should render the mcuLayers with video and member overlay', async () => {
// mock a call.joined event
dispatchMockedCallJoined({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
nodeId: 'node-id-1',
originCallId: callId,
capabilities: [],
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo()
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(2)
const children = Array.from(mcuLayers!.children)
// Check if the video overlay is present
const videoOverlay = children.find((child) =>
child.id.startsWith(SDK_PREFIX)
)
expect(videoOverlay).toBeDefined()
expect(videoOverlay?.id.startsWith(SDK_PREFIX)).toBe(true)
// Check if the member overlay is present
const memberOverlay = children.find((child) =>
child.id.startsWith(addOverlayPrefix('member-id-1'))
)
expect(memberOverlay).toBeDefined()
expect(
memberOverlay?.id.startsWith(addOverlayPrefix('member-id-1'))
).toBe(true)
})
it('should not render the video overlay if applyLocalVideoOverlay is false', async () => {
// mock a call.joined event
dispatchMockedCallJoined({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
nodeId: 'node-id-1',
originCallId: callId,
capabilities: [],
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo({
applyLocalVideoOverlay: false,
})
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(1)
const children = Array.from(mcuLayers!.children)
// Check if the video overlay is present
const videoOverlay = children.find((child) =>
child.id.startsWith(SDK_PREFIX)
)
expect(videoOverlay).not.toBeDefined()
// Check if the member overlay is present
const memberOverlay = children.find((child) =>
child.id.startsWith(addOverlayPrefix('member-id-1'))
)
expect(memberOverlay).toBeDefined()
expect(
memberOverlay?.id.startsWith(addOverlayPrefix('member-id-1'))
).toBe(true)
})
it('should not render the member overlay if applyMemberOverlay is false', async () => {
// mock a call.joined event
dispatchMockedCallJoined({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
nodeId: 'node-id-1',
originCallId: callId,
capabilities: [],
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo({ applyMemberOverlay: false })
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(1)
const children = Array.from(mcuLayers!.children)
// Check if the video overlay is present
const videoOverlay = children.find((child) =>
child.id.startsWith(SDK_PREFIX)
)
expect(videoOverlay).toBeDefined()
expect(videoOverlay?.id.startsWith(SDK_PREFIX)).toBe(true)
// Check if the member overlay is present
const memberOverlay = children.find((child) =>
child.id.startsWith(addOverlayPrefix('member-id-1'))
)
expect(memberOverlay).not.toBeDefined()
})
it('should render two elements if the IDs are different', async () => {
// mock a call.joined event
dispatchMockedCallJoined({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
nodeId: 'node-id-1',
originCallId: callId,
capabilities: [],
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const mockRootEl1 = document.createElement('div')
mockRootEl1.id = 'rootElement1'
const result1 = await renderAndStartVideo({ rootElement: mockRootEl1 })
expect(result1).toHaveProperty('element')
expect(result1).toHaveProperty('unsubscribe')
const mcuLayers1 = result1.element.querySelector('.mcuLayers')
expect(mcuLayers1).not.toBeNull()
expect(mcuLayers1!.childElementCount).toBe(2)
const mockRootEl2 = document.createElement('div')
mockRootEl2.id = 'rootElement2'
const result2 = await renderAndStartVideo({ rootElement: mockRootEl2 })
expect(result2).toHaveProperty('element')
expect(result2).toHaveProperty('unsubscribe')
const mcuLayers2 = result2.element.querySelector('.mcuLayers')
expect(mcuLayers2).not.toBeNull()
expect(mcuLayers2!.childElementCount).toBe(2)
expect(mcuLayers1).not.toBe(mcuLayers2)
})
it('should render only one element if the IDs are same', async () => {
// mock a call.joined event
dispatchMockedCallJoined({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
nodeId: 'node-id-1',
originCallId: callId,
capabilities: [],
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const mockRootEl = document.createElement('div')
mockRootEl.id = 'rootElement1'
const result1 = await renderAndStartVideo({ rootElement: mockRootEl })
expect(result1).toHaveProperty('element')
expect(result1).toHaveProperty('unsubscribe')
const mcuLayers1 = result1.element.querySelector('.mcuLayers')
expect(mcuLayers1).not.toBeNull()
expect(mcuLayers1!.childElementCount).toBe(2)
const result2 = await renderAndStartVideo({ rootElement: mockRootEl })
expect(result2).toHaveProperty('element')
expect(result2).toHaveProperty('unsubscribe')
const mcuLayers2 = result2.element.querySelector('.mcuLayers')
expect(mcuLayers2).not.toBeNull()
expect(mcuLayers2!.childElementCount).toBe(2)
expect(mcuLayers1).toBe(mcuLayers2)
})
it('should mirror the video overlay', async () => {
// mock a call.joined event
dispatchMockedCallJoined({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
nodeId: 'node-id-1',
originCallId: callId,
capabilities: [],
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo()
const mcuLayers = result.element.querySelector('.mcuLayers')
const videoElement = mcuLayers!.querySelector('video')
expect(room.localVideoOverlay!.mirrored).toBe(true)
expect(videoElement!.style.transform).toBe('scale(-1, 1)')
room.localVideoOverlay!.setMirror(false)
expect(room.localVideoOverlay!.mirrored).toBe(false)
expect(videoElement!.style.transform).toBe('scale(1, 1)')
room.localVideoOverlay!.setMirror(true)
expect(room.localVideoOverlay!.mirrored).toBe(true)
expect(videoElement!.style.transform).toBe('scale(-1, 1)')
})
it('should hide the video overlay', async () => {
// mock a call.joined event
dispatchMockedCallJoined({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
nodeId: 'node-id-1',
originCallId: callId,
capabilities: [],
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
await renderAndStartVideo()
expect(room.localVideoOverlay!.status).toBe('hidden')
room.localVideoOverlay!.show()
expect(room.localVideoOverlay!.status).toBe('visible')
room.localVideoOverlay!.hide()
expect(room.localVideoOverlay!.status).toBe('hidden')
})
})
})
describe('with VideoRoomSession', () => {
let room: VideoRoomSession
let stack: ReturnType<typeof configureFullStack>
let store: any
let jsdom: JSDOM
const callId = 'call-id-1'
const mockPeer = {
uuid: callId,
onRemoteSdp: jest.fn(),
}
const setupRoomForTests = () => {
// @ts-expect-error
room.getRTCPeerById = jest.fn((_id: string) => mockPeer)
// @ts-expect-error
room.runRTCPeerWorkers(callId)
}
beforeEach(() => {
stack = configureFullStack()
store = stack.store
room = createVideoRoomSessionObject({
store,
})
setupRoomForTests()
jsdom = new JSDOM('<!doctype html><html><body></body></html>')
global.document = jsdom.window.document
global.HTMLDivElement = jsdom.window.HTMLDivElement
})
afterEach(() => {
jest.clearAllMocks()
// @ts-expect-error
delete global.document
// @ts-expect-error
delete global.HTMLDivElement
})
it('should take a video element and return it with unsubscribe function', async () => {
const mockRootEl = document.createElement('div')
const result = await buildVideoElement({ room, rootElement: mockRootEl })
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
expect(result.element).toBeInstanceOf(HTMLDivElement)
expect(result.unsubscribe).toBeInstanceOf(Function)
})
it('should create a video element and return it with unsubscribe function', async () => {
const result = await buildVideoElement({ room })
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
expect(result.element).toBeInstanceOf(HTMLDivElement)
expect(result.unsubscribe).toBeInstanceOf(Function)
})
it('should unsubscribe from all events on unsubscribe', async () => {
const mockVideoEl = document.createElement('div')
const result = await buildVideoElement({ room, rootElement: mockVideoEl })
// Mock the room.off function to spy on it
room.off = jest.fn()
result.unsubscribe()
expect(room.off).toHaveBeenCalledWith('track', expect.any(Function))
expect(room.off).toHaveBeenCalledWith(
'layout.changed',
expect.any(Function)
)
expect(room.off).toHaveBeenCalledWith(
'member.updated.videoMuted',
expect.any(Function)
)
expect(room.off).toHaveBeenCalledWith('destroy', expect.any(Function))
})
describe('with remoteVideoTrack', () => {
const layoutEventPayload = {
jsonrpc: '2.0',
id: '79996d32-aefd-4e37-b1c1-382144334122',
method: 'signalwire.event',
params: {
event_type: 'video.layout.changed',
event_channel: 'd97016d7-6eaa-441e-a1c5-e817672a9dcd',
timestamp: 1716832047176777,
params: {
room_id: '8facb303-63da-41c5-9f6b-4c97255cdec2',
room_session_id: callId,
layout: {
layers: [
{
layer_index: 0,
x: 0,
y: 0,
z_index: 0,
height: 100,
width: 100,
member_id: 'member-id-1',
reservation: 'standard-1',
position: 'standard-1',
playing_file: false,
visible: true,
},
{
layer_index: 1,
x: 0,
y: 0,
z_index: 1,
height: 100,
width: 100,
member_id: null,
reservation: 'playback',
position: 'playback',
playing_file: false,
visible: true,
},
{
layer_index: 2,
x: 0,
y: 0,
z_index: 2,
height: 100,
width: 100,
member_id: null,
reservation: 'full-screen',
position: 'full-screen',
playing_file: false,
visible: true,
},
],
name: 'grid-responsive',
room_id: '8facb303-63da-41c5-9f6b-4c97255cdec2',
room_session_id: callId,
},
},
},
}
const renderAndStartVideo = (
params?: Omit<BuildVideoElementParams, 'room'>
) => {
const { rootElement: element } = params || {}
let mockRootEl: HTMLElement
if (!element) {
mockRootEl = document.createElement('div')
mockRootEl.id = 'rootElement'
} else {
mockRootEl = element
}
document.body.appendChild(mockRootEl)
const promise = buildVideoElement({
room,
rootElement: mockRootEl,
...params,
})
const videoElement = mockRootEl.querySelector('video')
expect(videoElement).not.toBeNull()
// Create and dispatch the 'canplay' event using a more specific Event
const canplayEvent = document.createEvent('HTMLEvents')
canplayEvent.initEvent('canplay', true, true)
videoElement!.dispatchEvent(canplayEvent)
return promise
}
beforeEach(() => {
const newPeerMock = {
...mockPeer,
hasVideoSender: true,
// @ts-expect-error
remoteVideoTrack: new MediaStreamTrack('video'),
}
// @ts-expect-error
room.getRTCPeerById = jest.fn((_id: string) => newPeerMock)
// @ts-expect-error
room.localStream = new MediaStream([])
})
it('should make video element that contains a remote video track', async () => {
const result = await renderAndStartVideo()
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const videoElement = result.element.querySelector('video')
// Check if srcObject contains the remote video track
expect(videoElement!.srcObject).toBeInstanceOf(MediaStream)
const mediaStream = videoElement!.srcObject as MediaStream
// @ts-expect-error
expect(mediaStream.getTracks()).toContain(room.peer.remoteVideoTrack)
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(0)
})
it('should render the mcuLayers with video and member overlay', async () => {
// mock a room.subscribed event
dispatchMockedRoomSubscribed({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo()
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(2)
const children = Array.from(mcuLayers!.children)
// Check if the video overlay is present
const videoOverlay = children.find((child) =>
child.id.startsWith(SDK_PREFIX)
)
expect(videoOverlay).toBeDefined()
expect(videoOverlay?.id.startsWith(SDK_PREFIX)).toBe(true)
// Check if the member overlay is present
const memberOverlay = children.find((child) =>
child.id.startsWith(addOverlayPrefix('member-id-1'))
)
expect(memberOverlay).toBeDefined()
expect(
memberOverlay?.id.startsWith(addOverlayPrefix('member-id-1'))
).toBe(true)
})
it('should not render the video overlay if applyLocalVideoOverlay is false', async () => {
// mock a room.subscribed event
dispatchMockedRoomSubscribed({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo({
applyLocalVideoOverlay: false,
})
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(1)
const children = Array.from(mcuLayers!.children)
// Check if the video overlay is present
const videoOverlay = children.find((child) =>
child.id.startsWith(SDK_PREFIX)
)
expect(videoOverlay).not.toBeDefined()
// Check if the member overlay is present
const memberOverlay = children.find((child) =>
child.id.startsWith(addOverlayPrefix('member-id-1'))
)
expect(memberOverlay).toBeDefined()
expect(
memberOverlay?.id.startsWith(addOverlayPrefix('member-id-1'))
).toBe(true)
})
it('should not render the member overlay if applyMemberOverlay is false', async () => {
// mock a room.subscribed event
dispatchMockedRoomSubscribed({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo({ applyMemberOverlay: false })
expect(result).toHaveProperty('element')
expect(result).toHaveProperty('unsubscribe')
const mcuLayers = result.element.querySelector('.mcuLayers')
expect(mcuLayers).not.toBeNull()
expect(mcuLayers!.childElementCount).toBe(1)
const children = Array.from(mcuLayers!.children)
// Check if the video overlay is present
const videoOverlay = children.find((child) =>
child.id.startsWith(SDK_PREFIX)
)
expect(videoOverlay).toBeDefined()
expect(videoOverlay?.id.startsWith(SDK_PREFIX)).toBe(true)
// Check if the member overlay is present
const memberOverlay = children.find((child) =>
child.id.startsWith(addOverlayPrefix('member-id-1'))
)
expect(memberOverlay).not.toBeDefined()
})
it('should render two elements if the IDs are different', async () => {
// mock a room.subscribed event
dispatchMockedRoomSubscribed({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const mockRootEl1 = document.createElement('div')
mockRootEl1.id = 'rootElement1'
const result1 = await renderAndStartVideo({ rootElement: mockRootEl1 })
expect(result1).toHaveProperty('element')
expect(result1).toHaveProperty('unsubscribe')
const mcuLayers1 = result1.element.querySelector('.mcuLayers')
expect(mcuLayers1).not.toBeNull()
expect(mcuLayers1!.childElementCount).toBe(2)
const mockRootEl2 = document.createElement('div')
mockRootEl2.id = 'rootElement2'
const result2 = await renderAndStartVideo({ rootElement: mockRootEl2 })
expect(result2).toHaveProperty('element')
expect(result2).toHaveProperty('unsubscribe')
const mcuLayers2 = result2.element.querySelector('.mcuLayers')
expect(mcuLayers2).not.toBeNull()
expect(mcuLayers2!.childElementCount).toBe(2)
expect(mcuLayers1).not.toBe(mcuLayers2)
})
it('should render only one element if the IDs are same', async () => {
// mock a room.subscribed event
dispatchMockedRoomSubscribed({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const mockRootEl = document.createElement('div')
mockRootEl.id = 'rootElement1'
const result1 = await renderAndStartVideo({ rootElement: mockRootEl })
expect(result1).toHaveProperty('element')
expect(result1).toHaveProperty('unsubscribe')
const mcuLayers1 = result1.element.querySelector('.mcuLayers')
expect(mcuLayers1).not.toBeNull()
expect(mcuLayers1!.childElementCount).toBe(2)
const result2 = await renderAndStartVideo({ rootElement: mockRootEl })
expect(result2).toHaveProperty('element')
expect(result2).toHaveProperty('unsubscribe')
const mcuLayers2 = result2.element.querySelector('.mcuLayers')
expect(mcuLayers2).not.toBeNull()
expect(mcuLayers2!.childElementCount).toBe(2)
expect(mcuLayers1).toBe(mcuLayers2)
})
it('should mirror the video overlay', async () => {
// mock a room.subscribed event
dispatchMockedRoomSubscribed({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
const result = await renderAndStartVideo()
const mcuLayers = result.element.querySelector('.mcuLayers')
const videoElement = mcuLayers!.querySelector('video')
expect(room.localVideoOverlay!.mirrored).toBe(true)
expect(videoElement!.style.transform).toBe('scale(-1, 1)')
room.localVideoOverlay!.setMirror(false)
expect(room.localVideoOverlay!.mirrored).toBe(false)
expect(videoElement!.style.transform).toBe('scale(1, 1)')
room.localVideoOverlay!.setMirror(true)
expect(room.localVideoOverlay!.mirrored).toBe(true)
expect(videoElement!.style.transform).toBe('scale(-1, 1)')
})
it('should hide the video overlay', async () => {
// mock a room.subscribed event
dispatchMockedRoomSubscribed({
session: stack.session,
callId: callId,
roomId: 'room-id-1',
roomSessionId: callId,
memberId: 'member-id-1',
})
// @ts-expect-error
stack.session.dispatch(actions.socketMessageAction(layoutEventPayload))
await renderAndStartVideo()
expect(room.localVideoOverlay!.status).toBe('hidden')
room.localVideoOverlay!.show()
expect(room.localVideoOverlay!.status).toBe('visible')
room.localVideoOverlay!.hide()
expect(room.localVideoOverlay!.status).toBe('hidden')
})
})
})
})