import { Builder, WebDriver } from 'selenium-webdriver'; import { TestAppConfig } from './selenium.conf'; import { OpenViduComponentsPO } from './utils.po.test'; const url = TestAppConfig.appUrl; describe('E2E: Screensharing features', () => { let browser: WebDriver; let utils: OpenViduComponentsPO; async function createChromeBrowser(): Promise { return await new Builder() .forBrowser(TestAppConfig.browserName) .withCapabilities(TestAppConfig.browserCapabilities) .setChromeOptions(TestAppConfig.browserOptions) .usingServer(TestAppConfig.seleniumAddress) .build(); } beforeEach(async () => { browser = await createChromeBrowser(); utils = new OpenViduComponentsPO(browser); }); afterEach(async () => { try { await utils.leaveRoom(); } catch (error) {} await browser.quit(); }); it('should toggle screensharing on and off twice, updating video count', async () => { await browser.get(`${url}&prejoin=false`); await utils.checkLayoutPresent(); // Enable screensharing await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('video')).toEqual(2); // Disable screensharing await utils.disableScreenShare(); expect(await utils.getNumberOfElements('video')).toEqual(1); // Enable again await utils.clickOn('#screenshare-btn'); await browser.sleep(500); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('video')).toEqual(2); // Disable again await utils.disableScreenShare(); expect(await utils.getNumberOfElements('video')).toEqual(1); }); it('should show screenshare and muted camera (camera off, screenshare on)', async () => { await browser.get(`${url}&prejoin=false`); await utils.checkLayoutPresent(); // Mute camera await utils.waitForElement('#camera-btn'); await utils.clickOn('#camera-btn'); // Enable screensharing const screenshareButton = await utils.waitForElement('#screenshare-btn'); expect(await screenshareButton.isDisplayed()).toBeTrue(); await screenshareButton.click(); await browser.sleep(500); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('video')).toEqual(2); // Disable screensharing await utils.disableScreenShare(); expect(await utils.getNumberOfElements('video')).toEqual(1); }); it('should display screensharing with a single pinned video', async () => { await browser.get(`${url}&prejoin=false`); await utils.checkLayoutPresent(); // Enable screensharing const screenshareButton = await utils.waitForElement('#screenshare-btn'); expect(await screenshareButton.isDisplayed()).toBeTrue(); await screenshareButton.click(); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); }); it('should replace pinned video when a second participant starts screensharing', async () => { const roomName = 'screensharingE2E'; const fixedUrl = `${url}&roomName=${roomName}&prejoin=false`; await browser.get(fixedUrl); await utils.checkLayoutPresent(); // First participant screenshares await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); // Second participant joins and screenshares const newTabScript = `window.open("${fixedUrl}")`; await browser.executeScript(newTabScript); const tabs = await browser.getAllWindowHandles(); await browser.switchTo().window(tabs[1]); await utils.checkLayoutPresent(); await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); expect(await utils.getNumberOfElements('video')).toEqual(4); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); // Switch back to first tab and check await browser.switchTo().window(tabs[0]); await browser.sleep(500); expect(await utils.getNumberOfElements('video')).toEqual(4); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); }); it('should unpin screensharing and restore previous pinned video when disabled', async () => { const roomName = 'screensharingtwoE2E'; const fixedUrl = `${url}&roomName=${roomName}&prejoin=false`; await browser.get(fixedUrl); await utils.checkLayoutPresent(); // First participant screenshares await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); // Second participant joins and screenshares const tabs = await utils.openTab(fixedUrl); await browser.switchTo().window(tabs[1]); await utils.checkLayoutPresent(); await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); expect(await utils.getNumberOfElements('video')).toEqual(4); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); // Disable screensharing for second participant await utils.disableScreenShare(); expect(await utils.getNumberOfElements('video')).toEqual(3); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); // Switch back to first tab and check await browser.switchTo().window(tabs[0]); await browser.sleep(500); expect(await utils.getNumberOfElements('video')).toEqual(3); await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfElements('.OV_big')).toEqual(1); }); it('should correctly share screen with microphone muted and maintain proper track state', async () => { // Helper for inspecting stream tracks const getMediaTracks = (className: string) => { return ` const tracks = document.getElementsByClassName('${className}')[0].srcObject.getTracks(); return tracks.map(track => ({ kind: track.kind, enabled: track.enabled, id: track.id, label: track.label }));`; }; // Setup: Navigate to room and skip prejoin await browser.get(`${url}&prejoin=false`); await utils.checkLayoutPresent(); // Step 1: First mute the microphone const micButton = await utils.waitForElement('#mic-btn'); await micButton.click(); // Step 2: Start screen sharing await utils.clickOn('#screenshare-btn'); // Step 3: Verify both streams are present await utils.waitForElement('.screen-type'); expect(await utils.getNumberOfElements('video')).toEqual(2); // Step 4: Verify screen share track properties const screenTracks: any[] = await browser.executeScript(getMediaTracks('screen-type')); expect(screenTracks.length).toEqual(1); expect(screenTracks[0].kind).toEqual('video'); expect(screenTracks[0].enabled).toBeTrue(); // Step 5: Verify microphone status indicators for both streams // await utils.waitForElement('#status-mic'); // const micStatusCount = await utils.getNumberOfElements('#status-mic'); // expect(micStatusCount).toEqual(2); // Step 6: Stop screen sharing and verify stream count await utils.clickOn('#screenshare-btn'); await browser.sleep(500); await utils.clickOn('#disable-screen-button'); await browser.sleep(500); expect(await utils.getNumberOfElements('video')).toEqual(1); }); // ==================== PIN/UNPIN TESTS ==================== // These tests demonstrate bugs in the pin system: // 1. Multiple screens can be auto-pinned simultaneously // 2. Manual unpins can be overridden by auto-pin logic when participants join it('should NOT have multiple screens pinned when both participants share screen', async () => { const roomName = 'pinBugCase1'; const fixedUrl = `${url}&roomName=${roomName}&prejoin=false`; // Participant A joins and shares screen await browser.get(fixedUrl); await utils.checkLayoutPresent(); await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); // Verify A's screen is pinned await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfPinnedStreams()).toEqual(1); const pinnedCountA1 = await utils.getNumberOfPinnedStreams(); console.log(`[Tab A] After A shares: ${pinnedCountA1} pinned stream(s)`); // Participant B joins const tabs = await utils.openTab(fixedUrl); await browser.switchTo().window(tabs[1]); await utils.checkLayoutPresent(); await browser.sleep(1000); // B should see A's screen pinned expect(await utils.getNumberOfElements('video')).toEqual(3); // 2 cameras + 1 screen expect(await utils.getNumberOfPinnedStreams()).toEqual(1); const pinnedCountB1 = await utils.getNumberOfPinnedStreams(); console.log(`[Tab B] After B joins: ${pinnedCountB1} pinned stream(s)`); // B shares screen await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); // B should see only their own screen pinned (auto-pin + unpin previous) expect(await utils.getNumberOfElements('video')).toEqual(4); // 2 cameras + 2 screens await utils.waitForElement('.OV_big'); const pinnedCountB2 = await utils.getNumberOfPinnedStreams(); console.log(`[Tab B] After B shares: ${pinnedCountB2} pinned stream(s)`); expect(pinnedCountB2).toEqual(1); // Should be 1, but implementation might show different // Switch to Tab A and check await browser.switchTo().window(tabs[0]); await browser.sleep(1000); expect(await utils.getNumberOfElements('video')).toEqual(4); // 2 cameras + 2 screens // BUG: In A's view, BOTH screens are pinned const pinnedCountA2 = await utils.getNumberOfPinnedStreams(); console.log(`[Tab A] After B shares: ${pinnedCountA2} pinned stream(s)`); // EXPECTED: Only B's screen should be pinned (the most recent one) // ACTUAL: Both A's and B's screens are pinned expect(pinnedCountA2).toEqual(1, 'BUG DETECTED: Multiple screens are pinned. Expected only the most recent screen to be pinned.'); }); it('should NOT re-pin manually unpinned screen when new participant joins', async () => { const roomName = 'pinBugCase2'; const fixedUrl = `${url}&roomName=${roomName}&prejoin=false`; // Participant A joins and shares screen await browser.get(fixedUrl); await utils.checkLayoutPresent(); await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); // Verify A's screen is auto-pinned await utils.waitForElement('.OV_big'); expect(await utils.getNumberOfPinnedStreams()).toEqual(1); // Participant B joins and shares screen const tabs = await utils.openTab(fixedUrl); await browser.switchTo().window(tabs[1]); await utils.checkLayoutPresent(); await browser.sleep(1000); await utils.waitForElement('#screenshare-btn'); await utils.clickOn('#screenshare-btn'); await browser.sleep(500); // B should see their own screen pinned expect(await utils.getNumberOfElements('video')).toEqual(4); // 2 cameras + 2 screens await utils.waitForElement('.OV_big'); let pinnedCountB = await utils.getNumberOfPinnedStreams(); console.log(`[Tab B] After B shares: ${pinnedCountB} pinned stream(s)`); // B manually unpins their own screen const screenStreams = await utils.getScreenShareStreams(); if (screenStreams.length > 0) { // Find B's own screen (it should be the pinned one) await utils.toggleStreamPin('.OV_big'); await browser.sleep(500); } // Verify B's screen is now unpinned pinnedCountB = await utils.getNumberOfPinnedStreams(); console.log(`[Tab B] After manually unpinning B's screen: ${pinnedCountB} pinned stream(s)`); expect(pinnedCountB).toEqual(0, 'B should have no pinned streams after manual unpin'); // B manually pins A's screen const screenElements = await utils.getScreenShareStreams(); if (screenElements.length >= 2) { // Pin the first screen that is not already pinned (should be A's screen) await utils.toggleStreamPin('.OV_stream.remote .screen-type'); await utils.toggleStreamPin('#pin-btn'); await browser.sleep(500); } // Verify A's screen is now pinned in B's view pinnedCountB = await utils.getNumberOfPinnedStreams(); console.log(`[Tab B] After manually pinning A's screen: ${pinnedCountB} pinned stream(s)`); expect(pinnedCountB).toEqual(1, "Only A's screen should be pinned"); // Participant C joins the room const tab3 = await utils.openTab(fixedUrl); await browser.switchTo().window(tab3[2]); await utils.checkLayoutPresent(); await browser.sleep(1500); // Switch back to B's tab await browser.switchTo().window(tabs[1]); await browser.sleep(1000); // B's screen should still be unpinned, but might get re-pinned automatically pinnedCountB = await utils.getNumberOfPinnedStreams(); console.log(`[Tab B] After C joins: ${pinnedCountB} pinned stream(s)`); // EXPECTED: No screens should be pinned (B manually unpinned everything) // ACTUAL: B's screen gets re-pinned automatically expect(pinnedCountB).toEqual(1, 'BUG DETECTED: Only one screen should be pinned after C joins.'); // Switch back to A's tab to verify await browser.switchTo().window(tabs[0]); await browser.sleep(500); const pinnedCountA2 = await utils.getNumberOfPinnedStreams(); console.log(`[Tab A] After C joins: ${pinnedCountA2} pinned stream(s)`); // EXPECTED: Only A's screen should be pinned // ACTUAL: A's screen remains pinned expect(pinnedCountA2).toEqual(1, "BUG DETECTED: A's screen should remain pinned after C joins."); }); });