diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx
index f7b292fe93..217b1e6b9a 100755
--- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx
@@ -281,6 +281,7 @@ class UserOptions extends PureComponent {
// description: ,
onClick: this.onSaveUserNames,
icon: 'download',
+ dataTest: 'downloadUserNamesList',
});
}
diff --git a/bigbluebutton-tests/playwright/chat/chat.js b/bigbluebutton-tests/playwright/chat/chat.js
index 4fa9861643..4a5f18c14a 100644
--- a/bigbluebutton-tests/playwright/chat/chat.js
+++ b/bigbluebutton-tests/playwright/chat/chat.js
@@ -3,6 +3,7 @@ const Page = require('../core/page');
const { openChat } = require('./util');
const p = require('../core/parameters');
const e = require('../core/elements');
+const { checkTextContent } = require('../core/util');
class Chat extends Page {
constructor(browser, page) {
@@ -10,7 +11,7 @@ class Chat extends Page {
}
async sendPublicMessage() {
- await openChat(this.page);
+ await openChat(this);
const message = this.getLocator(e.chatUserMessageText);
await expect(message).toHaveCount(0);
@@ -21,7 +22,7 @@ class Chat extends Page {
}
async clearChat() {
- await openChat(this.page);
+ await openChat(this);
const message = this.getLocator(e.chatUserMessageText);
await this.type(e.chatBox, e.message);
@@ -50,21 +51,30 @@ class Chat extends Page {
await this.waitForSelector(e.chatUserMessageText);
await this.waitAndClick(e.chatCopy);
// enable access to browser context clipboard
- await context.grantPermissions(['clipboard-write', 'clipboard-read'], { origin: process.env.BBB_SERVER_URL });
+ await context.grantPermissions(['clipboard-write', 'clipboard-read'], { origin: process.env.BBB_URL });
const copiedText = await this.page.evaluate(async () => navigator.clipboard.readText());
const check = copiedText.includes(`${p.fullName}: ${e.message}`);
expect(check).toBeTruthy();
}
- async saveChat() {
- await openChat(this.page);
+ async saveChat(testInfo) {
+ await openChat(this);
+ await this.type(e.chatBox, e.message);
+ await this.waitAndClick(e.sendButton);
+ await this.waitForSelector(e.chatUserMessageText);
await this.waitAndClick(e.chatOptions);
- await this.waitAndClick(e.chatSave);
- await this.page.waitForEvent('click');
+ const { content } = await this.handleDownload(e.chatSave, testInfo);
+
+ const dataToCheck = [
+ this.meetingId,
+ this.username,
+ e.message,
+ ];
+ await checkTextContent(content, dataToCheck);
}
async characterLimit() {
- await openChat(this.page);
+ await openChat(this);
const messageLocator = this.getLocator(e.chatUserMessageText);
await this.page.fill(e.chatBox, e.longMessage5000);
@@ -80,7 +90,7 @@ class Chat extends Page {
}
async emptyMessage() {
- await openChat(this.page);
+ await openChat(this);
const messageLocator = this.getLocator(e.chatUserMessageText);
await this.waitAndClick(e.sendButton);
diff --git a/bigbluebutton-tests/playwright/chat/chat.spec.js b/bigbluebutton-tests/playwright/chat/chat.spec.js
index 3f01d9aee5..301821ecc5 100644
--- a/bigbluebutton-tests/playwright/chat/chat.spec.js
+++ b/bigbluebutton-tests/playwright/chat/chat.spec.js
@@ -22,17 +22,16 @@ test.describe.parallel('Chat', () => {
});
test('Copy chat', async ({ browser, context, page }, testInfo) => {
- test.fixme(testInfo.config.projects[0].use.headless, 'Only works in headed mode');
+ test.fixme(testInfo.project.use.headless, 'Only works in headed mode');
const chat = new Chat(browser, page);
await chat.init(true, true);
await chat.copyChat(context);
});
- test.skip('Save chat', async ({ browser, page }) => {
- test.fixme();
+ test('Save chat', async ({ browser, page }, testInfo) => {
const chat = new Chat(browser, page);
await chat.init(true, true);
- await chat.saveChat();
+ await chat.saveChat(testInfo);
});
test('Verify character limit (5000 characters)', async ({ browser, page }) => {
diff --git a/bigbluebutton-tests/playwright/chat/util.js b/bigbluebutton-tests/playwright/chat/util.js
index cefb575443..f5a4ae2776 100644
--- a/bigbluebutton-tests/playwright/chat/util.js
+++ b/bigbluebutton-tests/playwright/chat/util.js
@@ -1,8 +1,8 @@
const e = require('../core/elements');
-async function openChat(page) {
- await page.waitForSelector(e.chatBox);
- await page.waitForSelector(e.chatMessages);
+async function openChat(test) {
+ await test.waitForSelector(e.chatBox);
+ await test.waitForSelector(e.chatMessages);
}
exports.openChat = openChat;
diff --git a/bigbluebutton-tests/playwright/core/elements.js b/bigbluebutton-tests/playwright/core/elements.js
index a19cd02667..a912a09435 100644
--- a/bigbluebutton-tests/playwright/core/elements.js
+++ b/bigbluebutton-tests/playwright/core/elements.js
@@ -217,6 +217,7 @@ exports.connectionStatusOfflineUser = 'div[data-test="offlineUser"]';
exports.connectionDataContainer = 'div[data-test="networkDataContainer"]';
exports.avatarsWrapperAvatar = 'div[data-test="avatarsWrapperAvatar"]';
exports.guestPolicyLabel = 'li[data-test="guestPolicyLabel"]';
+exports.downloadUserNamesList = 'li[data-test="downloadUserNamesList"]';
exports.waitingUsersBtn = 'div[data-test="waitingUsersBtn"]';
exports.joinMeetingDemoPage = 'div[class^="join-meeting"]';
exports.askModerator = 'button[data-test="askModerator"]';
diff --git a/bigbluebutton-tests/playwright/core/page.js b/bigbluebutton-tests/playwright/core/page.js
index f6ad2ac00c..55019bdd4e 100644
--- a/bigbluebutton-tests/playwright/core/page.js
+++ b/bigbluebutton-tests/playwright/core/page.js
@@ -2,7 +2,7 @@ require('dotenv').config();
const { expect } = require('@playwright/test');
const yaml = require('js-yaml');
const path = require('path');
-const fs = require('fs');
+const { readFileSync } = require('fs');
const parameters = require('./parameters');
const helpers = require('./helpers');
const e = require('./elements');
@@ -18,7 +18,7 @@ class Page {
async getSettingsYaml() {
try {
- return yaml.load(fs.readFileSync(path.join(__dirname, '../../../bigbluebutton-html5/private/config/settings.yml'), 'utf8'));
+ return yaml.load(readFileSync(path.join(__dirname, '../../../bigbluebutton-html5/private/config/settings.yml'), 'utf8'));
} catch (err) {
console.log(err);
}
@@ -46,6 +46,22 @@ class Page {
if (shouldCloseAudioModal) await this.closeAudioModal();
}
+ async handleDownload(selector, testInfo, timeout = ELEMENT_WAIT_TIME) {
+ const [download] = await Promise.all([
+ this.page.waitForEvent('download', { timeout }),
+ this.waitAndClick(selector, timeout),
+ ]);
+ await expect(download).toBeTruthy();
+ const path = await download.path();
+ const content = await readFileSync(path, 'utf8');
+ await testInfo.attach('downloaded', { path });
+
+ return {
+ download,
+ content,
+ }
+ }
+
async joinMicrophone() {
await this.waitForSelector(e.audioModal);
await this.waitAndClick(e.microphoneButton);
diff --git a/bigbluebutton-tests/playwright/core/util.js b/bigbluebutton-tests/playwright/core/util.js
index b7ec0a08c6..71d5fea224 100644
--- a/bigbluebutton-tests/playwright/core/util.js
+++ b/bigbluebutton-tests/playwright/core/util.js
@@ -1,3 +1,5 @@
+const { expect } = require("@playwright/test");
+
// Common
function checkElement([element, index = 0]) {
return document.querySelectorAll(element)[index] !== undefined;
@@ -8,5 +10,14 @@ function checkElementLengthEqualTo([element, count]) {
return document.querySelectorAll(element).length == count;
}
+// Text
+async function checkTextContent(baseContent, checkData) {
+ if (typeof checkData === 'string' ) checkData = new Array(checkData);
+
+ const check = checkData.every(word => baseContent.includes(word));
+ await expect(check).toBeTruthy();
+}
+
exports.checkElement = checkElement;
exports.checkElementLengthEqualTo = checkElementLengthEqualTo;
+exports.checkTextContent = checkTextContent;
diff --git a/bigbluebutton-tests/playwright/presentation/presentation.js b/bigbluebutton-tests/playwright/presentation/presentation.js
index 5ddc9fc95c..58e0aee2b9 100644
--- a/bigbluebutton-tests/playwright/presentation/presentation.js
+++ b/bigbluebutton-tests/playwright/presentation/presentation.js
@@ -72,7 +72,7 @@ class Presentation extends MultiUsers {
await expect(userSlides0).not.toEqual(userSlides1);
}
- async allowAndDisallowDownload() {
+ async allowAndDisallowDownload(testInfo) {
// allow the presentation download
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitAndClick(e.actions);
@@ -83,6 +83,7 @@ class Presentation extends MultiUsers {
await this.userPage.waitForSelector(e.toastDownload);
// check download button in presentation after ALLOW it - should be true
await this.userPage.hasElement(e.presentationDownloadBtn);
+ await this.userPage.handleDownload(e.presentationDownloadBtn, testInfo);
// disallow the presentation download
await this.modPage.waitAndClick(e.actions);
diff --git a/bigbluebutton-tests/playwright/presentation/presentation.spec.js b/bigbluebutton-tests/playwright/presentation/presentation.spec.js
index cc951c566e..29c155e834 100644
--- a/bigbluebutton-tests/playwright/presentation/presentation.spec.js
+++ b/bigbluebutton-tests/playwright/presentation/presentation.spec.js
@@ -27,10 +27,10 @@ test.describe.parallel('Presentation', () => {
await presentation.uploadPresentationTest();
});
- test('Allow and disallow presentation download', async ({ browser, context, page }) => {
+ test('Allow and disallow presentation download', async ({ browser, context, page }, testInfo) => {
const presentation = new Presentation(browser, context);
await presentation.initPages(page);
- await presentation.allowAndDisallowDownload();
+ await presentation.allowAndDisallowDownload(testInfo);
});
test('Remove all presentation', async ({ browser, context, page }) => {
diff --git a/bigbluebutton-tests/playwright/user/multiusers.js b/bigbluebutton-tests/playwright/user/multiusers.js
index 9ee13fd256..96c681c2c3 100644
--- a/bigbluebutton-tests/playwright/user/multiusers.js
+++ b/bigbluebutton-tests/playwright/user/multiusers.js
@@ -4,6 +4,7 @@ const e = require('../core/elements');
const { waitAndClearNotification } = require('../notifications/util');
const { sleep } = require('../core/helpers');
const { checkAvatarIcon, checkIsPresenter } = require('./util');
+const { checkTextContent } = require('../core/util');
class MultiUsers {
constructor(browser, context) {
@@ -151,6 +152,18 @@ class MultiUsers {
await this.modPage.hasElement(e.chatButton);
}
+ async saveUserNames(testInfo) {
+ await this.modPage.waitAndClick(e.manageUsers);
+ const { content } = await this.modPage.handleDownload(e.downloadUserNamesList, testInfo);
+
+ const dataToCheck = [
+ this.modPage.username,
+ this.userPage.username,
+ this.modPage.meetingId,
+ ];
+ await checkTextContent(content, dataToCheck);
+ }
+
async selectRandomUser() {
// check with no viewer joined
await this.modPage.waitAndClick(e.actions);
diff --git a/bigbluebutton-tests/playwright/user/user.spec.js b/bigbluebutton-tests/playwright/user/user.spec.js
index c1f99ae0b3..a4ae53b427 100644
--- a/bigbluebutton-tests/playwright/user/user.spec.js
+++ b/bigbluebutton-tests/playwright/user/user.spec.js
@@ -142,6 +142,12 @@ test.describe.parallel('User', () => {
});
});
+ test('Save user names', async ({ browser, context, page }, testInfo) => {
+ const multiusers = new MultiUsers(browser, context);
+ await multiusers.initPages(page);
+ await multiusers.saveUserNames(testInfo);
+ });
+
test('Select random user', async ({ browser, context, page }) => {
const multiusers = new MultiUsers(browser, context);
await multiusers.initModPage(page);