2021-11-03 00:45:52 +08:00
|
|
|
require('dotenv').config();
|
2022-03-29 21:53:07 +08:00
|
|
|
const { expect, default: test } = require('@playwright/test');
|
2022-03-21 23:04:43 +08:00
|
|
|
const { readFileSync } = require('fs');
|
2022-10-25 06:42:51 +08:00
|
|
|
|
2021-11-03 00:45:52 +08:00
|
|
|
const parameters = require('./parameters');
|
|
|
|
const helpers = require('./helpers');
|
2021-11-18 04:07:14 +08:00
|
|
|
const e = require('./elements');
|
2022-10-20 12:26:07 +08:00
|
|
|
const { env } = require('node:process');
|
2024-03-07 21:43:25 +08:00
|
|
|
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME, VIDEO_LOADING_WAIT_TIME, ELEMENT_WAIT_EXTRA_LONG_TIME } = require('./constants');
|
2022-02-05 03:26:35 +08:00
|
|
|
const { checkElement, checkElementLengthEqualTo } = require('./util');
|
2022-06-08 02:52:22 +08:00
|
|
|
const { generateSettingsData, getSettings } = require('./settings');
|
2021-11-03 00:45:52 +08:00
|
|
|
|
|
|
|
class Page {
|
2021-11-16 00:42:29 +08:00
|
|
|
constructor(browser, page) {
|
2021-11-03 00:45:52 +08:00
|
|
|
this.browser = browser;
|
2021-11-16 00:42:29 +08:00
|
|
|
this.page = page;
|
2021-11-03 00:45:52 +08:00
|
|
|
this.initParameters = Object.assign({}, parameters);
|
|
|
|
}
|
|
|
|
|
2021-11-30 21:42:57 +08:00
|
|
|
async bringToFront() {
|
|
|
|
await this.page.bringToFront();
|
|
|
|
}
|
|
|
|
|
|
|
|
async getLastTargetPage(context) {
|
|
|
|
const contextPages = await context.pages();
|
|
|
|
return new Page(this.browser, contextPages[contextPages.length - 1]);
|
|
|
|
}
|
|
|
|
|
2021-11-19 04:09:29 +08:00
|
|
|
async init(isModerator, shouldCloseAudioModal, initOptions) {
|
2023-08-23 04:25:50 +08:00
|
|
|
const { fullName, meetingId, createParameter, joinParameter, customMeetingId, isRecording } = initOptions || {};
|
2021-11-19 04:09:29 +08:00
|
|
|
|
|
|
|
if (!isModerator) this.initParameters.moderatorPW = '';
|
|
|
|
if (fullName) this.initParameters.fullName = fullName;
|
2022-01-29 03:52:22 +08:00
|
|
|
this.username = this.initParameters.fullName;
|
2023-07-14 22:57:42 +08:00
|
|
|
|
|
|
|
if (env.CONSOLE !== undefined) await helpers.setBrowserLogs(this.page);
|
2021-11-19 04:09:29 +08:00
|
|
|
|
2023-07-11 03:29:30 +08:00
|
|
|
this.meetingId = (meetingId) ? meetingId : await helpers.createMeeting(parameters, createParameter, customMeetingId, this.page);
|
|
|
|
const joinUrl = helpers.getJoinURL(this.meetingId, this.initParameters, isModerator, joinParameter);
|
2022-06-08 02:52:22 +08:00
|
|
|
const response = await this.page.goto(joinUrl);
|
|
|
|
await expect(response.ok()).toBeTruthy();
|
2022-08-20 07:57:17 +08:00
|
|
|
const hasErrorLabel = await this.checkElement(e.errorMessageLabel);
|
2022-06-08 02:52:22 +08:00
|
|
|
await expect(hasErrorLabel, 'Getting error when joining. Check if the BBB_URL and BBB_SECRET are set correctly').toBeFalsy();
|
2022-03-29 21:53:07 +08:00
|
|
|
this.settings = await generateSettingsData(this.page);
|
|
|
|
const { autoJoinAudioModal } = this.settings;
|
2023-08-23 04:25:50 +08:00
|
|
|
if (isRecording && !isModerator) await this.closeRecordingModal();
|
2022-03-29 21:53:07 +08:00
|
|
|
if (shouldCloseAudioModal && autoJoinAudioModal) await this.closeAudioModal();
|
2021-11-03 00:45:52 +08:00
|
|
|
}
|
|
|
|
|
2023-02-16 02:41:21 +08:00
|
|
|
async handleDownload(locator, testInfo, timeout = ELEMENT_WAIT_TIME) {
|
2022-03-21 23:04:43 +08:00
|
|
|
const [download] = await Promise.all([
|
|
|
|
this.page.waitForEvent('download', { timeout }),
|
2023-02-16 03:52:06 +08:00
|
|
|
locator.click({ timeout }),
|
2022-03-21 23:04:43 +08:00
|
|
|
]);
|
|
|
|
await expect(download).toBeTruthy();
|
2022-04-08 02:34:25 +08:00
|
|
|
const filePath = await download.path();
|
|
|
|
const content = await readFileSync(filePath, 'utf8');
|
2023-02-16 04:21:58 +08:00
|
|
|
await testInfo.attach('downloaded', { path: filePath });
|
2022-03-21 23:04:43 +08:00
|
|
|
|
|
|
|
return {
|
|
|
|
download,
|
|
|
|
content,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-14 21:59:46 +08:00
|
|
|
async handleNewTab(selector, context) {
|
2022-09-07 00:52:45 +08:00
|
|
|
const [newPage] = await Promise.all([
|
|
|
|
context.waitForEvent('page'),
|
|
|
|
this.waitAndClick(selector),
|
|
|
|
]);
|
|
|
|
return newPage;
|
|
|
|
}
|
|
|
|
|
2021-11-27 04:01:41 +08:00
|
|
|
async joinMicrophone() {
|
|
|
|
await this.waitForSelector(e.audioModal);
|
|
|
|
await this.waitAndClick(e.microphoneButton);
|
2022-07-02 04:55:32 +08:00
|
|
|
await this.waitForSelector(e.stopHearingButton);
|
|
|
|
await this.waitAndClick(e.joinEchoTestButton);
|
|
|
|
await this.waitForSelector(e.establishingAudioLabel);
|
|
|
|
await this.wasRemoved(e.establishingAudioLabel, ELEMENT_WAIT_LONGER_TIME);
|
2021-11-27 04:01:41 +08:00
|
|
|
await this.waitForSelector(e.isTalking);
|
|
|
|
}
|
|
|
|
|
2021-12-15 01:10:44 +08:00
|
|
|
async leaveAudio() {
|
2022-07-02 04:55:32 +08:00
|
|
|
await this.waitAndClick(e.audioDropdownMenu);
|
2021-12-15 01:10:44 +08:00
|
|
|
await this.waitAndClick(e.leaveAudio);
|
|
|
|
await this.waitForSelector(e.joinAudio);
|
|
|
|
}
|
|
|
|
|
|
|
|
async logoutFromMeeting() {
|
2024-02-23 21:09:31 +08:00
|
|
|
const { directLeaveButton } = this.settings;
|
|
|
|
|
|
|
|
if (directLeaveButton) {
|
|
|
|
await this.waitAndClick(e.leaveMeetingDropdown);
|
|
|
|
} else {
|
|
|
|
await this.waitAndClick(e.optionsButton);
|
|
|
|
}
|
|
|
|
await this.waitAndClick(e.logoutBtn);
|
2021-12-15 01:10:44 +08:00
|
|
|
}
|
|
|
|
|
2022-01-29 03:52:22 +08:00
|
|
|
async shareWebcam(shouldConfirmSharing = true, videoPreviewTimeout = ELEMENT_WAIT_TIME) {
|
2024-02-23 21:09:31 +08:00
|
|
|
const { webcamSharingEnabled } = this.settings;
|
2022-03-29 21:53:07 +08:00
|
|
|
test.fail(!webcamSharingEnabled, 'Webcam sharing is disabled');
|
|
|
|
|
2023-11-01 22:28:38 +08:00
|
|
|
if(!webcamSharingEnabled) {
|
2023-11-15 04:15:26 +08:00
|
|
|
return this.wasRemoved(e.joinVideo)
|
2023-11-01 22:28:38 +08:00
|
|
|
}
|
2021-11-27 04:01:41 +08:00
|
|
|
await this.waitAndClick(e.joinVideo);
|
|
|
|
if (shouldConfirmSharing) {
|
2022-03-08 02:56:08 +08:00
|
|
|
await this.bringToFront();
|
2021-11-27 04:01:41 +08:00
|
|
|
await this.waitForSelector(e.videoPreview, videoPreviewTimeout);
|
|
|
|
await this.waitAndClick(e.startSharingWebcam);
|
2021-11-26 02:23:58 +08:00
|
|
|
}
|
2022-02-03 08:05:26 +08:00
|
|
|
await this.waitForSelector(e.webcamContainer, VIDEO_LOADING_WAIT_TIME);
|
2021-11-27 04:01:41 +08:00
|
|
|
await this.waitForSelector(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
|
2022-08-23 10:58:56 +08:00
|
|
|
await this.wasRemoved(e.webcamConnecting);
|
2021-11-27 04:01:41 +08:00
|
|
|
}
|
|
|
|
|
2022-01-20 03:50:59 +08:00
|
|
|
getLocator(selector) {
|
2021-11-26 02:23:58 +08:00
|
|
|
return this.page.locator(selector);
|
|
|
|
}
|
|
|
|
|
2022-02-05 03:26:35 +08:00
|
|
|
getLocatorByIndex(selector, index) {
|
|
|
|
return this.page.locator(selector).nth(index);
|
|
|
|
}
|
|
|
|
|
2021-12-10 21:22:41 +08:00
|
|
|
async getSelectorCount(selector) {
|
2022-01-20 03:50:59 +08:00
|
|
|
const locator = this.getLocator(selector);
|
2021-11-26 02:23:58 +08:00
|
|
|
return locator.count();
|
|
|
|
}
|
|
|
|
|
2022-09-16 22:22:05 +08:00
|
|
|
async getCopiedText(context) {
|
2023-02-14 21:59:46 +08:00
|
|
|
await context.grantPermissions(['clipboard-write', 'clipboard-read'], { origin: process.env.BBB_URL });
|
2022-09-16 22:22:05 +08:00
|
|
|
return this.page.evaluate(async () => navigator.clipboard.readText());
|
|
|
|
}
|
|
|
|
|
2021-11-03 00:45:52 +08:00
|
|
|
async closeAudioModal() {
|
2024-03-07 21:43:25 +08:00
|
|
|
await this.waitForSelector(e.audioModal, ELEMENT_WAIT_EXTRA_LONG_TIME);
|
2022-01-20 21:03:18 +08:00
|
|
|
await this.waitAndClick(e.closeModal);
|
2021-11-03 00:45:52 +08:00
|
|
|
}
|
|
|
|
|
2023-08-23 04:25:50 +08:00
|
|
|
async closeRecordingModal() {
|
|
|
|
await this.waitForSelector(e.simpleModal, ELEMENT_WAIT_LONGER_TIME);
|
|
|
|
await this.waitAndClick(e.confirmRecording);
|
|
|
|
}
|
|
|
|
|
2021-11-20 01:32:56 +08:00
|
|
|
async waitForSelector(selector, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
await this.page.waitForSelector(selector, { timeout });
|
|
|
|
}
|
|
|
|
|
2023-02-14 21:59:46 +08:00
|
|
|
async waitForSelectorDetached(selector, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
await this.page.waitForSelector(selector, { state: 'detached', timeout });
|
|
|
|
}
|
|
|
|
|
|
|
|
async getElementBoundingBox(selector) {
|
|
|
|
const element = await this.page.$(selector);
|
|
|
|
return element.boundingBox();
|
|
|
|
}
|
|
|
|
|
2022-02-05 03:26:35 +08:00
|
|
|
async waitUntilHaveCountSelector(selector, count, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
await this.page.waitForFunction(
|
|
|
|
checkElementLengthEqualTo,
|
|
|
|
[selector, count],
|
|
|
|
{ timeout },
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-11-03 00:45:52 +08:00
|
|
|
async type(selector, text) {
|
2022-01-20 03:50:59 +08:00
|
|
|
const handle = this.getLocator(selector);
|
2021-11-20 01:32:56 +08:00
|
|
|
await handle.focus();
|
2022-03-02 04:11:45 +08:00
|
|
|
await handle.type(text, { timeout: ELEMENT_WAIT_TIME });
|
2021-11-03 00:45:52 +08:00
|
|
|
}
|
|
|
|
|
2021-11-26 02:23:58 +08:00
|
|
|
async waitAndClickElement(element, index = 0, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
await this.waitForSelector(element, timeout);
|
|
|
|
await this.page.evaluate(([elem, i]) => {
|
|
|
|
document.querySelectorAll(elem)[i].click();
|
|
|
|
}, [element, index]);
|
|
|
|
}
|
|
|
|
|
2021-11-20 01:32:56 +08:00
|
|
|
async waitAndClick(selector, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
await this.waitForSelector(selector, timeout);
|
|
|
|
await this.page.focus(selector);
|
2021-12-10 21:22:41 +08:00
|
|
|
await this.page.click(selector, { timeout });
|
2021-11-03 00:45:52 +08:00
|
|
|
}
|
2021-11-23 01:06:59 +08:00
|
|
|
|
2022-02-03 08:45:23 +08:00
|
|
|
async clickOnLocator(locator, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
await locator.click({ timeout });
|
|
|
|
}
|
|
|
|
|
2021-12-01 22:02:26 +08:00
|
|
|
async checkElement(selector, index = 0) {
|
|
|
|
return this.page.evaluate(checkElement, [selector, index]);
|
|
|
|
}
|
|
|
|
|
2021-11-23 01:06:59 +08:00
|
|
|
async wasRemoved(selector, timeout = ELEMENT_WAIT_TIME) {
|
2022-01-20 03:50:59 +08:00
|
|
|
const locator = this.getLocator(selector);
|
2021-11-23 01:06:59 +08:00
|
|
|
await expect(locator).toBeHidden({ timeout });
|
|
|
|
}
|
|
|
|
|
2022-05-21 07:22:55 +08:00
|
|
|
async wasNthElementRemoved(selector, count, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
const locator = this.getLocator(':nth-match(' + selector + ',' + count + ')');
|
|
|
|
await expect(locator).toBeHidden({ timeout });
|
|
|
|
}
|
|
|
|
|
2021-11-23 01:06:59 +08:00
|
|
|
async hasElement(selector, timeout = ELEMENT_WAIT_TIME) {
|
2022-01-20 03:50:59 +08:00
|
|
|
const locator = this.getLocator(selector);
|
2021-11-23 01:06:59 +08:00
|
|
|
await expect(locator).toBeVisible({ timeout });
|
|
|
|
}
|
2021-11-26 02:23:58 +08:00
|
|
|
|
2022-05-21 07:22:55 +08:00
|
|
|
async hasNElements(selector, count, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
const locator = this.getLocator(':nth-match(' + selector + ',' + count + ')');
|
|
|
|
await expect(locator).toBeVisible({ timeout });
|
|
|
|
}
|
|
|
|
|
2022-01-29 03:52:22 +08:00
|
|
|
async hasElementDisabled(selector, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
const locator = this.getLocator(selector);
|
|
|
|
await expect(locator).toBeDisabled({ timeout });
|
|
|
|
}
|
|
|
|
|
2022-02-03 08:45:23 +08:00
|
|
|
async hasElementEnabled(selector, timeout = ELEMENT_WAIT_TIME) {
|
2022-06-30 23:01:00 +08:00
|
|
|
const locator = this.getLocator(`${selector}:not([disabled])`);
|
2022-02-03 08:45:23 +08:00
|
|
|
await expect(locator).toBeEnabled({ timeout });
|
|
|
|
}
|
|
|
|
|
2021-11-26 02:23:58 +08:00
|
|
|
async hasText(selector, text, timeout = ELEMENT_WAIT_TIME) {
|
2022-08-03 07:37:16 +08:00
|
|
|
const locator = this.getLocator(selector).first();
|
2021-11-26 02:23:58 +08:00
|
|
|
await expect(locator).toContainText(text, { timeout });
|
|
|
|
}
|
2022-07-21 03:44:09 +08:00
|
|
|
|
2023-04-25 04:52:47 +08:00
|
|
|
async haveTitle(title) {
|
|
|
|
await expect(this.page).toHaveTitle(title);
|
|
|
|
}
|
|
|
|
|
2022-07-21 03:44:09 +08:00
|
|
|
async press(key) {
|
|
|
|
await this.page.keyboard.press(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
async down(key) {
|
|
|
|
await this.page.keyboard.down(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
async up(key) {
|
|
|
|
await this.page.keyboard.up(key);
|
|
|
|
}
|
2023-02-14 21:59:46 +08:00
|
|
|
|
2022-12-01 19:19:03 +08:00
|
|
|
async mouseDoubleClick(x, y) {
|
|
|
|
await this.page.mouse.dblclick(x, y);
|
|
|
|
}
|
2022-09-16 02:31:10 +08:00
|
|
|
|
|
|
|
async dragDropSelector(selector, position) {
|
2023-04-26 05:20:48 +08:00
|
|
|
await this.getLocator(selector).dragTo(this.page.locator(position), { timeout: ELEMENT_WAIT_TIME });
|
|
|
|
}
|
|
|
|
|
|
|
|
async dragAndDropWebcams(position) {
|
|
|
|
await this.getLocator(e.webcamContainer).first().hover({ timeout: 5000 });
|
|
|
|
await this.page.mouse.down();
|
|
|
|
await this.getLocator(e.whiteboard).hover({ timeout: 5000 }); // action for dispatching isDragging event
|
|
|
|
await this.getLocator(position).hover({ timeout: 5000 });
|
|
|
|
await this.page.mouse.up();
|
2022-09-16 02:31:10 +08:00
|
|
|
}
|
2022-09-23 04:17:15 +08:00
|
|
|
|
|
|
|
async checkElementCount(selector, count) {
|
|
|
|
const locator = await this.page.locator(selector);
|
2024-03-07 21:43:25 +08:00
|
|
|
await expect(locator).toHaveCount(count, { timeout: ELEMENT_WAIT_LONGER_TIME });
|
2022-09-23 04:17:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
async hasValue(selector, value) {
|
2023-02-14 21:59:46 +08:00
|
|
|
const locator = await this.page.locator(selector);
|
2022-09-23 04:17:15 +08:00
|
|
|
await expect(locator).toHaveValue(value);
|
|
|
|
}
|
2022-11-11 04:25:18 +08:00
|
|
|
|
2022-11-24 22:52:06 +08:00
|
|
|
async backgroundColorTest(selector, color) {
|
2022-11-11 04:25:18 +08:00
|
|
|
await expect(await this.page.$eval(selector, e => getComputedStyle(e).backgroundColor)).toBe(color);
|
|
|
|
}
|
|
|
|
|
2022-11-24 22:52:06 +08:00
|
|
|
async textColorTest(selector, color) {
|
2022-11-11 04:25:18 +08:00
|
|
|
await expect(await this.page.$eval(selector, e => getComputedStyle(e).color)).toBe(color);
|
|
|
|
}
|
2023-01-19 00:29:45 +08:00
|
|
|
|
|
|
|
async fontSizeCheck(selector, size) {
|
|
|
|
await expect(await this.page.$eval(selector, e => getComputedStyle(e).fontSize)).toBe(size);
|
|
|
|
}
|
2023-02-11 00:20:14 +08:00
|
|
|
|
|
|
|
async comparingSelectorsBackgroundColor(selector1, selector2) {
|
|
|
|
const getBackgroundColorComputed = (locator) => locator.evaluate((elem) => getComputedStyle(elem).backgroundColor);
|
|
|
|
const avatarInToastElementColor = this.page.locator(selector1);
|
|
|
|
const avatarInUserListColor = this.page.locator(selector2);
|
|
|
|
await expect(getBackgroundColorComputed(avatarInToastElementColor)).toStrictEqual(getBackgroundColorComputed(avatarInUserListColor));
|
|
|
|
}
|
2023-03-09 04:34:54 +08:00
|
|
|
|
|
|
|
async reloadPage() {
|
|
|
|
await this.page.reload();
|
|
|
|
}
|
2023-04-25 00:33:00 +08:00
|
|
|
|
|
|
|
async selectSlide(slideOption, timeout = ELEMENT_WAIT_TIME) {
|
|
|
|
await this.page.locator(e.skipSlide).selectOption({ label: slideOption }, { timeout });
|
|
|
|
}
|
2023-09-06 04:12:32 +08:00
|
|
|
|
|
|
|
async closeAllToastNotifications() {
|
|
|
|
await this.page.waitForSelector(e.whiteboard);
|
|
|
|
const closeToastBtnLocator = this.page.locator(e.closeToastBtn);
|
|
|
|
while (await closeToastBtnLocator.count() > 0) {
|
|
|
|
await this.page.click(e.closeToastBtn);
|
|
|
|
await helpers.sleep(1000); // expected time to toast notification disappear
|
|
|
|
}
|
|
|
|
}
|
2024-03-02 02:15:18 +08:00
|
|
|
|
2024-03-08 20:30:48 +08:00
|
|
|
async setViewPortSize() {
|
|
|
|
await this.page.setViewportSize({ width: 1366, height: 768 });
|
2024-03-02 02:15:18 +08:00
|
|
|
}
|
2021-11-03 00:45:52 +08:00
|
|
|
}
|
|
|
|
|
2021-11-03 06:50:20 +08:00
|
|
|
module.exports = exports = Page;
|