diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eServerSdkTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eServerSdkTest.java index 1bfd952f9..442d093b2 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eServerSdkTest.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eServerSdkTest.java @@ -154,11 +154,6 @@ public class OpenViduTestAppE2eServerSdkTest extends AbstractOpenViduTestappE2eT log.info("{} SDK {} {}-layer publisher to Chrome and Firefox subscribers", sdk, codec, layers); - // Both browsers join the room as subscriber-only participants with - // adaptiveStream disabled (the received layer only changes through the - // testapp's max-video-quality selector), each with its own identity (a - // second join with the testapp's default identity would kick the first - // browser out of the room) for (OpenViduTestappUser user : subscribers) { this.addSubscriber(user, false); WebElement participantNameInput = user.getDriver().findElement(By.id("participant-name-input-0")); @@ -167,6 +162,9 @@ public class OpenViduTestAppE2eServerSdkTest extends AbstractOpenViduTestappE2eT user.getDriver().findElements(By.className("connect-btn")).forEach(el -> el.sendKeys(Keys.ENTER)); user.getEventManager().waitUntilEventReaches("connected", "RoomEvent", 1); } + for (OpenViduTestappUser user : subscribers) { + user.getEventManager().waitUntilEventReaches("active", "ParticipantEvent", 1); + } this.startServerSdkPublisher(sdk, "TestRoom", codec, multiLayer); diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java index a2dcd072c..96b90a4cc 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java @@ -55,6 +55,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys; +import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; @@ -4740,4 +4741,73 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { this.waitUntilSubscriberFrameWidthIs(user, subscriberVideo, 1920); } + @Test + @DisplayName("Remote video element survives participant changes") + void remoteVideoElementSurvivesParticipantChangesTest() throws Exception { + // openvidu-testapp test: it must keep the DOM elements of the remote tracks + // already rendered when the remote participant list changes + OpenViduTestappUser publisher = setupBrowserAndConnectToOpenViduTestapp("chrome"); + OpenViduTestappUser subscriber = setupBrowserAndConnectToOpenViduTestapp("chrome"); + OpenViduTestappUser newcomer = setupBrowserAndConnectToOpenViduTestapp("chrome"); + + log.info("Remote video element survives participant changes"); + + this.addOnlyPublisherVideo(publisher, false, false, false); + this.joinRoomAs(publisher, "publisher"); + publisher.getEventManager().waitUntilEventReaches("localTrackPublished", "RoomEvent", 1); + + this.addSubscriber(subscriber, false); + this.joinRoomAs(subscriber, "subscriber"); + subscriber.getEventManager().waitUntilEventReaches("trackSubscribed", "RoomEvent", 1); + subscriber.getWaiter().until(ExpectedConditions.numberOfElementsToBe(By.tagName("video"), 1)); + WebElement remoteVideo = subscriber.getDriver() + .findElement(By.cssSelector("#openvidu-instance-0 video.remote")); + this.waitUntilSubscriberFramesPerSecondNotZero(subscriber, remoteVideo); + + // A participant joins: the subscriber's remote participant list grows + this.addSubscriber(newcomer, false); + this.joinRoomAs(newcomer, "newcomer"); + subscriber.getEventManager().waitUntilEventReaches("participantConnected", "RoomEvent", 1); + this.assertRemoteVideoElementKept(subscriber, remoteVideo, 1, "a participant joined"); + + // The publisher publishes a second video track: its publication list grows + publisher.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .add-video-btn")).click(); + publisher.getEventManager().waitUntilEventReaches("localTrackPublished", "RoomEvent", 2); + subscriber.getEventManager().waitUntilEventReaches("trackSubscribed", "RoomEvent", 2); + subscriber.getWaiter().until(ExpectedConditions.numberOfElementsToBe(By.tagName("video"), 2)); + this.assertRemoteVideoElementKept(subscriber, remoteVideo, 2, "the publisher published a second track"); + + // A participant leaves: the subscriber's remote participant list shrinks + gracefullyLeaveParticipants(newcomer, 1); + subscriber.getEventManager().waitUntilEventReaches("participantDisconnected", "RoomEvent", 1); + this.assertRemoteVideoElementKept(subscriber, remoteVideo, 2, "a participant left"); + + // And the kept element is still a playing video + this.waitUntilSubscriberFramesPerSecondNotZero(subscriber, remoteVideo); + + gracefullyLeaveParticipants(subscriber, 1); + gracefullyLeaveParticipants(publisher, 1); + } + + private void joinRoomAs(OpenViduTestappUser user, String identity) throws Exception { + WebElement participantNameInput = user.getDriver().findElement(By.id("participant-name-input-0")); + participantNameInput.clear(); + participantNameInput.sendKeys(identity); + user.getDriver().findElements(By.className("connect-btn")).forEach(el -> el.sendKeys(Keys.ENTER)); + user.getEventManager().waitUntilEventReaches("connected", "RoomEvent", 1); + } + + private void assertRemoteVideoElementKept(OpenViduTestappUser user, WebElement remoteVideo, int expectedVideos, + String change) { + try { + Assertions.assertTrue(remoteVideo.isDisplayed(), + "The remote video element is no longer displayed after " + change); + } catch (StaleElementReferenceException e) { + Assertions.fail("The remote video element was re-created after " + change + + ": the WebElement located before is stale", e); + } + Assertions.assertEquals(expectedVideos, user.getDriver().findElements(By.tagName("video")).size(), + "Wrong number of videos after " + change); + } + } diff --git a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html index fd0f02691..882482169 100644 --- a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html +++ b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html @@ -95,7 +95,7 @@ [index]="index" [participantEvents]="participantEvents" [trackEvents]="trackEvents" [earlyParticipantEvents]="earlyParticipantEvents" [earlyParticipantListeners]="earlyParticipantListeners" [earlyTrackEvents]="earlyTrackEvents" [earlyTrackListeners]="earlyTrackListeners"> - @for (participant of room.remoteParticipants | keyvalue; track participant) { + @for (participant of room.remoteParticipants | keyvalue; track participant.value.sid) {
- @for (trackPublication of participant.audioTrackPublications| keyvalue; track trackPublication) { + @for (trackPublication of participant.audioTrackPublications | keyvalue; track trackPublication.key) { }
- @for (trackPublication of participant.videoTrackPublications | keyvalue; track trackPublication) { + @for (trackPublication of participant.videoTrackPublications | keyvalue; track trackPublication.key) {