You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Filmstrip.ts 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import { Participant } from '../helpers/Participant';
  2. import BaseDialog from './BaseDialog';
  3. import BasePageObject from './BasePageObject';
  4. const LOCAL_VIDEO_XPATH = '//span[@id="localVideoContainer"]';
  5. const LOCAL_VIDEO_MENU_TRIGGER = '#local-video-menu-trigger';
  6. const LOCAL_USER_CONTROLS = 'aria/Local user controls';
  7. const HIDE_SELF_VIEW_BUTTON_XPATH = '//div[contains(@class, "popover")]//div[@id="hideselfviewButton"]';
  8. /**
  9. * Filmstrip elements.
  10. */
  11. export default class Filmstrip extends BasePageObject {
  12. /**
  13. * Asserts that {@code participant} shows or doesn't show the audio
  14. * mute icon for the conference participant identified by
  15. * {@code testee}.
  16. *
  17. * @param {Participant} testee - The {@code Participant} for whom we're checking the status of audio muted icon.
  18. * @param {boolean} reverse - If {@code true}, the method will assert the absence of the "mute" icon;
  19. * otherwise, it will assert its presence.
  20. * @returns {Promise<void>}
  21. */
  22. async assertAudioMuteIconIsDisplayed(testee: Participant, reverse = false): Promise<void> {
  23. let id;
  24. if (testee === this.participant) {
  25. id = 'localVideoContainer';
  26. } else {
  27. id = `participant_${await testee.getEndpointId()}`;
  28. }
  29. const mutedIconXPath
  30. = `//span[@id='${id}']//span[contains(@id, 'audioMuted')]//*[local-name()='svg' and @id='mic-disabled']`;
  31. await this.participant.driver.$(mutedIconXPath).waitForDisplayed({
  32. reverse,
  33. timeout: 5_000,
  34. timeoutMsg: `Audio mute icon is${reverse ? '' : ' not'} displayed for ${testee.name}`
  35. });
  36. }
  37. /**
  38. * Returns the remote display name for an endpoint.
  39. * @param endpointId The endpoint id.
  40. */
  41. async getRemoteDisplayName(endpointId: string) {
  42. const remoteDisplayName = this.participant.driver.$(`span[id="participant_${endpointId}_name"]`);
  43. await remoteDisplayName.moveTo();
  44. return await remoteDisplayName.getText();
  45. }
  46. /**
  47. * Returns the remote video id of a participant with endpointID.
  48. * @param endpointId
  49. */
  50. async getRemoteVideoId(endpointId: string) {
  51. const remoteDisplayName = this.participant.driver.$(`span[id="participant_${endpointId}"]`);
  52. await remoteDisplayName.moveTo();
  53. return await this.participant.driver.execute(eId =>
  54. document.evaluate(`//span[@id="participant_${eId}"]//video`,
  55. document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue?.srcObject?.id, endpointId);
  56. }
  57. /**
  58. * Returns the local video id.
  59. */
  60. getLocalVideoId() {
  61. return this.participant.driver.execute(
  62. 'return document.getElementById("localVideo_container").srcObject.id');
  63. }
  64. /**
  65. * Pins a participant by clicking on their thumbnail.
  66. * @param participant The participant.
  67. */
  68. async pinParticipant(participant: Participant) {
  69. const id = participant === this.participant
  70. ? 'localVideoContainer' : `participant_${await participant.getEndpointId()}`;
  71. await this.participant.driver.$(`//span[@id="${id}"]`).click();
  72. }
  73. /**
  74. * Gets avatar SRC attribute for the one displayed on small video thumbnail.
  75. * @param endpointId
  76. */
  77. async getAvatar(endpointId: string) {
  78. const elem = this.participant.driver.$(
  79. `//span[@id='participant_${endpointId}']//img[contains(@class,'userAvatar')]`);
  80. return await elem.isExisting() ? await elem.getAttribute('src') : null;
  81. }
  82. /**
  83. * Grants moderator rights to a participant.
  84. * @param participant
  85. */
  86. async grantModerator(participant: Participant) {
  87. await this.clickOnRemoteMenuLink(await participant.getEndpointId(), 'grantmoderatorlink', true);
  88. }
  89. /**
  90. * Clicks on the link in the remote participant actions menu.
  91. * @param participantId
  92. * @param linkClassname
  93. * @param dialogConfirm
  94. * @private
  95. */
  96. private async clickOnRemoteMenuLink(participantId: string, linkClassname: string, dialogConfirm: boolean) {
  97. await this.participant.driver.$(`//span[@id='participant_${participantId}']`).moveTo();
  98. await this.participant.driver.$(
  99. `//span[@id='participant_${participantId
  100. }']//span[@id='remotevideomenu']//div[@id='remote-video-menu-trigger']`).moveTo();
  101. const popoverElement = this.participant.driver.$(
  102. `//div[contains(@class, 'popover')]//div[contains(@class, '${linkClassname}')]`);
  103. await popoverElement.waitForExist();
  104. await popoverElement.waitForDisplayed();
  105. await popoverElement.click();
  106. if (dialogConfirm) {
  107. await new BaseDialog(this.participant).clickOkButton();
  108. }
  109. }
  110. /**
  111. * Mutes the audio of a participant.
  112. * @param participant
  113. */
  114. async muteAudio(participant: Participant) {
  115. await this.clickOnRemoteMenuLink(await participant.getEndpointId(), 'mutelink', false);
  116. }
  117. /**
  118. * Mutes the video of a participant.
  119. * @param participant
  120. */
  121. async muteVideo(participant: Participant) {
  122. await this.clickOnRemoteMenuLink(await participant.getEndpointId(), 'mutevideolink', true);
  123. }
  124. /**
  125. * Kicks a participant.
  126. * @param participantId
  127. */
  128. kickParticipant(participantId: string) {
  129. return this.clickOnRemoteMenuLink(participantId, 'kicklink', true);
  130. }
  131. /**
  132. * Clicks on the hide self view button from local video.
  133. */
  134. async hideSelfView() {
  135. // open local video menu
  136. await this.participant.driver.$(LOCAL_VIDEO_MENU_TRIGGER).moveTo();
  137. await this.participant.driver.$(LOCAL_USER_CONTROLS).moveTo();
  138. // click Hide self view button
  139. const hideSelfViewButton = this.participant.driver.$(HIDE_SELF_VIEW_BUTTON_XPATH);
  140. await hideSelfViewButton.waitForExist();
  141. await hideSelfViewButton.waitForClickable();
  142. await hideSelfViewButton.click();
  143. }
  144. /**
  145. * Checks whether the local self view is displayed or not.
  146. */
  147. assertSelfViewIsHidden(hidden: boolean) {
  148. return this.participant.driver.$(LOCAL_VIDEO_XPATH).waitForDisplayed({
  149. reverse: hidden,
  150. timeout: 5000,
  151. timeoutMsg: `Local video thumbnail is${hidden ? '' : ' not'} displayed for ${this.participant.name}`
  152. });
  153. }
  154. /**
  155. * Toggles the filmstrip.
  156. */
  157. async toggle() {
  158. const toggleButton = this.participant.driver.$('#toggleFilmstripButton');
  159. await toggleButton.moveTo();
  160. await toggleButton.waitForDisplayed();
  161. await toggleButton.click();
  162. }
  163. /**
  164. * Asserts that the remote videos are hidden or not.
  165. * @param reverse
  166. */
  167. assertRemoteVideosHidden(reverse = false) {
  168. return this.participant.driver.waitUntil(
  169. async () =>
  170. await this.participant.driver.$$('//div[@id="remoteVideos" and contains(@class, "hidden")]').length > 0,
  171. {
  172. timeout: 10_000, // 10 seconds
  173. timeoutMsg: `Timeout waiting fore remote videos to be hidden: ${!reverse}.`
  174. }
  175. );
  176. }
  177. /**
  178. * Counts the displayed remote video thumbnails.
  179. */
  180. async countVisibleThumbnails() {
  181. return (await this.participant.driver.$$('//div[@id="remoteVideos"]//span[contains(@class,"videocontainer")]')
  182. .filter(thumbnail => thumbnail.isDisplayed())).length;
  183. }
  184. }