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.

Toolbar.ts 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import BasePageObject from './BasePageObject';
  2. const AUDIO_MUTE = 'Mute microphone';
  3. const AUDIO_UNMUTE = 'Unmute microphone';
  4. const CHAT = 'Open chat';
  5. const CLOSE_CHAT = 'Close chat';
  6. const CLOSE_PARTICIPANTS_PANE = 'Close participants pane';
  7. const DESKTOP = 'Start sharing your screen';
  8. const HANGUP = 'Leave the meeting';
  9. const OVERFLOW_MENU = 'More actions menu';
  10. const OVERFLOW = 'More actions';
  11. const PARTICIPANTS = 'Open participants pane';
  12. const PROFILE = 'Edit your profile';
  13. const RAISE_HAND = 'Raise your hand';
  14. const SETTINGS = 'Open settings';
  15. const STOP_DESKTOP = 'Stop sharing your screen';
  16. const ENTER_TILE_VIEW_BUTTON = 'Enter tile view';
  17. const EXIT_TILE_VIEW_BUTTON = 'Exit tile view';
  18. const VIDEO_QUALITY = 'Manage video quality';
  19. const VIDEO_MUTE = 'Stop camera';
  20. const VIDEO_UNMUTE = 'Start camera';
  21. /**
  22. * The toolbar elements.
  23. */
  24. export default class Toolbar extends BasePageObject {
  25. /**
  26. * Returns the button.
  27. *
  28. * @param {string} accessibilityCSSSelector - The selector to find the button.
  29. * @returns {WebdriverIO.Element} The button.
  30. * @private
  31. */
  32. private getButton(accessibilityCSSSelector: string) {
  33. return this.participant.driver.$(`aria/${accessibilityCSSSelector}`);
  34. }
  35. /**
  36. * The audio mute button.
  37. */
  38. get audioMuteBtn() {
  39. return this.getButton(AUDIO_MUTE);
  40. }
  41. /**
  42. * The audio unmute button.
  43. */
  44. get audioUnMuteBtn() {
  45. return this.getButton(AUDIO_UNMUTE);
  46. }
  47. /**
  48. * Clicks audio mute button.
  49. *
  50. * @returns {Promise<void>}
  51. */
  52. async clickAudioMuteButton(): Promise<void> {
  53. this.participant.log('Clicking on: Audio Mute Button');
  54. await this.audioMuteBtn.click();
  55. }
  56. /**
  57. * Clicks audio unmute button.
  58. *
  59. * @returns {Promise<void>}
  60. */
  61. async clickAudioUnmuteButton(): Promise<void> {
  62. this.participant.log('Clicking on: Audio Unmute Button');
  63. await this.audioUnMuteBtn.click();
  64. }
  65. /**
  66. * The video mute button.
  67. */
  68. get videoMuteBtn() {
  69. return this.getButton(VIDEO_MUTE);
  70. }
  71. /**
  72. * The video unmute button.
  73. */
  74. get videoUnMuteBtn() {
  75. return this.getButton(VIDEO_UNMUTE);
  76. }
  77. /**
  78. * Clicks video mute button.
  79. *
  80. * @returns {Promise<void>}
  81. */
  82. async clickVideoMuteButton(): Promise<void> {
  83. this.participant.log('Clicking on: Video Mute Button');
  84. await this.videoMuteBtn.click();
  85. }
  86. /**
  87. * Clicks video unmute button.
  88. *
  89. * @returns {Promise<void>}
  90. */
  91. async clickVideoUnmuteButton(): Promise<void> {
  92. this.participant.log('Clicking on: Video Unmute Button');
  93. await this.videoUnMuteBtn.click();
  94. }
  95. /**
  96. * Clicks Participants pane button.
  97. *
  98. * @returns {Promise<void>}
  99. */
  100. async clickCloseParticipantsPaneButton(): Promise<void> {
  101. this.participant.log('Clicking on: Close Participants pane Button');
  102. await this.getButton(CLOSE_PARTICIPANTS_PANE).click();
  103. }
  104. /**
  105. * Clicks Participants pane button.
  106. *
  107. * @returns {Promise<void>}
  108. */
  109. async clickParticipantsPaneButton(): Promise<void> {
  110. this.participant.log('Clicking on: Participants pane Button');
  111. // Special case for participants pane button, as it contains the number of participants and its label
  112. // is changing
  113. await this.participant.driver.$(`[aria-label^="${PARTICIPANTS}"]`).click();
  114. }
  115. /**
  116. * Clicks on the video quality toolbar button which opens the
  117. * dialog for adjusting max-received video quality.
  118. */
  119. async clickVideoQualityButton(): Promise<void> {
  120. return this.clickButtonInOverflowMenu(VIDEO_QUALITY);
  121. }
  122. /**
  123. * Clicks on the profile toolbar button which opens or closes the profile panel.
  124. */
  125. async clickProfileButton(): Promise<void> {
  126. return this.clickButtonInOverflowMenu(PROFILE);
  127. }
  128. /**
  129. * Clicks on the raise hand button that enables participants will to speak.
  130. */
  131. async clickRaiseHandButton(): Promise<void> {
  132. this.participant.log('Clicking on: Raise hand Button');
  133. await this.getButton(RAISE_HAND).click();
  134. }
  135. /**
  136. * Clicks on the chat button that opens chat panel.
  137. */
  138. async clickChatButton(): Promise<void> {
  139. this.participant.log('Clicking on: Chat Button');
  140. await this.getButton(CHAT).click();
  141. }
  142. /**
  143. * Clicks on the chat button that closes chat panel.
  144. */
  145. async clickCloseChatButton(): Promise<void> {
  146. this.participant.log('Clicking on: Close Chat Button');
  147. await this.getButton(CLOSE_CHAT).click();
  148. }
  149. /**
  150. * Clicks on the desktop sharing button that starts desktop sharing.
  151. */
  152. async clickDesktopSharingButton() {
  153. await this.getButton(DESKTOP).click();
  154. }
  155. /**
  156. * Clicks on the desktop sharing button to stop it.
  157. */
  158. async clickStopDesktopSharingButton() {
  159. await this.getButton(STOP_DESKTOP).click();
  160. }
  161. /**
  162. * Clicks on the tile view button which enables tile layout.
  163. */
  164. async clickEnterTileViewButton() {
  165. await this.getButton(ENTER_TILE_VIEW_BUTTON).click();
  166. }
  167. /**
  168. * Clicks on the tile view button which exits tile layout.
  169. */
  170. async clickExitTileViewButton() {
  171. await this.getButton(EXIT_TILE_VIEW_BUTTON).click();
  172. }
  173. /**
  174. * Clicks on the hangup button that ends the conference.
  175. */
  176. async clickHangupButton(): Promise<void> {
  177. this.participant.log('Clicking on: Hangup Button');
  178. await this.getButton(HANGUP).click();
  179. }
  180. /**
  181. * Clicks on the settings toolbar button which opens or closes the settings panel.
  182. */
  183. async clickSettingsButton() {
  184. await this.clickButtonInOverflowMenu(SETTINGS);
  185. }
  186. /**
  187. * Ensure the overflow menu is open and clicks on a specified button.
  188. * @param accessibilityLabel The accessibility label of the button to be clicked.
  189. * @private
  190. */
  191. private async clickButtonInOverflowMenu(accessibilityLabel: string) {
  192. await this.openOverflowMenu();
  193. // sometimes the overflow button tooltip is over the last entry in the menu,
  194. // so let's move focus away before clicking the button
  195. await this.participant.driver.$('#overflow-context-menu').moveTo();
  196. this.participant.log(`Clicking on: ${accessibilityLabel}`);
  197. await this.getButton(accessibilityLabel).click();
  198. await this.closeOverflowMenu();
  199. }
  200. /**
  201. * Checks if the overflow menu is open and visible.
  202. * @private
  203. */
  204. private async isOverflowMenuOpen() {
  205. return await this.participant.driver.$$(`aria/${OVERFLOW_MENU}`).length > 0;
  206. }
  207. /**
  208. * Clicks on the overflow toolbar button which opens or closes the overflow menu.
  209. * @private
  210. */
  211. private async clickOverflowButton(): Promise<void> {
  212. await this.getButton(OVERFLOW).click();
  213. }
  214. /**
  215. * Ensure the overflow menu is displayed.
  216. * @private
  217. */
  218. private async openOverflowMenu() {
  219. if (await this.isOverflowMenuOpen()) {
  220. return;
  221. }
  222. await this.clickOverflowButton();
  223. await this.waitForOverFlowMenu(true);
  224. }
  225. /**
  226. * Ensures the overflow menu is not displayed.
  227. * @private
  228. */
  229. private async closeOverflowMenu() {
  230. if (!await this.isOverflowMenuOpen()) {
  231. return;
  232. }
  233. await this.clickOverflowButton();
  234. await this.waitForOverFlowMenu(false);
  235. }
  236. /**
  237. * Waits for the overflow menu to be visible or hidden.
  238. * @param visible
  239. * @private
  240. */
  241. private async waitForOverFlowMenu(visible: boolean) {
  242. await this.getButton(OVERFLOW_MENU).waitForDisplayed({
  243. reverse: !visible,
  244. timeout: 3000,
  245. timeoutMsg: `Overflow menu is not ${visible ? 'visible' : 'hidden'}`
  246. });
  247. }
  248. /**
  249. * Gets the participant's avatar image element located in the toolbar.
  250. */
  251. async getProfileImage() {
  252. await this.openOverflowMenu();
  253. const elem = this.participant.driver.$(`[aria-label^="${PROFILE}"] img`);
  254. return await elem.isExisting() ? await elem.getAttribute('src') : null;
  255. }
  256. }