test: enhance E2E tests with room and webhook functionality, add specific test scripts

This commit is contained in:
Carlos Santos 2025-06-12 16:08:06 +02:00
parent eb9de7e9de
commit fac7ed2636
5 changed files with 218 additions and 44 deletions

View File

@ -6,8 +6,8 @@ on:
jobs: jobs:
e2e-test-core: e2e-room-functionality-test:
name: E2E Tests Core name: E2E Room Functionality Tests
runs-on: ov-actions-runner runs-on: ov-actions-runner
steps: steps:
- name: Setup Node.js - name: Setup Node.js
@ -28,7 +28,83 @@ jobs:
# Install Playwright browsers # Install Playwright browsers
mkdir -p /tmp/ms-playwright mkdir -p /tmp/ms-playwright
PLAYWRIGHT_BROWSERS_PATH=/tmp/ms-playwright npx playwright install --with-deps chromium PLAYWRIGHT_BROWSERS_PATH=/tmp/ms-playwright npx playwright install --with-deps chromium
npm run test:e2e-core npm run test:e2e-core-room
env:
RUN_MODE: CI
PLAYWRIGHT_BROWSERS_PATH: /tmp/ms-playwright
- name: Upload failed test videos
if: always()
uses: actions/upload-artifact@v4
with:
name: test-videos
path: |
frontend/webcomponent/test-results/*/*.webm
retention-days: 2
- name: Clean up
if: always()
uses: OpenVidu/actions/cleanup@main
e2e-events-functionality-test:
name: E2E Events Functionality Tests
runs-on: ov-actions-runner
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.13'
- name: Setup OpenVidu Local Deployment
uses: OpenVidu/actions/start-openvidu-local-deployment@main
- name: Setup OpenVidu Meet
uses: OpenVidu/actions/start-openvidu-meet@main
env:
MEET_WEBHOOK_ENABLED: true
- name: Start OpenVidu Meet Testapp
uses: OpenVidu/actions/start-openvidu-meet-testapp@main
- name: Run tests
run: |
cd frontend/webcomponent
# Install Playwright browsers
mkdir -p /tmp/ms-playwright
PLAYWRIGHT_BROWSERS_PATH=/tmp/ms-playwright npx playwright install --with-deps chromium
npm run test:e2e-core-events
env:
RUN_MODE: CI
PLAYWRIGHT_BROWSERS_PATH: /tmp/ms-playwright
- name: Upload failed test videos
if: always()
uses: actions/upload-artifact@v4
with:
name: test-videos
path: |
frontend/webcomponent/test-results/*/*.webm
retention-days: 2
- name: Clean up
if: always()
uses: OpenVidu/actions/cleanup@main
e2e-webhooks-functionality-test:
name: E2E Webhooks Functionality Tests
runs-on: ov-actions-runner
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.13'
- name: Setup OpenVidu Local Deployment
uses: OpenVidu/actions/start-openvidu-local-deployment@main
- name: Setup OpenVidu Meet
uses: OpenVidu/actions/start-openvidu-meet@main
env:
MEET_WEBHOOK_ENABLED: true
- name: Start OpenVidu Meet Testapp
uses: OpenVidu/actions/start-openvidu-meet-testapp@main
- name: Run tests
run: |
cd frontend/webcomponent
# Install Playwright browsers
mkdir -p /tmp/ms-playwright
PLAYWRIGHT_BROWSERS_PATH=/tmp/ms-playwright npx playwright install --with-deps chromium
npm run test:e2e-core-webhooks
env: env:
RUN_MODE: CI RUN_MODE: CI
PLAYWRIGHT_BROWSERS_PATH: /tmp/ms-playwright PLAYWRIGHT_BROWSERS_PATH: /tmp/ms-playwright
@ -79,6 +155,9 @@ jobs:
path: | path: |
frontend/webcomponent/test-results/*/*.webm frontend/webcomponent/test-results/*/*.webm
retention-days: 2 retention-days: 2
- name: Clean up
if: always()
uses: OpenVidu/actions/cleanup@main
e2e-recording-access-test: e2e-recording-access-test:
name: E2E Recording Access Tests name: E2E Recording Access Tests

View File

@ -8,6 +8,9 @@
"test:unit": "jest --forceExit --testPathPattern \"tests/unit\" --ci", "test:unit": "jest --forceExit --testPathPattern \"tests/unit\" --ci",
"test:e2e": "playwright test", "test:e2e": "playwright test",
"test:e2e-core": "playwright test tests/e2e/core/", "test:e2e-core": "playwright test tests/e2e/core/",
"test:e2e-core-room": "playwright test tests/e2e/core/room.test.ts",
"test:e2e-core-events": "playwright test tests/e2e/core/events.test.ts",
"test:e2e-core-webhooks": "playwright test tests/e2e/core/webhooks.test.ts",
"test:e2e-ui-features": "playwright test tests/e2e/ui-feature-preferences.test.ts", "test:e2e-ui-features": "playwright test tests/e2e/ui-feature-preferences.test.ts",
"test:e2e-recording-access": "playwright test tests/e2e/recording-access.test.ts", "test:e2e-recording-access": "playwright test tests/e2e/recording-access.test.ts",
"lint": "eslint 'src/**/*.ts'" "lint": "eslint 'src/**/*.ts'"

View File

@ -1,5 +1,10 @@
import { test, expect } from '@playwright/test'; import { test, expect } from '@playwright/test';
import { waitForElementInIframe } from '../helpers/function-helpers'; import {
deleteAllRecordings,
deleteAllRooms,
joinRoomAs,
waitForElementInIframe
} from '../../helpers/function-helpers';
let subscribedToAppErrors = false; let subscribedToAppErrors = false;
@ -41,40 +46,34 @@ test.describe('Web Component E2E Tests', () => {
await context.storageState({ path: 'test_localstorage_state.json' }); await context.storageState({ path: 'test_localstorage_state.json' });
}); });
test.describe('Component Rendering', () => { test.afterAll(async ({ browser }) => {
test('should load the web component with proper iframe', async ({ page }) => { const tempContext = await browser.newContext();
await page.click('#join-as-moderator'); const tempPage = await tempContext.newPage();
const component = page.locator('openvidu-meet'); await deleteAllRooms(tempPage);
await expect(component).toBeVisible(); await deleteAllRecordings(tempPage);
const hasIframe = await page.evaluate(() => { await tempContext.close();
const component = document.querySelector('openvidu-meet'); await tempPage.close();
return !!component?.shadowRoot?.querySelector('iframe');
});
expect(hasIframe).toBeTruthy();
});
}); });
test.describe('Event Handling', () => { test.describe('Event Handling', () => {
test('should successfully join as moderator and receive JOIN event', async ({ page }) => { test('should successfully join as moderator and receive JOIN event', async ({ page }) => {
await page.click('#join-as-moderator'); await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page);
await waitForElementInIframe(page, 'ov-session');
await page.waitForSelector('.event-JOIN'); await page.waitForSelector('.event-JOIN');
const joinElements = await page.locator('.event-JOIN').all(); const joinElements = await page.locator('.event-JOIN').all();
expect(joinElements.length).toBe(1); expect(joinElements.length).toBe(1);
}); });
test('should successfully join as publisher and receive JOIN event', async ({ page }) => { test('should successfully join as publisher and receive JOIN event', async ({ page }) => {
await page.click('#join-as-publisher'); await joinRoomAs('publisher', `P-${Math.random().toString(36).substring(2, 9)}`, page);
await waitForElementInIframe(page, 'ov-session');
await page.waitForSelector('.event-JOIN'); await page.waitForSelector('.event-JOIN');
const joinElements = await page.locator('.event-JOIN').all(); const joinElements = await page.locator('.event-JOIN').all();
expect(joinElements.length).toBe(1); expect(joinElements.length).toBe(1);
}); });
test('should successfully join to room and receive LEFT event when using leave command', async ({ page }) => { test('should successfully join to room and receive LEFT event when using leave command', async ({ page }) => {
await page.click('#join-as-moderator'); await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page);
await waitForElementInIframe(page, 'ov-session');
await page.click('#leave-room-btn'); await page.click('#leave-room-btn');
await page.waitForSelector('.event-LEFT'); await page.waitForSelector('.event-LEFT');
const leftElements = await page.locator('.event-LEFT').all(); const leftElements = await page.locator('.event-LEFT').all();
@ -84,8 +83,8 @@ test.describe('Web Component E2E Tests', () => {
test('should successfully join to room and receive LEFT event when using disconnect button', async ({ test('should successfully join to room and receive LEFT event when using disconnect button', async ({
page page
}) => { }) => {
await page.click('#join-as-moderator'); await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page);
await waitForElementInIframe(page, 'ov-session');
const button = await waitForElementInIframe(page, '#leave-btn'); const button = await waitForElementInIframe(page, '#leave-btn');
await button.click(); await button.click();
await page.waitForSelector('.event-LEFT'); await page.waitForSelector('.event-LEFT');
@ -96,8 +95,8 @@ test.describe('Web Component E2E Tests', () => {
test('should successfully join to room and receive MEETING_ENDED event when using end meeting command', async ({ test('should successfully join to room and receive MEETING_ENDED event when using end meeting command', async ({
page page
}) => { }) => {
await page.click('#join-as-moderator'); await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page);
await waitForElementInIframe(page, 'ov-session');
await page.click('#end-meeting-btn'); await page.click('#end-meeting-btn');
await page.waitForSelector('.event-MEETING_ENDED'); await page.waitForSelector('.event-MEETING_ENDED');
const meetingEndedElements = await page.locator('.event-MEETING_ENDED').all(); const meetingEndedElements = await page.locator('.event-MEETING_ENDED').all();
@ -108,23 +107,4 @@ test.describe('Web Component E2E Tests', () => {
expect(leftEventElements.length).toBe(0); expect(leftEventElements.length).toBe(0);
}); });
}); });
test.describe('Webhook Handling', () => {
test('should successfully receive meetingStarted and meetingEnded webhooks', async ({ page }) => {
await page.click('#join-as-moderator');
await page.waitForTimeout(1000); // Wait for 1 second to ensure the meeting has started
await page.screenshot({ path: 'screenshot.png' });
await waitForElementInIframe(page, 'ov-session');
await page.waitForSelector('.webhook-meetingStarted');
const meetingStartedElements = await page.locator('.webhook-meetingStarted').all();
expect(meetingStartedElements.length).toBe(1);
// End the meeting
await page.click('#end-meeting-btn');
await page.waitForSelector('.webhook-meetingEnded');
const meetingEndedElements = await page.locator('.webhook-meetingEnded').all();
expect(meetingEndedElements.length).toBe(1);
});
});
}); });

View File

@ -19,6 +19,7 @@ import {
let subscribedToAppErrors = false; let subscribedToAppErrors = false;
// Test suite for room functionality in OpenVidu Meet
test.describe('Room Functionality Tests', () => { test.describe('Room Functionality Tests', () => {
const testAppUrl = 'http://localhost:5080'; const testAppUrl = 'http://localhost:5080';
const testRoomPrefix = 'testing-room'; const testRoomPrefix = 'testing-room';
@ -69,6 +70,24 @@ test.describe('Room Functionality Tests', () => {
await tempPage.close(); await tempPage.close();
}); });
// ==========================================
// COMPONENT RENDERING TESTS
// ==========================================
test.describe('Component Rendering', () => {
test('should load the web component with proper iframe', async ({ page }) => {
await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page);
const component = page.locator('openvidu-meet');
await expect(component).toBeVisible();
const hasIframe = await page.evaluate(() => {
const component = document.querySelector('openvidu-meet');
return !!component?.shadowRoot?.querySelector('iframe');
});
expect(hasIframe).toBeTruthy();
});
});
// ========================================== // ==========================================
// BASIC FUNCTIONALITY TESTS // BASIC FUNCTIONALITY TESTS
// ========================================== // ==========================================

View File

@ -0,0 +1,93 @@
import { test, expect } from '@playwright/test';
import { deleteAllRecordings, deleteAllRooms, joinRoomAs, startStopRecording } from '../../helpers/function-helpers';
let subscribedToAppErrors = false;
test.describe('Web Component E2E Tests', () => {
const testAppUrl = 'http://localhost:5080';
const testRoomPrefix = 'test-room';
test.beforeAll(async ({ browser }) => {
// Create a test room before all tests
const tempContext = await browser.newContext();
const tempPage = await tempContext.newPage();
await tempPage.goto(testAppUrl);
await tempPage.waitForSelector('.create-room');
await tempPage.fill('#room-id-prefix', testRoomPrefix);
await tempPage.click('.create-room-btn');
await tempPage.waitForSelector(`#${testRoomPrefix}`);
await tempPage.close();
await tempContext.close();
});
test.beforeEach(async ({ page }) => {
if (!subscribedToAppErrors) {
page.on('console', (msg) => {
const type = msg.type();
const tag = type === 'error' ? 'ERROR' : type === 'warning' ? 'WARNING' : 'LOG';
console.log('[' + tag + ']', msg.text());
});
subscribedToAppErrors = true;
}
await page.goto(testAppUrl);
await page.waitForSelector('.rooms-container');
await page.waitForSelector(`#${testRoomPrefix}`);
await page.click('.dropdown-button');
await page.waitForSelector('#join-as-moderator');
await page.waitForSelector('#join-as-publisher');
});
test.afterEach(async ({ context }) => {
await context.storageState({ path: 'test_localstorage_state.json' });
});
test.afterAll(async ({ browser }) => {
const tempContext = await browser.newContext();
const tempPage = await tempContext.newPage();
await deleteAllRooms(tempPage);
await deleteAllRecordings(tempPage);
await tempContext.close();
await tempPage.close();
});
test.describe('Webhook Handling', () => {
test('should successfully receive meetingStarted and meetingEnded webhooks', async ({ page }) => {
await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page);
await page.waitForSelector('.webhook-meetingStarted');
const meetingStartedElements = await page.locator('.webhook-meetingStarted').all();
expect(meetingStartedElements.length).toBe(1);
// End the meeting
await page.click('#end-meeting-btn');
await page.waitForSelector('.webhook-meetingEnded');
const meetingEndedElements = await page.locator('.webhook-meetingEnded').all();
expect(meetingEndedElements.length).toBe(1);
});
test('should successfully receive recordingStarted, recordingUpdated and recordingEnded webhooks', async ({
page
}) => {
await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page);
// Start recording
await startStopRecording(page, 'start');
await page.waitForSelector('.webhook-recordingStarted');
const recordingStartedElements = await page.locator('.webhook-recordingStarted').all();
expect(recordingStartedElements.length).toBe(1);
// Update recording
await page.waitForTimeout(2000); // Wait for a bit before updating
await page.waitForSelector('.webhook-recordingUpdated');
const recordingUpdatedElements = await page.locator('.webhook-recordingUpdated').all();
expect(recordingUpdatedElements.length).toBe(1);
// End recording
await startStopRecording(page, 'stop');
await page.waitForSelector('.webhook-recordingEnded');
const recordingEndedElements = await page.locator('.webhook-recordingEnded').all();
expect(recordingEndedElements.length).toBe(1);
});
});
});