tests: update WebComponent tests for improved attribute handling and event management

This commit is contained in:
juancarmore 2025-07-08 23:58:37 +02:00
parent 2b7466c6e3
commit 28ac4b0d8c
4 changed files with 200 additions and 65 deletions

View File

@ -1,9 +1,8 @@
import { describe, it, expect, jest } from '@jest/globals';
import { WEBCOMPONENT_ROOM_URL } from '../config';
import { describe, expect, it, jest } from '@jest/globals';
import { OpenViduMeet } from '../../src/components/OpenViduMeet';
import '../../src/index';
describe('Web Component Attributes', () => {
describe('OpenViduMeet WebComponent Attributes', () => {
let component: OpenViduMeet;
beforeEach(() => {
@ -21,8 +20,10 @@ describe('Web Component Attributes', () => {
expect(iframe).not.toBeNull();
expect(iframe?.getAttribute('allow')).toContain('camera');
expect(iframe?.getAttribute('allow')).toContain('microphone');
expect(iframe?.getAttribute('allow')).toContain('fullscreen');
expect(iframe?.getAttribute('allow')).toContain('display-capture');
expect(iframe?.getAttribute('allow')).toContain('fullscreen');
expect(iframe?.getAttribute('allow')).toContain('autoplay');
expect(iframe?.getAttribute('allow')).toContain('compute-pressure');
});
it('should reject rendering iframe when "room-url" attribute is missing', () => {
@ -41,25 +42,28 @@ describe('Web Component Attributes', () => {
});
it('should update iframe src when "room-url" attribute changes', () => {
component.setAttribute('room-url', WEBCOMPONENT_ROOM_URL);
const roomUrl = 'https://example.com/room/testRoom-123?secret=123456';
component.setAttribute('room-url', roomUrl);
component.setAttribute('user', 'testUser');
// Manually trigger the update (MutationObserver doesn't always trigger in tests)
(component as any).updateIframeSrc();
const iframe = component.shadowRoot?.querySelector('iframe');
expect(iframe?.src).toEqual(`${WEBCOMPONENT_ROOM_URL}?user=testUser`);
expect(iframe?.src).toEqual(`${roomUrl}&user=testUser`);
});
it('should extract origin from room-url and set as allowed origin', () => {
const roomUrl = 'https://example.com/room/123';
const domain = 'https://example.com';
const roomUrl = `${domain}/room/testRoom-123?secret=123456`;
component.setAttribute('room-url', roomUrl);
// Trigger update
(component as any).updateIframeSrc();
// Check if origin was extracted and set
expect((component as any).targetIframeOrigin).toBe('https://example.com');
expect((component as any).commandsManager.targetIframeOrigin).toBe('https://example.com');
expect((component as any).targetIframeOrigin).toBe(domain);
expect((component as any).commandsManager.targetIframeOrigin).toBe(domain);
expect((component as any).eventsManager.targetIframeOrigin).toBe(domain);
});
});

View File

@ -1,10 +1,11 @@
import { describe, it, expect, jest } from '@jest/globals';
import { describe, expect, it, jest } from '@jest/globals';
import { CommandsManager } from '../../src/components/CommandsManager';
import { OpenViduMeet } from '../../src/components/OpenViduMeet';
import '../../src/index';
import { WebComponentCommand } from '../../src/typings/ce/command.model';
import { CommandsManager } from '../../src/components/CommandsManager';
import { WebComponentEvent } from '../../src/typings/ce/event.model';
describe('OpenViduMeet Web Component Commands', () => {
describe('OpenViduMeet WebComponent Commands', () => {
let component: OpenViduMeet;
let commandsManager: CommandsManager;
@ -21,31 +22,121 @@ describe('OpenViduMeet Web Component Commands', () => {
});
it('should update allowedOrigin when setAllowedOrigin is called', () => {
const testOrigin = 'https://test-origin.com';
const testOrigin = 'https://example.com';
commandsManager.setTargetOrigin(testOrigin);
expect(commandsManager['targetIframeOrigin']).toBe(testOrigin);
// Check if it was updated
expect(commandsManager['targetIframeOrigin']).toBe(testOrigin);
expect((component as any).commandsManager.targetIframeOrigin).toBe(testOrigin);
});
it('should call commandsManager.leaveRoom when leaveRoom is called', () => {
const meetSpy = jest.spyOn(component['commandsManager'], 'leaveRoom');
it('should send initialize command with initialize()', () => {
const spy = jest.spyOn(commandsManager as any, 'sendMessage');
const spy = jest.spyOn(commandsManager, 'sendMessage' as keyof CommandsManager);
component.leaveRoom();
const testOrigin = 'https://example.com';
Object.defineProperty(window, 'location', {
value: { origin: testOrigin },
writable: true
});
expect(meetSpy).toHaveBeenCalled();
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith({ command: WebComponentCommand.LEAVE_ROOM });
commandsManager.initialize();
expect(spy).toHaveBeenCalledWith({
command: WebComponentCommand.INITIALIZE,
payload: { domain: testOrigin }
});
});
it('should call commandsManager.sendMessage when endMeeting is called', () => {
const spy = jest.spyOn(commandsManager, 'sendMessage' as keyof CommandsManager);
it('should subscribe and trigger event with on()', () => {
const callback = jest.fn();
commandsManager.on(component, WebComponentEvent.READY, callback);
const event = new CustomEvent(WebComponentEvent.READY, { detail: { foo: 'bar' } });
component.dispatchEvent(event);
expect(callback).toHaveBeenCalledWith({ foo: 'bar' });
});
it('should not subscribe unsupported events with on()', () => {
const callback = jest.fn();
commandsManager.on(component, 'not-supported' as any, callback);
const event = new CustomEvent('not-supported', { detail: { foo: 'bar' } });
component.dispatchEvent(event);
expect(callback).not.toHaveBeenCalled();
});
it('should subscribe and trigger event only once with once()', () => {
const callback = jest.fn();
commandsManager.once(component, WebComponentEvent.READY, callback);
const event = new CustomEvent(WebComponentEvent.READY, { detail: 123 });
component.dispatchEvent(event);
component.dispatchEvent(event);
expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith(123);
});
it('should unsubscribe a specific handler with off()', () => {
const callback = jest.fn();
commandsManager.on(component, WebComponentEvent.READY, callback);
commandsManager.off(component, WebComponentEvent.READY, callback);
const event = new CustomEvent(WebComponentEvent.READY, {});
component.dispatchEvent(event);
expect(callback).not.toHaveBeenCalled();
});
it('should unsubscribe all handlers for an event with off()', () => {
const cb1 = jest.fn();
const cb2 = jest.fn();
commandsManager.on(component, WebComponentEvent.READY, cb1);
commandsManager.on(component, WebComponentEvent.READY, cb2);
commandsManager.off(component, WebComponentEvent.READY);
const event = new CustomEvent(WebComponentEvent.READY, {});
component.dispatchEvent(event);
expect(cb1).not.toHaveBeenCalled();
expect(cb2).not.toHaveBeenCalled();
});
it('should call commandsManager.leaveRoom when leaveRoom is called', () => {
const leaveRoomSpy = jest.spyOn(component['commandsManager'], 'leaveRoom');
const sendMessageSpy = jest.spyOn(commandsManager, 'sendMessage' as keyof CommandsManager);
component.leaveRoom();
expect(leaveRoomSpy).toHaveBeenCalled();
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
expect(sendMessageSpy).toHaveBeenCalledWith({ command: WebComponentCommand.LEAVE_ROOM });
});
it('should call commandsManager.endMeeting when endMeeting is called', () => {
const endMeetingSpy = jest.spyOn(component['commandsManager'], 'endMeeting');
const sendMessageSpy = jest.spyOn(commandsManager, 'sendMessage' as keyof CommandsManager);
component.endMeeting();
expect(spy).toHaveBeenCalledWith({ command: WebComponentCommand.END_MEETING });
expect(endMeetingSpy).toHaveBeenCalled();
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
expect(sendMessageSpy).toHaveBeenCalledWith({ command: WebComponentCommand.END_MEETING });
});
it('should call commandsManager.kickParticipant when kickParticipant is called', () => {
const participantIdentity = 'test-participant';
const kickParticipantSpy = jest.spyOn(component['commandsManager'], 'kickParticipant');
const sendMessageSpy = jest.spyOn(commandsManager, 'sendMessage' as keyof CommandsManager);
component.kickParticipant(participantIdentity);
expect(kickParticipantSpy).toHaveBeenCalledWith(participantIdentity);
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
expect(sendMessageSpy).toHaveBeenCalledWith({
command: WebComponentCommand.KICK_PARTICIPANT,
payload: { participantIdentity }
});
});
it('should send message to iframe with correct origin', () => {
@ -60,18 +151,13 @@ describe('OpenViduMeet Web Component Commands', () => {
});
// Set allowed origin
(component as any).commandsManager.setTargetOrigin('https://test.com');
const testOrigin = 'https://example.com';
(component as any).commandsManager.setTargetOrigin(testOrigin);
// Send a message
(component as any).commandsManager.sendMessage({ command: 'TEST' });
// Check if postMessage was called correctly
expect(mockPostMessage).toHaveBeenCalledWith({ command: 'TEST' }, 'https://test.com');
expect(mockPostMessage).toHaveBeenCalledWith({ command: 'TEST' }, testOrigin);
});
// it('should call commandsManager.sendMessage when toggleChat is called', () => {
// const spy = jest.spyOn(component['commandsManager'], 'sendMessage');
// component.toggleChat();
// expect(spy).toHaveBeenCalledWith({ action: WebComponentCommand.TOGGLE_CHAT });
// });
});

View File

@ -1,12 +1,13 @@
import { describe, it, expect, jest } from '@jest/globals';
import { OpenViduMeet } from '../../src/components/OpenViduMeet';
import { describe, expect, it, jest } from '@jest/globals';
import { EventsManager } from '../../src/components/EventsManager';
import { OpenViduMeet } from '../../src/components/OpenViduMeet';
import '../../src/index';
describe('Web Component Events', () => {
describe('OpenViduMeet WebComponent Events', () => {
const testOrigin = 'http://example.com';
let component: OpenViduMeet;
let eventsManager: EventsManager;
const allowedOrigin = 'http://example.com';
beforeEach(() => {
component = document.createElement('openvidu-meet') as OpenViduMeet;
@ -19,26 +20,77 @@ describe('Web Component Events', () => {
document.body.innerHTML = '';
});
it('should update allowedOrigin when setAllowedOrigin is called', () => {
eventsManager.setTargetOrigin(testOrigin);
// Check if it was updated
expect((eventsManager as any).targetIframeOrigin).toBe(testOrigin);
expect((component as any).eventsManager.targetIframeOrigin).toBe(testOrigin);
});
it('should register message event listener on connection', () => {
const addEventListenerSpy = jest.spyOn(window, 'addEventListener');
// Call connectedCallback again (even though it was called when created)
(component as any).connectedCallback();
expect(addEventListenerSpy).toHaveBeenCalledWith('message', expect.any(Function));
});
it('should ignore invalid messages', () => {
eventsManager.setTargetOrigin(testOrigin);
const dispatchEventSpy = jest.spyOn(component, 'dispatchEvent');
const event = new MessageEvent('message', {
origin: allowedOrigin,
origin: testOrigin,
data: { invalid: 'data' }
});
(eventsManager as any).handleMessage(event);
expect(dispatchEventSpy).not.toHaveBeenCalled();
});
// TODO: Add test for leave room event
it('should ignore messages from unknown origins', () => {
const dispatchEventSpy = jest.spyOn(component, 'dispatchEvent');
const event = new MessageEvent('message', {
origin: 'https://not-allowed.com',
data: { event: 'READY', payload: {} }
});
(eventsManager as any).handleMessage(event);
expect(dispatchEventSpy).not.toHaveBeenCalled();
});
it('should dispatch event for valid messages from allowed origin', () => {
eventsManager.setTargetOrigin(testOrigin);
const dispatchEventSpy = jest.spyOn(component, 'dispatchEvent');
const event = new MessageEvent('message', {
origin: testOrigin,
data: { event: 'READY', payload: { foo: 'bar' } }
});
(eventsManager as any).handleMessage(event);
expect(dispatchEventSpy).toHaveBeenCalledWith(
expect.objectContaining({
type: 'READY',
detail: { foo: 'bar' }
})
);
});
it('should ignore messages without an event property', () => {
eventsManager.setTargetOrigin(testOrigin);
const dispatchEventSpy = jest.spyOn(component, 'dispatchEvent');
const event = new MessageEvent('message', {
origin: testOrigin,
data: { payload: {} }
});
(eventsManager as any).handleMessage(event);
expect(dispatchEventSpy).not.toHaveBeenCalled();
});
it('should remove message event listener on cleanup', () => {
const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
eventsManager.cleanup();
expect(removeEventListenerSpy).toHaveBeenCalledWith('message', expect.any(Function));
});
});

View File

@ -1,11 +1,12 @@
import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals';
import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals';
import { CommandsManager } from '../../src/components/CommandsManager';
import { OpenViduMeet } from '../../src/components/OpenViduMeet';
import '../../src/index';
import { WebComponentCommand } from '../../src/typings/ce/command.model';
import { WEBCOMPONENT_ROOM_URL } from '../config';
import { CommandsManager } from '../../src/components/CommandsManager';
describe('OpenViduMeet Event Handling', () => {
const testOrigin = window.location.origin;
let component: OpenViduMeet;
let commandsManager: CommandsManager;
@ -21,33 +22,22 @@ describe('OpenViduMeet Event Handling', () => {
document.body.innerHTML = '';
});
it('should be created correctly', () => {
expect(component).toBeDefined();
expect(component.shadowRoot).not.toBeNull();
});
it('should remove message event listener on disconnection', () => {
const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
// Call disconnectedCallback
(component as any).disconnectedCallback();
expect(removeEventListenerSpy).toHaveBeenCalledWith('message', expect.any(Function));
});
it('should call sendMessage when READY event is received', () => {
const sendMessageSpy = jest.spyOn(commandsManager, 'sendMessage' as keyof CommandsManager);
(component as any).eventsManager.setTargetOrigin(testOrigin);
// Mock a message event
const readyEvent = new MessageEvent('message', {
data: { event: 'READY' }
data: { event: 'READY' },
origin: testOrigin
});
window.dispatchEvent(readyEvent);
expect(sendMessageSpy).toHaveBeenCalledTimes(1);
expect(sendMessageSpy).toHaveBeenCalledWith({
command: WebComponentCommand.INITIALIZE,
payload: { domain: window.location.origin }
payload: { domain: testOrigin }
});
// Check if sendMessage was not called again
@ -58,12 +48,15 @@ describe('OpenViduMeet Event Handling', () => {
// Create a spy for dispatchEvent
const dispatchEventSpy = jest.spyOn(component, 'dispatchEvent');
(component as any).eventsManager.setTargetOrigin(testOrigin);
// Mock a message event
const messageEvent = new MessageEvent('message', {
data: {
event: 'test-event',
payload: { foo: 'bar' }
}
},
origin: testOrigin
});
// Manually call the handler
@ -88,7 +81,6 @@ describe('OpenViduMeet Event Handling', () => {
(component as any).loadTimeout = setTimeout(() => {}, 1000);
// Remove from DOM
(component as any).disconnectedCallback();
// Check if cleanup was called
@ -119,7 +111,8 @@ describe('OpenViduMeet Event Handling', () => {
document.body.appendChild(component);
// Set attributes
component.setAttribute('room-url', WEBCOMPONENT_ROOM_URL);
const roomUrl = 'https://example.com/room/testRoom-123?secret=123456';
component.setAttribute('room-url', roomUrl);
component.setAttribute('user', 'testUser');
component.setAttribute('role', 'publisher');
component.setAttribute('token', 'test-token');
@ -131,7 +124,7 @@ describe('OpenViduMeet Event Handling', () => {
const iframe = component.shadowRoot?.querySelector('iframe');
const src = iframe?.src;
expect(src).toContain(WEBCOMPONENT_ROOM_URL);
expect(src).toContain(roomUrl);
expect(src).toContain('user=testUser');
expect(src).toContain('role=publisher');
expect(src).toContain('token=test-token');