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.

ParticipantsPane.ts 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. import { ChainablePromiseElement } from 'webdriverio';
  2. import { Participant } from '../helpers/Participant';
  3. import AVModerationMenu from './AVModerationMenu';
  4. import BasePageObject from './BasePageObject';
  5. /**
  6. * Classname of the closed/hidden participants pane
  7. */
  8. const PARTICIPANTS_PANE = 'participants_pane';
  9. const INVITE = 'Invite someone';
  10. /**
  11. * Represents the participants pane from the UI.
  12. */
  13. export default class ParticipantsPane extends BasePageObject {
  14. /**
  15. * Gets the audio video moderation menu.
  16. */
  17. getAVModerationMenu() {
  18. return new AVModerationMenu(this.participant);
  19. }
  20. /**
  21. * Checks if the pane is open.
  22. */
  23. isOpen() {
  24. return this.participant.driver.$(`.${PARTICIPANTS_PANE}`).isExisting();
  25. }
  26. /**
  27. * Clicks the "participants" toolbar button to open the participants pane.
  28. */
  29. async open() {
  30. await this.participant.getToolbar().clickParticipantsPaneButton();
  31. const pane = this.participant.driver.$(`.${PARTICIPANTS_PANE}`);
  32. await pane.waitForExist();
  33. await pane.waitForStable();
  34. await pane.waitForDisplayed();
  35. }
  36. /**
  37. * Clicks the "participants" toolbar button to close the participants pane.
  38. */
  39. async close() {
  40. await this.participant.getToolbar().clickCloseParticipantsPaneButton();
  41. await this.participant.driver.$(`.${PARTICIPANTS_PANE}`).waitForDisplayed({ reverse: true });
  42. }
  43. /**
  44. * Asserts that {@code participant} shows or doesn't show the video mute icon for the conference participant
  45. * identified by {@code testee}.
  46. *
  47. * @param {Participant} testee - The {@code Participant} for whom we're checking the status of audio muted icon.
  48. * @param {boolean} reverse - If {@code true}, the method will assert the absence of the "mute" icon;
  49. * otherwise, it will assert its presence.
  50. * @returns {Promise<void>}
  51. */
  52. async assertVideoMuteIconIsDisplayed(testee: Participant, reverse = false): Promise<void> {
  53. const isOpen = await this.isOpen();
  54. if (!isOpen) {
  55. await this.open();
  56. }
  57. const id = `participant-item-${await testee.getEndpointId()}`;
  58. const mutedIconXPath
  59. = `//div[@id='${id}']//div[contains(@class, 'indicators')]//*[local-name()='svg' and @id='videoMuted']`;
  60. await this.participant.driver.$(mutedIconXPath).waitForDisplayed({
  61. reverse,
  62. timeout: 2000,
  63. timeoutMsg: `Video mute icon is${reverse ? '' : ' not'} displayed for ${testee.name}`
  64. });
  65. if (!isOpen) {
  66. await this.close();
  67. }
  68. }
  69. /**
  70. * Clicks the context menu button in the participants pane.
  71. */
  72. async clickContextMenuButton() {
  73. if (!await this.isOpen()) {
  74. await this.open();
  75. }
  76. const menu = this.participant.driver.$('#participants-pane-context-menu');
  77. await menu.waitForDisplayed();
  78. await menu.click();
  79. }
  80. /**
  81. * Trys to click allow video button.
  82. * @param participantToUnmute
  83. */
  84. async allowVideo(participantToUnmute: Participant) {
  85. if (!await this.isOpen()) {
  86. await this.open();
  87. }
  88. const participantId = await participantToUnmute.getEndpointId();
  89. const participantItem = this.participant.driver.$(`#participant-item-${participantId}`);
  90. await participantItem.waitForExist();
  91. await participantItem.moveTo();
  92. const unmuteButton = this.participant.driver
  93. .$(`button[data-testid="unmute-video-${participantId}"]`);
  94. await unmuteButton.waitForExist();
  95. await unmuteButton.click();
  96. }
  97. /**
  98. * Trys to click ask to unmute button.
  99. * @param participantToUnmute
  100. * @param fromContextMenu
  101. */
  102. async askToUnmute(participantToUnmute: Participant, fromContextMenu: boolean) {
  103. if (!await this.isOpen()) {
  104. await this.open();
  105. }
  106. await this.participant.getNotifications().dismissAnyJoinNotification();
  107. const participantId = await participantToUnmute.getEndpointId();
  108. await this.selectParticipant(participantToUnmute);
  109. if (fromContextMenu) {
  110. await this.openParticipantContextMenu(participantToUnmute);
  111. }
  112. const unmuteButton = this.participant.driver
  113. .$(`[data-testid="unmute-audio-${participantId}"]`);
  114. await unmuteButton.waitForExist();
  115. await unmuteButton.click();
  116. }
  117. /**
  118. * Open context menu for given participant.
  119. */
  120. async selectParticipant(participant: Participant) {
  121. const participantId = await participant.getEndpointId();
  122. const participantItem = this.participant.driver.$(`#participant-item-${participantId}`);
  123. await participantItem.waitForExist();
  124. await participantItem.waitForStable();
  125. await participantItem.waitForDisplayed();
  126. await participantItem.moveTo();
  127. }
  128. /**
  129. * Open context menu for given participant.
  130. */
  131. async openParticipantContextMenu(participant: Participant) {
  132. const participantId = await participant.getEndpointId();
  133. const meetingParticipantMoreOptions = this.participant.driver
  134. .$(`[data-testid="participant-more-options-${participantId}"]`);
  135. await meetingParticipantMoreOptions.waitForExist();
  136. await meetingParticipantMoreOptions.waitForDisplayed();
  137. await meetingParticipantMoreOptions.waitForStable();
  138. await meetingParticipantMoreOptions.moveTo();
  139. await meetingParticipantMoreOptions.click();
  140. }
  141. /**
  142. * Clicks the invite button.
  143. */
  144. async clickInvite() {
  145. if (!await this.isOpen()) {
  146. await this.open();
  147. }
  148. const inviteButton = this.participant.driver.$(`aria/${INVITE}`);
  149. await inviteButton.waitForDisplayed();
  150. await inviteButton.click();
  151. }
  152. /**
  153. * Find the participant by name.
  154. * @param name - The name to look for.
  155. * @private
  156. */
  157. private async findLobbyParticipantByName(name: string): Promise<ChainablePromiseElement> {
  158. return this.participant.driver.$$('//div[@id="lobby-list"]//div[starts-with(@id, "participant-item-")]')
  159. .find(async participant => (await participant.getText()).includes(name));
  160. }
  161. /**
  162. * Tries to click on the approve button and fails if it cannot be clicked.
  163. * @param participantNameToAdmit - the name of the participant to admit.
  164. */
  165. async admitLobbyParticipant(participantNameToAdmit: string) {
  166. const participantToAdmit = await this.findLobbyParticipantByName(participantNameToAdmit);
  167. await participantToAdmit.moveTo();
  168. const participantIdToAdmit = (await participantToAdmit.getAttribute('id'))
  169. .substring('participant-item-'.length);
  170. const admitButton = this.participant.driver
  171. .$(`[data-testid="admit-${participantIdToAdmit}"]`);
  172. await admitButton.waitForExist();
  173. await admitButton.click();
  174. }
  175. /**
  176. * Tries to click on the reject button and fails if it cannot be clicked.
  177. * @param participantNameToReject - the name of the participant for this {@link ParticipantsPane} to reject.
  178. */
  179. async rejectLobbyParticipant(participantNameToReject: string) {
  180. const participantToReject
  181. = await this.findLobbyParticipantByName(participantNameToReject);
  182. await participantToReject.moveTo();
  183. const participantIdToReject = (await participantToReject.getAttribute('id'))
  184. .substring('participant-item-'.length);
  185. const moreOptionsButton
  186. = this.participant.driver.$(`aria/More moderation options ${participantNameToReject}`);
  187. await moreOptionsButton.click();
  188. const rejectButton = this.participant.driver
  189. .$(`[data-testid="reject-${participantIdToReject}"]`);
  190. await rejectButton.waitForExist();
  191. await rejectButton.click();
  192. }
  193. }