Skip to content

Commit

Permalink
Merge pull request #18294 from gabriellpr/refactoring-create-join-test
Browse files Browse the repository at this point in the history
test: separate create and join parameters
  • Loading branch information
antobinary committed Jul 18, 2023
2 parents 7d38a31 + 972b907 commit 3b2b189
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 177 deletions.
98 changes: 90 additions & 8 deletions bigbluebutton-tests/playwright/core/helpers.js
Expand Up @@ -4,7 +4,11 @@ const axios = require('axios');
const { test, expect } = require('@playwright/test');
const xml2js = require('xml2js');
const { runScript } = require('./util');
const { env } = require('node:process');

const { format } = require('node:util');
// This is version 4 of chalk, not version 5, which uses ESM
const chalk = require('chalk');
const parameters = require('./parameters');

function getRandomInt(min, max) {
Expand All @@ -26,36 +30,36 @@ function apiCall(name, callParams) {
return axios.get(url, { adapter: 'http' }).then(response => xml2js.parseStringPromise(response.data));
}

function createMeetingUrl(params, customParameter, customMeetingId) {
function createMeetingUrl(params, createParameter, customMeetingId) {
const meetingID = (customMeetingId) ? customMeetingId : `random-${getRandomInt(1000000, 10000000).toString()}`;
const mp = params.moderatorPW;
const ap = params.attendeePW;
const baseQuery = `name=${meetingID}&meetingID=${meetingID}&attendeePW=${ap}&moderatorPW=${mp}`
+ `&allowStartStopRecording=true&autoStartRecording=false&welcome=${params.welcome}`;
const query = customParameter !== undefined ? `${baseQuery}&${customParameter}` : baseQuery;
const query = createParameter !== undefined ? `${baseQuery}&${createParameter}` : baseQuery;
const apiCall = `create${query}${params.secret}`;
const checksum = sha1(apiCall);
const url = `${params.server}/create?${query}&checksum=${checksum}`;
return url;
}

function createMeetingPromise(params, customParameter, customMeetingId) {
const url = createMeetingUrl(params, customParameter, customMeetingId);
function createMeetingPromise(params, createParameter, customMeetingId) {
const url = createMeetingUrl(params, createParameter, customMeetingId);
return axios.get(url, { adapter: 'http' });
}

async function createMeeting(params, customParameter) {
const promise = createMeetingPromise(params, customParameter);
async function createMeeting(params, createParameter, page) {
const promise = createMeetingPromise(params, createParameter);
const response = await promise;
expect(response.status).toEqual(200);
const xmlResponse = await xml2js.parseStringPromise(response.data);
return xmlResponse.response.meetingID[0];
}

function getJoinURL(meetingID, params, moderator, customParameter) {
function getJoinURL(meetingID, params, moderator, joinParameter) {
const pw = moderator ? params.moderatorPW : params.attendeePW;
const baseQuery = `fullName=${params.fullName}&meetingID=${meetingID}&password=${pw}`;
const query = customParameter !== undefined ? `${baseQuery}&${customParameter}` : baseQuery;
const query = joinParameter !== undefined ? `${baseQuery}&${joinParameter}` : baseQuery;
const apiCall = `join${query}${params.secret}`;
const checksum = sha1(apiCall);
return `${params.server}/join?${query}&checksum=${checksum}`;
Expand All @@ -68,6 +72,83 @@ async function checkRootPermission() {
await expect(checkSudo, 'Sudo failed: need to run this test with root permission (can be fixed by running "sudo -v" and entering the password)').toBeTruthy();
}

async function console_format(msg, CONSOLE_options) {
const args = await Promise.all(msg.args().map(itm => itm.jsonValue()));
// For Chrome, args[0] is a format string that we will process using
// node.js's util.format, but that function discards css style
// information from "%c" format specifiers. So first loop over the
// format string, replacing every "%c" with "%s" and replacing the
// corresponding css style with an ANSI color sequence.
//
// See https://console.spec.whatwg.org/ sections 2.2.1 and 2.3.4

let split_arg0 = args[0].split("%");
for (let i = 1, j = 1; i < split_arg0.length; i++, j++) {
if (split_arg0[i].startsWith('c')) {
split_arg0[i] = 's' + split_arg0[i].substr(1);
const styles = args[j].split(';');
args[j] = '';
for (const style of styles) {
const stdStyle = style.trim().toLowerCase();
if (stdStyle.startsWith('color:') && CONSOLE_options.colorize) {
const color = stdStyle.substr(6).trim();
args[j] = chalk.keyword(color)._styler.open;
} else if (stdStyle.startsWith('font-size:') && CONSOLE_options.drop_references) {
// For Chrome, we "drop references" by discarding everything after a font size change
split_arg0.length = i;
args.length = j;
}
}
} else if (split_arg0[i] == "") {
// format is "%%", so don't do special processing for
// split_arg0[i+1], and only increment i, not j
i++; // NOSONAR
}
}
args[0] = split_arg0.join('%');

// see playwright consoleMessage class documentation
let result = format(...args);

if (CONSOLE_options.drop_references) {
// For Firefox, we "drop references" by discarding a URL at the end of the line
result = result.replace(/https:\/\/\S*$/, '');
}

if (CONSOLE_options.noClientLogger) {
result = result.replace(/clientLogger: /, '');
}

if (CONSOLE_options.drop_timestamps) {
// timestamp formatting is a bit complicated, with four "%s" fields and corresponding arguments,
// so just filter them out (if requested) after all the other formatting is done
result = result.replace(/\[\d\d:\d\d:\d\d:\d\d\d\d\] /, '');
}

if (CONSOLE_options.line_label) {
if (CONSOLE_options.colorize) {
result = chalk.keyword('green')(CONSOLE_options.line_label) + result;
} else {
result = CONSOLE_options.line_label + result;
}
}

return result;
}

async function setBrowserLogs(page) {
const CONSOLE_strings = env.CONSOLE.split(',').map(opt => opt.trim().toLowerCase());
const CONSOLE_options = {
colorize: CONSOLE_strings.includes('color') || CONSOLE_strings.includes('colour'),
drop_references: CONSOLE_strings.includes('norefs'),
drop_timestamps: CONSOLE_strings.includes('nots'),
line_label: CONSOLE_strings.includes('label') ? this.username + " " : undefined,
noClientLogger: CONSOLE_strings.includes('nocl') || CONSOLE_strings.includes('noclientlogger'),
};

page.on('console', async (msg) => console.log(await console_format(msg, CONSOLE_options)));
}

function linkIssue(issueNumber) {
test.info().annotations.push({
type: 'Issue/PR',
Expand All @@ -91,3 +172,4 @@ exports.getJoinURL = getJoinURL;
exports.checkRootPermission = checkRootPermission;
exports.linkIssue = linkIssue;
exports.sleep = sleep;
exports.setBrowserLogs = setBrowserLogs;
91 changes: 5 additions & 86 deletions bigbluebutton-tests/playwright/core/page.js
@@ -1,10 +1,6 @@
require('dotenv').config();
const { expect, default: test } = require('@playwright/test');
const { readFileSync } = require('fs');
const { format } = require('node:util');

// This is version 4 of chalk, not version 5, which uses ESM
const chalk = require('chalk');

const parameters = require('./parameters');
const helpers = require('./helpers');
Expand All @@ -14,73 +10,6 @@ const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME, VIDEO_LOADING_WAIT_TIME } =
const { checkElement, checkElementLengthEqualTo } = require('./util');
const { generateSettingsData, getSettings } = require('./settings');

function formatWithCss(CONSOLE_options, ...args) {
// For Chrome, args[0] is a format string that we will process using
// node.js's util.format, but that function discards css style
// information from "%c" format specifiers. So first loop over the
// format string, replacing every "%c" with "%s" and replacing the
// corresponding css style with an ANSI color sequence.
//
// See https://console.spec.whatwg.org/ sections 2.2.1 and 2.3.4

let split_arg0 = args[0].split("%");
for (let i = 1, j = 1; i < split_arg0.length; i++, j++) {
if (split_arg0[i].startsWith('c')) {
split_arg0[i] = 's' + split_arg0[i].substr(1);
const styles = args[j].split(';');
args[j] = '';
for (const style of styles) {
const stdStyle = style.trim().toLowerCase();
if (stdStyle.startsWith('color:') && CONSOLE_options.colorize) {
const color = stdStyle.substr(6).trim();
args[j] = chalk.keyword(color)._styler.open;
} else if (stdStyle.startsWith('font-size:') && CONSOLE_options.drop_references) {
// For Chrome, we "drop references" by discarding everything after a font size change
split_arg0.length = i;
args.length = j;
}
}
} else if (split_arg0[i] == "") {
// format is "%%", so don't do special processing for
// split_arg0[i+1], and only increment i, not j
i++; // NOSONAR
}
}
args[0] = split_arg0.join('%');
return format(...args);
}

async function console_format(msg, CONSOLE_options) {
// see playwright consoleMessage class documentation
const args = await Promise.all(msg.args().map(itm => itm.jsonValue()));
let result = formatWithCss(CONSOLE_options, ...args);

if (CONSOLE_options.drop_references) {
// For Firefox, we "drop references" by discarding a URL at the end of the line
result = result.replace(/https:\/\/\S*$/, '');
}

if (CONSOLE_options.noClientLogger) {
result = result.replace(/clientLogger: /, '');
}

if (CONSOLE_options.drop_timestamps) {
// timestamp formatting is a bit complicated, with four "%s" fields and corresponding arguments,
// so just filter them out (if requested) after all the other formatting is done
result = result.replace(/\[\d\d:\d\d:\d\d:\d\d\d\d\] /, '');
}

if (CONSOLE_options.line_label) {
if (CONSOLE_options.colorize) {
result = chalk.keyword('green')(CONSOLE_options.line_label) + result;
} else {
result = CONSOLE_options.line_label + result;
}
}

return result;
}

class Page {
constructor(browser, page) {
this.browser = browser;
Expand All @@ -98,26 +27,16 @@ class Page {
}

async init(isModerator, shouldCloseAudioModal, initOptions) {
const { fullName, meetingId, customParameter, customMeetingId } = initOptions || {};
const { fullName, meetingId, createParameter, joinParameter, customMeetingId } = initOptions || {};

if (!isModerator) this.initParameters.moderatorPW = '';
if (fullName) this.initParameters.fullName = fullName;
this.username = this.initParameters.fullName;

if (env.CONSOLE !== undefined) await helpers.setBrowserLogs(this.page);

if (env.CONSOLE !== undefined) {
const CONSOLE_strings = env.CONSOLE.split(',').map(opt => opt.trim().toLowerCase());
const CONSOLE_options = {
colorize: CONSOLE_strings.includes('color') || CONSOLE_strings.includes('colour'),
drop_references: CONSOLE_strings.includes('norefs'),
drop_timestamps: CONSOLE_strings.includes('nots'),
line_label: CONSOLE_strings.includes('label') ? this.username + " " : undefined,
noClientLogger: CONSOLE_strings.includes('nocl') || CONSOLE_strings.includes('noclientlogger'),
};
this.page.on('console', async (msg) => console.log(await console_format(msg, CONSOLE_options)));
}

this.meetingId = (meetingId) ? meetingId : await helpers.createMeeting(parameters, customParameter, customMeetingId);
const joinUrl = helpers.getJoinURL(this.meetingId, this.initParameters, isModerator, customParameter);
this.meetingId = (meetingId) ? meetingId : await helpers.createMeeting(parameters, createParameter, customMeetingId, this.page);
const joinUrl = helpers.getJoinURL(this.meetingId, this.initParameters, isModerator, joinParameter);
const response = await this.page.goto(joinUrl);
await expect(response.ok()).toBeTruthy();
const hasErrorLabel = await this.checkElement(e.errorMessageLabel);
Expand Down
8 changes: 4 additions & 4 deletions bigbluebutton-tests/playwright/parameters/customparameters.js
Expand Up @@ -133,8 +133,8 @@ class CustomParameters extends MultiUsers {
await this.modPage.wasRemoved(e.presentationPlaceholder);
}

async forceRestorePresentationOnNewEvents(customParameter) {
await this.initUserPage(true, this.context, { useModMeetingId: true, customParameter });
async forceRestorePresentationOnNewEvents(joinParameter) {
await this.initUserPage(true, this.context, { useModMeetingId: true, joinParameter });
const { presentationHidden, pollEnabled } = getSettings();
if (!presentationHidden) await this.userPage.waitAndClick(e.minimizePresentation);
const zoomInCase = await util.zoomIn(this.modPage);
Expand All @@ -148,8 +148,8 @@ class CustomParameters extends MultiUsers {
await this.userPage.checkElement(e.restorePresentation);
}

async forceRestorePresentationOnNewPollResult(customParameter) {
await this.initUserPage(true, this.context, { useModMeetingId: true, customParameter })
async forceRestorePresentationOnNewPollResult(joinParameter) {
await this.initUserPage(true, this.context, { useModMeetingId: true, joinParameter })
const { presentationHidden,pollEnabled } = getSettings();
if (!presentationHidden) await this.userPage.waitAndClick(e.minimizePresentation);
if (pollEnabled) await util.poll(this.modPage, this.userPage);
Expand Down

0 comments on commit 3b2b189

Please sign in to comment.