From fac7ed2636dd9903f29896020e45dfa045b3c52f Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Thu, 12 Jun 2025 16:08:06 +0200 Subject: [PATCH] test: enhance E2E tests with room and webhook functionality, add specific test scripts --- .github/workflows/wc-e2e-test.yaml | 85 ++++++++++++++++- frontend/webcomponent/package.json | 3 + .../events.test.ts} | 62 +++++-------- .../webcomponent/tests/e2e/core/room.test.ts | 19 ++++ .../tests/e2e/core/webhooks.test.ts | 93 +++++++++++++++++++ 5 files changed, 218 insertions(+), 44 deletions(-) rename frontend/webcomponent/tests/e2e/{openvidu-meet.test.ts => core/events.test.ts} (62%) create mode 100644 frontend/webcomponent/tests/e2e/core/webhooks.test.ts diff --git a/.github/workflows/wc-e2e-test.yaml b/.github/workflows/wc-e2e-test.yaml index 6711c00..3646c5b 100644 --- a/.github/workflows/wc-e2e-test.yaml +++ b/.github/workflows/wc-e2e-test.yaml @@ -6,8 +6,8 @@ on: jobs: - e2e-test-core: - name: E2E Tests Core + e2e-room-functionality-test: + name: E2E Room Functionality Tests runs-on: ov-actions-runner steps: - name: Setup Node.js @@ -28,7 +28,83 @@ jobs: # 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 + 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: RUN_MODE: CI PLAYWRIGHT_BROWSERS_PATH: /tmp/ms-playwright @@ -79,6 +155,9 @@ jobs: path: | frontend/webcomponent/test-results/*/*.webm retention-days: 2 + - name: Clean up + if: always() + uses: OpenVidu/actions/cleanup@main e2e-recording-access-test: name: E2E Recording Access Tests diff --git a/frontend/webcomponent/package.json b/frontend/webcomponent/package.json index db1989e..07605fd 100644 --- a/frontend/webcomponent/package.json +++ b/frontend/webcomponent/package.json @@ -8,6 +8,9 @@ "test:unit": "jest --forceExit --testPathPattern \"tests/unit\" --ci", "test:e2e": "playwright test", "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-recording-access": "playwright test tests/e2e/recording-access.test.ts", "lint": "eslint 'src/**/*.ts'" diff --git a/frontend/webcomponent/tests/e2e/openvidu-meet.test.ts b/frontend/webcomponent/tests/e2e/core/events.test.ts similarity index 62% rename from frontend/webcomponent/tests/e2e/openvidu-meet.test.ts rename to frontend/webcomponent/tests/e2e/core/events.test.ts index ec13231..3711048 100644 --- a/frontend/webcomponent/tests/e2e/openvidu-meet.test.ts +++ b/frontend/webcomponent/tests/e2e/core/events.test.ts @@ -1,5 +1,10 @@ import { test, expect } from '@playwright/test'; -import { waitForElementInIframe } from '../helpers/function-helpers'; +import { + deleteAllRecordings, + deleteAllRooms, + joinRoomAs, + waitForElementInIframe +} from '../../helpers/function-helpers'; let subscribedToAppErrors = false; @@ -41,40 +46,34 @@ test.describe('Web Component E2E Tests', () => { await context.storageState({ path: 'test_localstorage_state.json' }); }); - test.describe('Component Rendering', () => { - test('should load the web component with proper iframe', async ({ page }) => { - await page.click('#join-as-moderator'); - const component = page.locator('openvidu-meet'); - await expect(component).toBeVisible(); + test.afterAll(async ({ browser }) => { + const tempContext = await browser.newContext(); + const tempPage = await tempContext.newPage(); + await deleteAllRooms(tempPage); + await deleteAllRecordings(tempPage); - const hasIframe = await page.evaluate(() => { - const component = document.querySelector('openvidu-meet'); - return !!component?.shadowRoot?.querySelector('iframe'); - }); - expect(hasIframe).toBeTruthy(); - }); + await tempContext.close(); + await tempPage.close(); }); test.describe('Event Handling', () => { test('should successfully join as moderator and receive JOIN event', async ({ page }) => { - await page.click('#join-as-moderator'); - await waitForElementInIframe(page, 'ov-session'); + await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page); await page.waitForSelector('.event-JOIN'); const joinElements = await page.locator('.event-JOIN').all(); expect(joinElements.length).toBe(1); }); test('should successfully join as publisher and receive JOIN event', async ({ page }) => { - await page.click('#join-as-publisher'); - await waitForElementInIframe(page, 'ov-session'); + await joinRoomAs('publisher', `P-${Math.random().toString(36).substring(2, 9)}`, page); await page.waitForSelector('.event-JOIN'); const joinElements = await page.locator('.event-JOIN').all(); expect(joinElements.length).toBe(1); }); test('should successfully join to room and receive LEFT event when using leave command', async ({ page }) => { - await page.click('#join-as-moderator'); - await waitForElementInIframe(page, 'ov-session'); + await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page); + await page.click('#leave-room-btn'); await page.waitForSelector('.event-LEFT'); 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 ({ page }) => { - await page.click('#join-as-moderator'); - await waitForElementInIframe(page, 'ov-session'); + await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page); + const button = await waitForElementInIframe(page, '#leave-btn'); await button.click(); 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 ({ page }) => { - await page.click('#join-as-moderator'); - await waitForElementInIframe(page, 'ov-session'); + await joinRoomAs('moderator', `P-${Math.random().toString(36).substring(2, 9)}`, page); + await page.click('#end-meeting-btn'); await page.waitForSelector('.event-MEETING_ENDED'); const meetingEndedElements = await page.locator('.event-MEETING_ENDED').all(); @@ -108,23 +107,4 @@ test.describe('Web Component E2E Tests', () => { 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); - }); - }); }); diff --git a/frontend/webcomponent/tests/e2e/core/room.test.ts b/frontend/webcomponent/tests/e2e/core/room.test.ts index 0c9a415..4c9bab9 100644 --- a/frontend/webcomponent/tests/e2e/core/room.test.ts +++ b/frontend/webcomponent/tests/e2e/core/room.test.ts @@ -19,6 +19,7 @@ import { let subscribedToAppErrors = false; +// Test suite for room functionality in OpenVidu Meet test.describe('Room Functionality Tests', () => { const testAppUrl = 'http://localhost:5080'; const testRoomPrefix = 'testing-room'; @@ -69,6 +70,24 @@ test.describe('Room Functionality Tests', () => { 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 // ========================================== diff --git a/frontend/webcomponent/tests/e2e/core/webhooks.test.ts b/frontend/webcomponent/tests/e2e/core/webhooks.test.ts new file mode 100644 index 0000000..7ce0c5a --- /dev/null +++ b/frontend/webcomponent/tests/e2e/core/webhooks.test.ts @@ -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); + }); + }); +});