snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 01:21:02 +05:00
commit 30810eecd7
10161 changed files with 987110 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
# E2E Testing with playwright
## Running tests
```sh
$ RC_SERVER_1=http://localhost:3000 RC_SERVER_1_ADMIN_USER=test RC_SERVER_1_ADMIN_PASSWORD=test RC_SERVER_1_MATRIX_SERVER_NAME=my.matrix.server \
RC_SERVER_2=http://localhost:3000 RC_SERVER_2_ADMIN_USER=test2 RC_SERVER_2_ADMIN_PASSWORD=test RC_SERVER_2_MATRIX_SERVER_NAME=my2.matrix.server \
yarn run test:e2e:federation
```
## Important
Make sure to increase the rate limiter for the user register api under Admin => Rate Limiter => Feature limiting. This is necessary since we are registering new users programatically.

View File

@@ -0,0 +1,20 @@
export const RC_SERVER_1 = {
url: process.env.RC_SERVER_1 ?? 'http://localhost:3000',
username: process.env.RC_SERVER_1_ADMIN_USER ?? '',
password: process.env.RC_SERVER_1_ADMIN_PASSWORD ?? '',
matrixServerName: process.env.RC_SERVER_1_MATRIX_SERVER_NAME ?? '',
};
export const RC_SERVER_2 = {
url: process.env.RC_SERVER_2 ?? 'http://localhost:3000',
username: process.env.RC_SERVER_2_ADMIN_USER ?? '',
password: process.env.RC_SERVER_2_ADMIN_PASSWORD ?? '',
matrixServerName: process.env.RC_SERVER_2_MATRIX_SERVER_NAME ?? '',
};
export const RC_EXTRA_SERVER = {
url: process.env.RC_EXTRA_SERVER ?? 'http://localhost:3000',
username: process.env.RC_EXTRA_SERVER_ADMIN_USER ?? '',
password: process.env.RC_EXTRA_SERVER_ADMIN_PASSWORD ?? '',
matrixServerName: process.env.RC_EXTRA_SERVER_MATRIX_SERVER_NAME ?? '',
};

View File

@@ -0,0 +1,20 @@
export default async function (): Promise<void> {
const requiredEnvVars = [
'RC_SERVER_1',
'RC_SERVER_2',
'RC_SERVER_1_ADMIN_USER',
'RC_SERVER_1_ADMIN_PASSWORD',
'RC_SERVER_1_MATRIX_SERVER_NAME',
'RC_SERVER_2_ADMIN_USER',
'RC_SERVER_2_ADMIN_PASSWORD',
'RC_SERVER_2_MATRIX_SERVER_NAME',
'RC_EXTRA_SERVER',
'RC_EXTRA_SERVER_ADMIN_USER',
'RC_EXTRA_SERVER_ADMIN_PASSWORD',
'RC_EXTRA_SERVER_MATRIX_SERVER_NAME',
];
if (requiredEnvVars.some((envVar) => !process.env[envVar])) {
throw new Error(`Missing required environment variables: ${requiredEnvVars.filter((envVar) => !process.env[envVar]).join(', ')}`);
}
}

View File

@@ -0,0 +1,17 @@
import type { Locator, Page } from '@playwright/test';
export class FederationAccountProfile {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get inputName(): Locator {
return this.page.locator('//label[contains(text(), "Name")]/..//input');
}
get btnSubmit(): Locator {
return this.page.getByRole('button', { name: 'Save changes', exact: true });
}
}

View File

@@ -0,0 +1,78 @@
import type { Locator, Page } from '@playwright/test';
import { FederationAdminFlextab } from './fragments/admin-flextab';
export class FederationAdmin {
private readonly page: Page;
readonly tabs: FederationAdminFlextab;
constructor(page: Page) {
this.page = page;
this.tabs = new FederationAdminFlextab(page);
}
get inputSearchRooms(): Locator {
return this.page.locator('input[placeholder ="Search rooms"]');
}
get inputSearchUsers(): Locator {
return this.page.locator('input[placeholder="Search Users"]');
}
get inputSearchSettings(): Locator {
return this.page.locator('input[type=search]');
}
get roomsInputName(): Locator {
return this.page.locator('//label[text()="Name"]/following-sibling::span//input');
}
get roomsInputDescription(): Locator {
return this.page.locator('//label[text()="Description"]/following-sibling::span//textarea');
}
get roomsInputAnnouncement(): Locator {
return this.page.locator('//label[text()="Announcement"]/following-sibling::span//textarea');
}
get roomsInputTopic(): Locator {
return this.page.locator('//label[text()="Topic"]/following-sibling::span//textarea');
}
get roomsInputFavorite(): Locator {
return this.page.locator('//label[text()="Favorite"]/following-sibling::span//input/following-sibling::i');
}
get roomsInputPrivate(): Locator {
return this.page.locator('//label[text()="Private"]/following-sibling::span//input/following-sibling::i');
}
get roomsInputReadOnly(): Locator {
return this.page.locator('//label[text()="Read Only"]/following-sibling::span//input/following-sibling::i');
}
get roomsInputArchived(): Locator {
return this.page.locator('//label[text()="Archived"]/following-sibling::span//input/following-sibling::i');
}
get roomsInputDefault(): Locator {
return this.page.locator('//label[text()="Default"]/following-sibling::span//input/following-sibling::i');
}
get roomsInputFeatured(): Locator {
return this.page.locator('//label[text()="Featured"]/following-sibling::span//input/following-sibling::i');
}
get roomsBtnDelete(): Locator {
return this.page.locator('role=button[name="Delete"]');
}
get roomsBtnUploadAvatar(): Locator {
return this.page.locator('role=button[name="Upload"]');
}
get roomsBtnDefaultAvatar(): Locator {
return this.page.locator('button[title="Set Default Avatar"]');
}
}

View File

@@ -0,0 +1,94 @@
import type { Locator, Page } from '@playwright/test';
import { FederationHomeContent } from './fragments/home-content';
import { FederationHomeFlextab } from './fragments/home-flextab';
import { FederationSidenav } from './fragments/home-sidenav';
import { Navbar, RoomToolbar, ToastMessages } from '../../page-objects/fragments';
import { CreateNewChannelModal, CreateNewDMModal } from '../../page-objects/fragments/modals';
export class FederationChannel {
private readonly page: Page;
readonly content: FederationHomeContent;
readonly sidenav: FederationSidenav;
readonly navbar: Navbar;
readonly tabs: FederationHomeFlextab;
readonly roomToolbar: RoomToolbar;
readonly toastMessage: ToastMessages;
readonly newChannelModal: CreateNewChannelModal;
readonly newDMModal: CreateNewDMModal;
constructor(page: Page) {
this.page = page;
this.content = new FederationHomeContent(page);
this.sidenav = new FederationSidenav(page);
this.navbar = new Navbar(page);
this.tabs = new FederationHomeFlextab(page);
this.roomToolbar = new RoomToolbar(page);
this.toastMessage = new ToastMessages(page);
this.newChannelModal = new CreateNewChannelModal(page);
this.newDMModal = new CreateNewDMModal(page);
}
get btnContextualbarClose(): Locator {
return this.page.locator('[data-qa="ContextualbarActionClose"]');
}
async getFederationServerName(): Promise<string> {
return (await this.page.locator('[data-qa="federated-origin-server-name"]').locator('span').innerText()).substring(1).trim();
}
async createPublicChannelAndInviteUsersUsingCreationModal(channelName: string, usernamesToInvite: string[]) {
await this.navbar.createNew('Channel', channelName, {
private: false,
federated: true,
members: usernamesToInvite,
});
}
async createDiscussionSearchingForChannel(channelName: string) {
await this.navbar.openCreate('Discussion');
await this.page.locator('//label[text()="Parent channel or group"]/following-sibling::span//input').waitFor();
await this.page.locator('//label[text()="Parent channel or group"]/following-sibling::span//input').focus();
await this.page.locator('//label[text()="Parent channel or group"]/following-sibling::span//input').type(channelName, { delay: 100 });
}
async createTeam(teamName: string) {
await this.navbar.createNew('Team', teamName);
}
async createPrivateGroupAndInviteUsersUsingCreationModal(channelName: string, usernamesToInvite: string[]) {
await this.navbar.createNew('Channel', channelName, {
private: true,
federated: true,
members: usernamesToInvite,
});
}
async createDirectMessagesUsingModal(usernamesToInvite: string[]) {
await this.navbar.openCreate('Direct message');
for await (const username of usernamesToInvite) {
await this.newDMModal.inviteUserToDM(username);
}
await this.newDMModal.btnCreate.click();
}
async createNonFederatedPublicChannelAndInviteUsersUsingCreationModal(channelName: string, usernamesToInvite: string[]) {
await this.navbar.openCreate('Channel');
await this.newChannelModal.checkboxPrivate.click();
await this.newChannelModal.inputName.fill(channelName);
for await (const username of usernamesToInvite) {
await this.newChannelModal.inviteUserToChannel(username);
}
await this.newChannelModal.btnCreate.click();
}
}

View File

@@ -0,0 +1,46 @@
import type { Locator, Page } from '@playwright/test';
export class FederationAdminFlextabUsers {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get btnNew(): Locator {
return this.page.locator('role=button[name="New"]');
}
get btnEdit(): Locator {
return this.page.locator('role=button[name="Edit"]');
}
get btnSave(): Locator {
return this.page.locator('role=button[name="Save"]');
}
get inputName(): Locator {
return this.page.locator('//label[text()="Name"]/following-sibling::span//input');
}
get inputUserName(): Locator {
return this.page.locator('//label[text()="Username"]/following-sibling::span//input');
}
get inputEmail(): Locator {
return this.page.locator('//label[text()="Email"]/following-sibling::span//input').first();
}
get inputPassword(): Locator {
return this.page.locator('//label[text()="Password"]/following-sibling::span//input');
}
get checkboxVerified(): Locator {
return this.page.locator('//label[text()="Email"]/following-sibling::span//input/following-sibling::i');
}
async addRole(role: string): Promise<void> {
await this.page.locator('//label[text()="Roles"]/following-sibling::span//input').click();
await this.page.locator(`li[value=${role}]`).click();
}
}

View File

@@ -0,0 +1,11 @@
import type { Page } from '@playwright/test';
import { FederationAdminFlextabUsers } from './admin-flextab-users';
export class FederationAdminFlextab {
readonly users: FederationAdminFlextabUsers;
constructor(page: Page) {
this.users = new FederationAdminFlextabUsers(page);
}
}

View File

@@ -0,0 +1,244 @@
import type { Locator, Page } from '@playwright/test';
export class FederationHomeContent {
protected readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get inputMessage(): Locator {
return this.page.locator('[name="msg"]');
}
get messagePopUpItems(): Locator {
return this.page.locator('role=menu[name="People"]');
}
get messageListItems(): Locator {
return this.page.locator('[role="listitem"][aria-roledescription="message"]');
}
get lastUserMessage(): Locator {
return this.messageListItems.last();
}
get lastUserMessageBody(): Locator {
return this.lastUserMessage.locator('[role="document"][aria-roledescription="message body"]');
}
async sendMessage(text: string): Promise<void> {
await this.page.locator('[name="msg"]').type(text);
await this.page.locator('button[aria-label="Send"]').click();
}
async sendMessageUsingEnter(text: string): Promise<void> {
await this.page.locator('[name="msg"]').type(text);
await this.page.keyboard.press('Enter');
}
async editLastMessage(message: string): Promise<void> {
await this.openLastMessageMenu();
await this.btnOptionEditMessage.click();
await this.page.locator('[name="msg"]').fill(message);
await this.page.keyboard.press('Enter');
}
async deleteLastMessage(): Promise<void> {
await this.openLastMessageMenu();
await this.btnOptionDeleteMessage.click();
await this.page.locator('#modal-root dialog .rcx-modal__inner .rcx-modal__footer .rcx-button--danger').click();
}
async starLastMessage(): Promise<void> {
await this.openLastMessageMenu();
await this.btnOptionStarMessage.waitFor();
await this.btnOptionStarMessage.click();
}
async replyInDm(message: string): Promise<void> {
await this.openLastMessageMenu();
await this.btnOptionReplyDirectly.click();
await this.page.waitForTimeout(2000);
await this.page.locator('[name="msg"]').type(message, { delay: 100 });
await this.page.waitForTimeout(2000);
await this.page.keyboard.press('Enter');
}
async sendAudioRecordedMessage(): Promise<void> {
await this.btnRecordAudio.click();
await this.page.waitForTimeout(3000);
await this.page.locator('.rc-message-box__icon.rc-message-box__audio-message-done').click();
await this.btnModalConfirm.click();
}
async sendAudioRecordedInThreadMessage(): Promise<void> {
await this.btnRecordAudio.nth(1).click();
await this.page.waitForTimeout(3000);
await this.page.locator('.rc-message-box__icon.rc-message-box__audio-message-done').click();
await this.btnModalConfirm.click();
}
async sendVideoRecordedMessage(): Promise<void> {
await this.btnVideoMessage.click();
await this.page.locator('.rcx-box.rcx-box--full.rcx-icon--name-video').click();
await this.page.waitForTimeout(3000);
await this.page.locator('.rcx-box.rcx-box--full.rcx-icon--name-stop-unfilled').click();
await this.page.locator('button >> text="Send"').click();
await this.page.waitForTimeout(3000);
await this.btnModalConfirm.click();
}
async dispatchSlashCommand(text: string): Promise<void> {
await this.page.locator('[name="msg"]').fill(text);
await this.page.locator('button[aria-label="Send"]').waitFor();
await this.page.locator('button[aria-label="Send"]').click();
}
get btnModalConfirm(): Locator {
return this.page.locator('#modal-root .rcx-button-group--align-end .rcx-button--primary');
}
get lastMessageFileName(): Locator {
return this.page.locator('[role="listitem"][aria-roledescription="message"]:last-child');
}
async getLastFileMessageByFileName(filename: string): Promise<Locator> {
return this.page
.locator('[role="listitem"][aria-roledescription="message"]:last-child .rcx-message-container')
.last()
.locator(`div[title="${filename}"]`);
}
async getLastFileThreadMessageByFileName(filename: string): Promise<Locator> {
return this.page
.locator('div.thread-list ul.thread [role="listitem"][aria-roledescription="message"]:last-child .rcx-message-container')
.last()
.locator(`div[title="${filename}"]`);
}
get lastFileMessage(): Locator {
return this.page.locator('[role="listitem"][aria-roledescription="message"]:last-child .rcx-message-container').last();
}
get waitForLastMessageTextAttachmentEqualsText(): Locator {
return this.page.locator('[role="listitem"][aria-roledescription="message"]:last-child .rcx-attachment__details .rcx-message-body');
}
get waitForLastThreadMessageTextAttachmentEqualsText(): Locator {
return this.page
.locator('div.thread-list ul.thread [role="listitem"][aria-roledescription="message"]')
.last()
.locator('.rcx-attachment__details');
}
get btnOptionEditMessage(): Locator {
return this.page.locator('[data-qa-id="edit-message"]');
}
get btnOptionDeleteMessage(): Locator {
return this.page.locator('[data-qa-id="delete-message"]');
}
get btnOptionPinMessage(): Locator {
return this.page.locator('[data-qa-id="pin-message"]');
}
get btnOptionStarMessage(): Locator {
return this.page.locator('[data-qa-id="star-message"]');
}
get btnVideoMessage(): Locator {
return this.page.locator('[data-qa-id="video-message"]');
}
get btnRecordAudio(): Locator {
return this.page.locator('[data-qa-id="audio-record"]');
}
get btnMenuMoreActions() {
return this.page.locator('[data-qa-id="menu-more-actions"]');
}
get btnContactEdit(): Locator {
return this.page.locator('.rcx-vertical-bar button:has-text("Edit")');
}
get btnOptionReplyInThread(): Locator {
return this.page.locator('[data-qa-id="reply-in-thread"]');
}
get btnOptionStartDiscussion(): Locator {
return this.page.locator('[data-qa-id="start-discussion"]');
}
get btnOptionReplyDirectly(): Locator {
return this.page.locator('[data-qa-id="reply-directly"]');
}
get lastThreadMessageText(): Locator {
return this.page.locator('div.thread-list ul.thread [role="listitem"][aria-roledescription="message"]').last();
}
async sendFileMessage(fileName: string): Promise<void> {
await this.page.locator('input[type=file]').setInputFiles(`./tests/e2e/federation/files/${fileName}`);
}
async sendThreadMessage(message: string): Promise<void> {
await this.page.getByRole('dialog').locator('[name="msg"]').last().fill(message);
await this.page.keyboard.press('Enter');
}
async openLastMessageMenu(): Promise<void> {
await this.lastUserMessage.hover();
await this.lastUserMessage.getByRole('button', { name: 'More', exact: true }).waitFor();
await this.lastUserMessage.getByRole('button', { name: 'More', exact: true }).click();
}
threadSendToChannelAlso(): Locator {
return this.page.getByRole('dialog').locator('label', { hasText: 'Also send to channel' });
}
async quoteMessage(message: string): Promise<void> {
await this.openLastMessageMenu();
await this.page.locator('[data-qa-id="quote-message"]').click();
await this.page.locator('[name="msg"]').fill(message);
await this.page.keyboard.press('Enter');
}
async openLastThreadMessageMenu(): Promise<void> {
await this.lastThreadMessageText.hover();
await this.lastThreadMessageText.getByRole('button', { name: 'More', exact: true }).waitFor();
await this.lastThreadMessageText.getByRole('button', { name: 'More', exact: true }).click();
}
async quoteMessageInsideThread(message: string): Promise<void> {
await this.openLastThreadMessageMenu();
await this.page.locator('[data-qa-id="quote-message"]').click();
await this.sendThreadMessage(message);
}
async reactToMessage(emoji: string): Promise<void> {
await this.openLastMessageMenu();
await this.page.locator('[data-qa-id="reaction-message"]').click();
await this.page.locator('input.js-emojipicker-search').type(emoji);
await this.page.locator(`[data-emoji="${emoji}"]`).last().click();
}
async unreactLastMessage(): Promise<void> {
await this.lastUserMessage.locator('.rcx-message-reactions__reaction').nth(1).waitFor();
await this.lastUserMessage.locator('.rcx-message-reactions__reaction').nth(1).click();
}
async getSystemMessageByText(text: string): Promise<Locator> {
return this.page.locator('[role="document"][aria-roledescription="system message body"]', { hasText: text });
}
async getLastSystemMessageName(): Promise<Locator> {
return this.page.locator('[role="listitem"][aria-roledescription="system message"]').last().getByRole('button');
}
async getAllReactions(): Promise<Locator> {
return this.lastUserMessage.locator('.rcx-message-reactions__reaction');
}
}

View File

@@ -0,0 +1,21 @@
import type { Locator, Page } from '@playwright/test';
export class FederationHomeFlextabChannels {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get btnAddExisting(): Locator {
return this.page.locator('button >> text="Add Existing"');
}
get inputChannels(): Locator {
return this.page.locator('#modal-root input').first();
}
get btnAdd(): Locator {
return this.page.locator('#modal-root button:has-text("Add")');
}
}

View File

@@ -0,0 +1,13 @@
import type { Locator, Page } from '@playwright/test';
export class FederationHomeFlextabDirectMessageMember {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
getUserInfoUsername(username: string): Locator {
return this.page.locator(`//div[contains(@class, "rcx-box--full") and contains(@title, "${username}")]`);
}
}

View File

@@ -0,0 +1,57 @@
import type { Locator, Page } from '@playwright/test';
export class FederationHomeFlextabMembers {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
getUserInList(username: string): Locator {
return this.page.locator(`[data-qa="MemberItem-${username}"]`);
}
get addUsersButton(): Locator {
return this.page.locator('role=button[name="Add"]');
}
get btnRemoveUserFromRoom(): Locator {
return this.page.locator('[value="removeUser"]');
}
get btnMenuUserInfo(): Locator {
return this.page.getByRole('dialog', { name: 'User Info', exact: true }).getByRole('button', { name: 'More', exact: true });
}
getKebabMenuForUser(username: string): Locator {
return this.page.locator(`[data-username="${username}"] [data-testid="menu"]`);
}
async getOptionFromKebabMenuForUser(optionName: string): Promise<Locator> {
return this.page.locator(`ol li[value="${optionName}"].rcx-option`);
}
async removeUserFromRoom(username: string): Promise<void> {
await this.getUserInList(username).hover();
await this.getKebabMenuForUser(username).click();
await (await this.getOptionFromKebabMenuForUser('removeUser')).click();
await this.page.locator('#modal-root dialog .rcx-modal__inner .rcx-modal__footer .rcx-button--danger').click();
}
async addMultipleUsers(usernames: string[]) {
await this.addUsersButton.click();
for await (const username of usernames) {
await this.page.getByRole('textbox', { name: 'Choose users' }).click();
await this.page.getByRole('textbox', { name: 'Choose users' }).fill(username);
await this.page.getByRole('listbox').waitFor();
await this.page.getByRole('listbox').selectOption(username);
}
await this.addUsersButton.click();
}
async showAllUsers() {
await this.page.locator('.rcx-select >> text=Online').first().click();
await this.page.locator('.rcx-option:has-text("All")').first().click();
}
}

View File

@@ -0,0 +1,41 @@
import type { Locator, Page } from '@playwright/test';
export class FederationHomeFlextabNotificationPreferences {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get btnSave(): Locator {
return this.page.locator('role=button[name="Save"]');
}
getPreferenceByDevice(device: string): Locator {
return this.page.locator(`//div[@id="${device}Alert"]`);
}
async selectDropdownById(text: string): Promise<void> {
await this.page.locator(`//div[@id="${text}"]`).click();
}
async selectOptionByLabel(text: string): Promise<void> {
await this.page.locator(`li.rcx-option >> text="${text}"`).click();
}
async selectDevice(text: string): Promise<void> {
await this.page.locator(`[data-qa-id="${text}-notifications"]`).click();
}
async updateDevicePreference(device: string): Promise<void> {
await this.selectDevice(device);
await this.selectDropdownById(`${device}Alert`);
await this.selectOptionByLabel('Mentions');
}
async updateAllNotificationPreferences(): Promise<void> {
await this.updateDevicePreference('Desktop');
await this.updateDevicePreference('Mobile');
await this.updateDevicePreference('Email');
}
}

View File

@@ -0,0 +1,49 @@
import type { Locator, Page } from '@playwright/test';
export class FederationHomeFlextabRoom {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get btnEdit(): Locator {
return this.page.locator('role=button[name="Edit"]');
}
get btnLeave(): Locator {
return this.page.locator('role=button[name="Leave"]');
}
get btnDelete(): Locator {
return this.page.locator('role=button[name="Delete"]');
}
get inputName(): Locator {
return this.page.getByRole('dialog').getByRole('textbox', { name: 'Name' });
}
get inputTopic(): Locator {
return this.page.getByRole('dialog').getByRole('textbox', { name: 'Topic' });
}
get inputAnnouncement(): Locator {
return this.page.getByRole('dialog').getByRole('textbox', { name: 'Announcement' });
}
get inputDescription(): Locator {
return this.page.getByRole('dialog').getByRole('textbox', { name: 'Description' });
}
get checkboxReadOnly(): Locator {
return this.page.locator('text=Read OnlyOnly authorized users can write new messages >> i');
}
get btnSave(): Locator {
return this.page.locator('role=button[name="Save"]');
}
get btnModalConfirm(): Locator {
return this.page.locator('#modal-root dialog .rcx-modal__inner .rcx-modal__footer .rcx-button--danger');
}
}

View File

@@ -0,0 +1,44 @@
import type { Locator, Page } from '@playwright/test';
import { FederationHomeFlextabChannels } from './home-flextab-channels';
import { FederationHomeFlextabDirectMessageMember } from './home-flextab-dm-member';
import { FederationHomeFlextabMembers } from './home-flextab-members';
import { FederationHomeFlextabNotificationPreferences } from './home-flextab-notificationPreferences';
import { FederationHomeFlextabRoom } from './home-flextab-room';
export class FederationHomeFlextab {
private readonly page: Page;
readonly members: FederationHomeFlextabMembers;
readonly dmUserMember: FederationHomeFlextabDirectMessageMember;
readonly room: FederationHomeFlextabRoom;
readonly channels: FederationHomeFlextabChannels;
readonly notificationPreferences: FederationHomeFlextabNotificationPreferences;
constructor(page: Page) {
this.page = page;
this.members = new FederationHomeFlextabMembers(page);
this.room = new FederationHomeFlextabRoom(page);
this.channels = new FederationHomeFlextabChannels(page);
this.notificationPreferences = new FederationHomeFlextabNotificationPreferences(page);
this.dmUserMember = new FederationHomeFlextabDirectMessageMember(page);
}
get btnAddExistingChannelToTeam(): Locator {
return this.page.locator('role=button[name="Add Existing"]');
}
async searchForChannelOnAddChannelToTeam(channelName: string): Promise<void> {
await this.page.locator('//label[contains(text(), "Channels")]/..//input').focus();
await this.page.waitForTimeout(2000);
await this.page.locator('//label[contains(text(), "Channels")]/..//input').type(channelName);
}
get userInfoUsername(): Locator {
return this.page.locator('[data-qa="UserInfoUserName"]');
}
}

View File

@@ -0,0 +1,51 @@
import type { Locator, Page } from '@playwright/test';
export class FederationSidenav {
private readonly page: Page;
constructor(page: Page) {
this.page = page;
}
get checkboxFederatedChannel(): Locator {
return this.page.locator(
'//*[@id="modal-root"]//*[contains(@class, "rcx-field") and contains(text(), "Federated")]/../following-sibling::label/i',
);
}
async countFilteredChannelsOnDirectory(name: string): Promise<number> {
await this.page.locator('button[title="Directory"]').click();
await this.page.locator('button:has-text("Channels")').click();
await this.page.locator('input[placeholder ="Search Channels"]').focus();
await this.page.locator('input[placeholder ="Search Channels"]').type(name, { delay: 100 });
await this.page.waitForTimeout(5000);
return this.page.locator('table tbody tr').count();
}
async openChatWhenHaveMultipleWithTheSameName(name: string, item: number): Promise<void> {
await this.page.locator('role=navigation >> role=button[name=Search]').click();
await this.page.locator('role=search >> role=searchbox').focus();
await this.page.locator('role=search >> role=searchbox').type(name);
await this.page.waitForTimeout(2000);
await this.page.locator(`role=search >> role=listbox >> role=link >> text="${name}"`).nth(item).click({ force: true });
}
async countRoomsByNameOnSearch(name: string): Promise<number> {
await this.page.locator('role=navigation >> role=button[name=Search]').click();
await this.page.locator('role=search >> role=searchbox').focus();
await this.page.locator('role=search >> role=searchbox').type(name);
await this.page.locator(`role=search >> role=listbox >> role=link >> text="${name}"`).waitFor();
await this.page.waitForTimeout(2000);
return this.page.locator(`role=search >> role=listbox >> role=link >> text="${name}"`).count();
}
async openDMMultipleChat(name: string): Promise<void> {
await this.page.locator('role=navigation >> role=button[name=Search]').click();
await this.page.locator('role=search >> role=searchbox').focus();
await this.page.locator('role=search >> role=searchbox').type(name);
await this.page.locator(`role=search >> role=listbox >> role=link >> text="${name}"`).waitFor();
await this.page.locator(`.rcx-sidebar-item`).nth(1).click({ force: true });
}
}

View File

@@ -0,0 +1,81 @@
import { faker } from '@faker-js/faker';
import * as constants from '../../config/constants';
import { FederationAdmin } from '../../page-objects/admin';
import { FederationChannel } from '../../page-objects/channel';
import { doLogin } from '../../utils/auth';
import { createChannelUsingAPI } from '../../utils/channel';
import { formatIntoFullMatrixUsername } from '../../utils/format';
import { registerUser } from '../../utils/register-user';
import { test, expect, setupTesting, tearDownTesting } from '../../utils/test';
test.describe.parallel('Federation - Admin Panel - Rooms', () => {
let poFederationChannelServer1: FederationChannel;
let userFromServer2UsernameOnly: string;
const channelName = faker.string.uuid();
let poFederationAdmin: FederationAdmin;
test.beforeAll(async ({ apiServer1, apiServer2, browser }) => {
await setupTesting(apiServer1);
await setupTesting(apiServer2);
userFromServer2UsernameOnly = await registerUser(apiServer2);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);
const page = await browser.newPage();
poFederationChannelServer1 = new FederationChannel(page);
await doLogin({
page,
server: constants.RC_SERVER_1,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await createChannelUsingAPI(apiServer2, channelName);
await poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [fullUsernameFromServer2]);
await page.close();
});
test.afterAll(async ({ apiServer1, apiServer2 }) => {
await tearDownTesting(apiServer1);
await tearDownTesting(apiServer2);
});
test.beforeEach(async ({ page }) => {
poFederationAdmin = new FederationAdmin(page);
await doLogin({
page,
server: {
url: constants.RC_SERVER_2.url,
username: constants.RC_SERVER_2.username,
password: constants.RC_SERVER_2.password,
},
});
await page.goto(`${constants.RC_SERVER_2.url}/admin/rooms`);
});
test('expect to have the 2 rooms(with the same name) created and showing correctly', async ({ page }) => {
await poFederationAdmin.inputSearchRooms.type(channelName);
await page.waitForTimeout(5000);
await expect(await page.locator(`table tbody tr`).count()).toBe(2);
});
test('expect to be able to edit only (name, topic and favorite) when the room is a federated one', async ({ page }) => {
await poFederationAdmin.inputSearchRooms.type(channelName);
await page.waitForTimeout(5000);
await page.locator(`table tbody tr`).first().click();
await expect(poFederationAdmin.roomsInputName).not.toBeDisabled();
await expect(poFederationAdmin.roomsInputTopic).not.toBeDisabled();
await expect(poFederationAdmin.roomsInputFavorite).not.toBeDisabled();
await expect(poFederationAdmin.roomsInputDescription).not.toBeVisible();
await expect(poFederationAdmin.roomsInputAnnouncement).not.toBeVisible();
await expect(poFederationAdmin.roomsInputPrivate).not.toBeVisible();
await expect(poFederationAdmin.roomsInputReadOnly).not.toBeVisible();
await expect(poFederationAdmin.roomsInputArchived).not.toBeVisible();
await expect(poFederationAdmin.roomsInputDefault).toBeDisabled();
await expect(poFederationAdmin.roomsInputFeatured).toBeDisabled();
await expect(poFederationAdmin.roomsBtnDelete).toBeDisabled();
await expect(poFederationAdmin.roomsBtnUploadAvatar).toBeDisabled();
await expect(poFederationAdmin.roomsBtnDefaultAvatar).toBeDisabled();
});
});

View File

@@ -0,0 +1,128 @@
import * as constants from '../../config/constants';
import { FederationAdmin } from '../../page-objects/admin';
import { FederationChannel } from '../../page-objects/channel';
import { doLogin } from '../../utils/auth';
import { createChannelAndInviteRemoteUserToCreateLocalUser } from '../../utils/channel';
import { formatIntoFullMatrixUsername, formatUsernameAndDomainIntoMatrixFormat } from '../../utils/format';
import { registerUser } from '../../utils/register-user';
import { test, expect, setupTesting, tearDownTesting } from '../../utils/test';
test.describe.parallel('Federation - Admin Panel - Users', () => {
let poFederationChannelServer1: FederationChannel;
let userFromServer2UsernameOnly: string;
let usernameWithDomainFromServer2: string;
let poFederationAdmin: FederationAdmin;
test.beforeEach(async ({ page }) => {
poFederationAdmin = new FederationAdmin(page);
});
test.beforeAll(async ({ apiServer1, apiServer2, browser }) => {
await setupTesting(apiServer1);
await setupTesting(apiServer2);
userFromServer2UsernameOnly = await registerUser(apiServer2);
usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);
const page = await browser.newPage();
poFederationChannelServer1 = new FederationChannel(page);
await createChannelAndInviteRemoteUserToCreateLocalUser({
page,
poFederationChannelServer: poFederationChannelServer1,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
});
});
test.afterAll(async ({ apiServer1, apiServer2 }) => {
await tearDownTesting(apiServer1);
await tearDownTesting(apiServer2);
});
test.beforeEach(async ({ page }) => {
poFederationChannelServer1 = new FederationChannel(page);
await doLogin({
page,
server: {
url: constants.RC_SERVER_1.url,
username: constants.RC_SERVER_1.username,
password: constants.RC_SERVER_1.password,
},
});
await page.goto(`${constants.RC_SERVER_1.url}/admin/users`);
});
test('expect to not be able to edit federated users from the admin panel', async ({ page }) => {
await poFederationAdmin.inputSearchUsers.type(usernameWithDomainFromServer2);
await page.locator(`table tr`).locator(`figure[data-username="${usernameWithDomainFromServer2}"]`).click();
await expect(poFederationAdmin.tabs.users.btnEdit).toBeDisabled();
});
test('expect to not be able to edit federated users from the admin panel (trying to bypass by url)', async ({ page }) => {
await poFederationAdmin.inputSearchUsers.type(usernameWithDomainFromServer2);
await page.locator(`table tr`).locator(`figure[data-username="${usernameWithDomainFromServer2}"]`).click();
await expect(poFederationAdmin.tabs.users.btnEdit).toBeDisabled();
const currentUrl = await page.url();
await page.goto(`${currentUrl.replace('info', 'edit')}`);
await expect(page.locator('.rcx-box.rcx-box--full.rcx-callout__wrapper')).toBeVisible();
await expect(
page.locator('.rcx-box.rcx-box--full.rcx-callout__wrapper').locator('.rcx-box.rcx-box--full.rcx-callout__children'),
).toContainText('Not possible to edit a federated user');
});
test('expect not to have the kebab menu enabled, since there should not be any menu option enabled for federated users', async ({
page,
}) => {
await poFederationAdmin.inputSearchUsers.type(usernameWithDomainFromServer2);
await page.locator(`table tr`).locator(`figure[data-username="${usernameWithDomainFromServer2}"]`).click();
await expect(page.locator('[data-testid="menu"]')).not.toBeVisible();
});
test('expect to federated users (remote only) not being counted as a seat cap in an EE environment', async ({
browser,
page,
apiServer2,
}) => {
const before = parseInt((await page.locator('role=status').textContent())?.replace('Seats Available', '').trim() || '0');
const newUserFromServer2 = await registerUser(apiServer2);
const page2 = await browser.newPage();
const poFederationChannelServer1ForUser2 = new FederationChannel(page2);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(newUserFromServer2, constants.RC_SERVER_2.matrixServerName);
await createChannelAndInviteRemoteUserToCreateLocalUser({
page: page2,
poFederationChannelServer: poFederationChannelServer1ForUser2,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
});
const after = parseInt((await page.locator('role=status').textContent())?.replace('Seats Available', '').trim() || '0');
expect(before).toEqual(after);
await page2.close();
});
test('expect to federated users (but local ones) being counted as a seat cap in an EE environment', async ({
browser,
page,
apiServer1,
}) => {
const before = parseInt((await page.locator('role=status').textContent())?.replace('Seats Available', '').trim() || '0');
const newUserFromServer1 = await registerUser(apiServer1);
const page2 = await browser.newPage();
const poFederationChannelServer1ForUser2 = new FederationChannel(page2);
const fullUsernameFromServer1 = formatIntoFullMatrixUsername(newUserFromServer1, constants.RC_SERVER_1.matrixServerName);
await createChannelAndInviteRemoteUserToCreateLocalUser({
page: page2,
poFederationChannelServer: poFederationChannelServer1ForUser2,
fullUsernameFromServer: fullUsernameFromServer1,
server: constants.RC_SERVER_1,
});
await page.reload();
const after = parseInt((await page.locator('role=status').textContent())?.replace('Seats Available', '').trim() || '0');
expect(before).not.toEqual(after);
expect(before - 1).toEqual(after);
await page2.close();
});
});

View File

@@ -0,0 +1,88 @@
import { faker } from '@faker-js/faker';
import { CreateNewChannelModal } from '../../../page-objects/fragments/modals';
import * as constants from '../../config/constants';
import { FederationChannel } from '../../page-objects/channel';
import { doLogin } from '../../utils/auth';
import { createGroupAndInviteRemoteUserToCreateLocalUser } from '../../utils/channel';
import { formatIntoFullMatrixUsername } from '../../utils/format';
import { registerUser } from '../../utils/register-user';
import { test, expect, setupTesting, tearDownTesting } from '../../utils/test';
test.describe.parallel('Federation - CE version', () => {
let poFederationChannelServer2: FederationChannel;
let userFromServer2UsernameOnly: string;
let userFromServer1UsernameOnly: string;
let fullUsernameFromServer1: string;
let fullUsernameFromServer2: string;
let newChannelModal: CreateNewChannelModal;
test.beforeAll(async ({ apiServer1, apiServer2, browser }) => {
await setupTesting(apiServer1);
await setupTesting(apiServer2);
userFromServer1UsernameOnly = await registerUser(apiServer1);
userFromServer2UsernameOnly = await registerUser(apiServer2);
fullUsernameFromServer1 = formatIntoFullMatrixUsername(userFromServer1UsernameOnly, constants.RC_SERVER_1.matrixServerName);
fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);
const page = await browser.newPage();
poFederationChannelServer2 = new FederationChannel(page);
});
test.afterAll(async ({ apiServer1, apiServer2 }) => {
await tearDownTesting(apiServer1);
await tearDownTesting(apiServer2);
});
test.beforeEach(async ({ page }) => {
poFederationChannelServer2 = new FederationChannel(page);
await doLogin({
page,
server: {
url: constants.RC_SERVER_2.url,
username: constants.RC_SERVER_2.username,
password: constants.RC_SERVER_2.password,
},
});
await page.goto(`${constants.RC_SERVER_2.url}/home`);
});
test('expect to not be able to create channels from the UI', async ({ page }) => {
newChannelModal = new CreateNewChannelModal(page);
await poFederationChannelServer2.navbar.openChat('Channel');
await newChannelModal.advancedSettingsAccordion.click();
await expect(newChannelModal.checkboxFederated).toBeDisabled();
});
test('expect to not be able to create DMs from UI inviting external users (an user who does not exists on the server yet)', async () => {
await poFederationChannelServer2.createDirectMessagesUsingModal([fullUsernameFromServer1]);
await poFederationChannelServer2.toastMessage.waitForDisplay({ type: 'error' });
});
test('expect to not be able to create DMs from UI inviting external users (an user who already exists in the server)', async ({
browser,
}) => {
const page2 = await browser.newPage();
const poFederationChannelServer1 = new FederationChannel(page2);
await createGroupAndInviteRemoteUserToCreateLocalUser({
page: page2,
poFederationChannelServer: poFederationChannelServer1,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
});
await poFederationChannelServer2.createDirectMessagesUsingModal([fullUsernameFromServer1]);
await poFederationChannelServer2.toastMessage.waitForDisplay({ type: 'error' });
});
test('expect to not be able to invite federated users to non-federated rooms (using modal)', async () => {
const channelName = faker.string.uuid();
await poFederationChannelServer2.createNonFederatedPublicChannelAndInviteUsersUsingCreationModal(channelName, [
fullUsernameFromServer2,
]);
await poFederationChannelServer2.navbar.openChat(channelName);
await poFederationChannelServer2.roomToolbar.openMembersTab();
await poFederationChannelServer2.tabs.members.showAllUsers();
await expect(poFederationChannelServer2.tabs.members.getUserInList(constants.RC_SERVER_2.username)).toBeVisible();
});
});

View File

@@ -0,0 +1,876 @@
import * as constants from '../../config/constants';
import { FederationChannel } from '../../page-objects/channel';
import { doLogin } from '../../utils/auth';
import { createChannelAndInviteRemoteUserToCreateLocalUser } from '../../utils/channel';
import { formatIntoFullMatrixUsername, formatUsernameAndDomainIntoMatrixFormat } from '../../utils/format';
import { registerUser } from '../../utils/register-user';
import { test, expect, setupTesting, tearDownTesting } from '../../utils/test';
test.describe.parallel('Federation - Direct Messages', () => {
let poFederationChannelServer1: FederationChannel;
let userFromServer2UsernameOnly: string;
let userFromServer1UsernameOnly: string;
test.beforeAll(async ({ apiServer1, apiServer2, browser }) => {
await setupTesting(apiServer1);
await setupTesting(apiServer2);
userFromServer1UsernameOnly = await registerUser(apiServer1);
userFromServer2UsernameOnly = await registerUser(apiServer2);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);
const page = await browser.newPage();
poFederationChannelServer1 = new FederationChannel(page);
await createChannelAndInviteRemoteUserToCreateLocalUser({
page,
poFederationChannelServer: poFederationChannelServer1,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
});
});
test.afterAll(async ({ apiServer1, apiServer2 }) => {
await tearDownTesting(apiServer1);
await tearDownTesting(apiServer2);
});
test.beforeEach(async ({ page }) => {
poFederationChannelServer1 = new FederationChannel(page);
await doLogin({
page,
server: {
url: constants.RC_SERVER_1.url,
username: constants.RC_SERVER_1.username,
password: constants.RC_SERVER_1.password,
},
});
await page.addInitScript(() => {
window.localStorage.setItem('fuselage-localStorage-members-list-type', JSON.stringify('online'));
});
});
test.describe('Direct Messages (DMs)', () => {
test.describe('Inviting users using the creation modal', () => {
test('expect to create a DM inviting an user from the Server B who does not exist in Server A yet', async ({
browser,
apiServer2,
page,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
const usernameFromServer2 = await registerUser(apiServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: usernameFromServer2,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
usernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.roomToolbar.openUserInfo();
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await poFederationChannelServer2.roomToolbar.openUserInfo();
await expect(poFederationChannelServer1.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer2.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test('expect to create a DM inviting an user from the Server B who already exist in Server A', async ({ browser, page }) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.createDirectMessagesUsingModal([userFromServer2UsernameOnly]);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.roomToolbar.openUserInfo();
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await poFederationChannelServer2.roomToolbar.openUserInfo();
await expect(poFederationChannelServer1.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer2.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test.describe('With multiple users (when the remote user does not exists in the server A yet)', () => {
let createdUsernameFromServer2: string;
test('expect to create a DM inviting an user from the Server B who does not exist in Server A yet + an user from Server A only (locally)', async ({
browser,
apiServer2,
page,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
createdUsernameFromServer2 = await registerUser(apiServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: createdUsernameFromServer2,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(createdUsernameFromServer2, constants.RC_SERVER_2.matrixServerName);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
createdUsernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
const adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
const userCreatedWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer1UsernameOnly,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2, userFromServer1UsernameOnly]);
await poFederationChannelServer1.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer1.roomToolbar.openMembersTab();
await poFederationChannelServer1.tabs.members.showAllUsers();
await poFederationChannelServer2.sidenav.openDMMultipleChat(userCreatedWithDomainFromServer1);
await poFederationChannelServer2.roomToolbar.openMembersTab();
await poFederationChannelServer2.tabs.members.showAllUsers();
await expect(poFederationChannelServer1.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(createdUsernameFromServer2)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(userCreatedWithDomainFromServer1)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(adminUsernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test('expect the user from Server A (locally) is able to access the previous created group', async ({ browser }) => {
const page2 = await browser.newPage();
const poFederationChannel1ForUser2 = new FederationChannel(page2);
await doLogin({
page: page2,
server: {
url: constants.RC_SERVER_1.url,
username: userFromServer1UsernameOnly,
password: constants.RC_SERVER_1.password,
},
storeState: false,
});
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
createdUsernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
await page2.goto(`${constants.RC_SERVER_1.url}/home`);
await poFederationChannel1ForUser2.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);
await poFederationChannel1ForUser2.roomToolbar.openMembersTab();
await poFederationChannel1ForUser2.tabs.members.showAllUsers();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await page2.close();
});
});
test.describe('With multiple users (when the user from Server B already exists in Server A)', () => {
test('expect to create a DM inviting an user from the Server B who already exist in Server A + an user from Server A only (locally)', async ({
browser,
page,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
const usernameOriginalFromServer1OnlyWithDomain = formatUsernameAndDomainIntoMatrixFormat(
userFromServer1UsernameOnly,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.createDirectMessagesUsingModal([userFromServer2UsernameOnly, userFromServer1UsernameOnly]);
await poFederationChannelServer1.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer1.roomToolbar.openMembersTab();
await poFederationChannelServer1.tabs.members.showAllUsers();
await poFederationChannelServer2.sidenav.openDMMultipleChat(usernameOriginalFromServer1OnlyWithDomain);
await poFederationChannelServer2.roomToolbar.openMembersTab();
await poFederationChannelServer2.tabs.members.showAllUsers();
await expect(poFederationChannelServer1.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(userFromServer2UsernameOnly)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(usernameOriginalFromServer1OnlyWithDomain)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(usernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test('expect the user from Server A (locally) is able to access the previous created', async ({ browser }) => {
const page2 = await browser.newPage();
const poFederationChannel1ForUser2 = new FederationChannel(page2);
await doLogin({
page: page2,
server: {
url: constants.RC_SERVER_1.url,
username: userFromServer1UsernameOnly,
password: constants.RC_SERVER_1.password,
},
storeState: false,
});
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
await page2.goto(`${constants.RC_SERVER_1.url}/home`);
await poFederationChannel1ForUser2.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);
await poFederationChannel1ForUser2.roomToolbar.openMembersTab();
await poFederationChannel1ForUser2.tabs.members.showAllUsers();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await page2.close();
});
});
});
test.describe('Using Slash commands', () => {
test('expect to create a DM inviting an user from the Server B who does not exist in Server A yet', async ({
browser,
page,
apiServer2,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
const usernameFromServer2 = await registerUser(apiServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: usernameFromServer2,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
usernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.navbar.openChat('general');
await poFederationChannelServer1.content.dispatchSlashCommand(`/federation dm ${fullUsernameFromServer2}`);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.roomToolbar.openUserInfo();
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await poFederationChannelServer2.roomToolbar.openUserInfo();
await expect(poFederationChannelServer1.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer2.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test('expect to create a DM inviting an user from the Server B who already exist in Server A', async ({
browser,
page,
apiServer2,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
const createdUsernameFromServer2 = await registerUser(apiServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: createdUsernameFromServer2,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(createdUsernameFromServer2, constants.RC_SERVER_2.matrixServerName);
await poFederationChannelServer1.navbar.logout();
await createChannelAndInviteRemoteUserToCreateLocalUser({
page,
poFederationChannelServer: poFederationChannelServer1,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
closePageAfterCreation: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
createdUsernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
const adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.navbar.openChat('general');
await poFederationChannelServer1.content.dispatchSlashCommand(`/federation dm @${usernameWithDomainFromServer2}`);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.roomToolbar.openUserInfo();
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer2.navbar.openChat(adminUsernameWithDomainFromServer1);
await poFederationChannelServer2.roomToolbar.openUserInfo();
await expect(poFederationChannelServer1.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer2.tabs.dmUserMember.getUserInfoUsername(adminUsernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test('expect to create a DM inviting an user from the Server A who does not exist in Server B yet', async ({
browser,
page,
apiServer1,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
const createdUsernameFromServer1 = await registerUser(apiServer1);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: constants.RC_SERVER_2.username,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const fullUsernameFromServer1 = formatIntoFullMatrixUsername(createdUsernameFromServer1, constants.RC_SERVER_1.matrixServerName);
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
createdUsernameFromServer1,
constants.RC_SERVER_1.matrixServerName,
);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_2.username,
constants.RC_SERVER_2.matrixServerName,
);
await poFederationChannelServer2.navbar.openChat('general');
await poFederationChannelServer2.content.dispatchSlashCommand(`/federation dm ${fullUsernameFromServer1}`);
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await poFederationChannelServer2.roomToolbar.openUserInfo();
await poFederationChannelServer2.content.sendMessage('hello world');
await poFederationChannelServer1.navbar.logout();
await doLogin({
page,
server: {
url: constants.RC_SERVER_1.url,
username: createdUsernameFromServer1,
password: constants.RC_SERVER_1.password,
},
storeState: false,
});
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.roomToolbar.openUserInfo();
await expect(poFederationChannelServer2.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer1)).toBeVisible();
await expect(poFederationChannelServer1.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer2)).toBeVisible();
await pageForServer2.close();
});
test('expect to create a DM inviting an user from the Server A who already exist in Server B', async ({
browser,
page,
apiServer2,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
const createdUsernameFromServer2 = await registerUser(apiServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: createdUsernameFromServer2,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(createdUsernameFromServer2, constants.RC_SERVER_2.matrixServerName);
await poFederationChannelServer1.navbar.logout();
await createChannelAndInviteRemoteUserToCreateLocalUser({
page,
poFederationChannelServer: poFederationChannelServer1,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
closePageAfterCreation: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
createdUsernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
const adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer2.navbar.openChat('general');
await poFederationChannelServer2.content.dispatchSlashCommand(`/federation dm @${adminUsernameWithDomainFromServer1}`);
await page.waitForTimeout(2000);
await poFederationChannelServer2.navbar.openChat(adminUsernameWithDomainFromServer1);
await poFederationChannelServer2.roomToolbar.openUserInfo();
await poFederationChannelServer2.content.sendMessage('hello world');
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.roomToolbar.openUserInfo();
await expect(poFederationChannelServer2.tabs.dmUserMember.getUserInfoUsername(adminUsernameWithDomainFromServer1)).toBeVisible();
await expect(poFederationChannelServer1.tabs.dmUserMember.getUserInfoUsername(usernameWithDomainFromServer2)).toBeVisible();
await pageForServer2.close();
});
test.describe('With multiple users (when the remote user does not exists in the server A yet)', () => {
let createdUsernameFromServer2: string;
test('expect to create a DM, and invite an user from the Server B who does not exist in Server A yet + an user from Server A only (locally)', async ({
browser,
apiServer2,
page,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
createdUsernameFromServer2 = await registerUser(apiServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: createdUsernameFromServer2,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(createdUsernameFromServer2, constants.RC_SERVER_2.matrixServerName);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
createdUsernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
const usernameOriginalFromServer1OnlyWithDomain = formatUsernameAndDomainIntoMatrixFormat(
userFromServer1UsernameOnly,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.navbar.openChat('general');
await poFederationChannelServer1.content.dispatchSlashCommand(
`/federation dm ${fullUsernameFromServer2} @${userFromServer1UsernameOnly}`,
);
await poFederationChannelServer1.sidenav.openDMMultipleChat(userFromServer1UsernameOnly);
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer1.roomToolbar.openMembersTab();
await poFederationChannelServer1.tabs.members.showAllUsers();
await poFederationChannelServer2.sidenav.openDMMultipleChat(usernameOriginalFromServer1OnlyWithDomain);
await poFederationChannelServer2.roomToolbar.openMembersTab();
await poFederationChannelServer2.tabs.members.showAllUsers();
await expect(poFederationChannelServer1.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(createdUsernameFromServer2)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(usernameOriginalFromServer1OnlyWithDomain)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(usernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test('expect the user from Server A (locally) is able to access the previous created group', async ({ browser }) => {
const page2 = await browser.newPage();
const poFederationChannel1ForUser2 = new FederationChannel(page2);
await doLogin({
page: page2,
server: {
url: constants.RC_SERVER_1.url,
username: userFromServer1UsernameOnly,
password: constants.RC_SERVER_1.password,
},
storeState: false,
});
await page2.goto(`${constants.RC_SERVER_1.url}/home`);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
createdUsernameFromServer2,
constants.RC_SERVER_2.matrixServerName,
);
await poFederationChannel1ForUser2.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);
await poFederationChannel1ForUser2.roomToolbar.openMembersTab();
await poFederationChannel1ForUser2.tabs.members.showAllUsers();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await page2.close();
});
});
test.describe('With multiple users (when the user from Server B already exists in Server A)', () => {
test('expect to create a DM, and invite an user from the Server B who already exist in Server A + an user from Server A only (locally)', async ({
browser,
page,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
const usernameOriginalFromServer1OnlyWithDomain = formatUsernameAndDomainIntoMatrixFormat(
userFromServer1UsernameOnly,
constants.RC_SERVER_1.matrixServerName,
);
await poFederationChannelServer1.navbar.openChat('general');
await poFederationChannelServer1.content.dispatchSlashCommand(
`/federation dm @${usernameWithDomainFromServer2} @${userFromServer1UsernameOnly}`,
);
await poFederationChannelServer1.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.content.sendMessage('hello world');
await poFederationChannelServer1.roomToolbar.openMembersTab();
await poFederationChannelServer1.tabs.members.showAllUsers();
await poFederationChannelServer2.sidenav.openDMMultipleChat(usernameOriginalFromServer1OnlyWithDomain);
await poFederationChannelServer2.roomToolbar.openMembersTab();
await poFederationChannelServer2.tabs.members.showAllUsers();
await expect(poFederationChannelServer1.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannelServer1.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(userFromServer2UsernameOnly)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(usernameOriginalFromServer1OnlyWithDomain)).toBeVisible();
await expect(poFederationChannelServer2.tabs.members.getUserInList(usernameWithDomainFromServer1)).toBeVisible();
await pageForServer2.close();
});
test('expect the user from Server A (locally) is able to access the previous created group', async ({ browser }) => {
const page2 = await browser.newPage();
const poFederationChannel1ForUser2 = new FederationChannel(page2);
await doLogin({
page: page2,
server: {
url: constants.RC_SERVER_1.url,
username: userFromServer1UsernameOnly,
password: constants.RC_SERVER_1.password,
},
storeState: false,
});
await page2.goto(`${constants.RC_SERVER_1.url}/home`);
const usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
await poFederationChannel1ForUser2.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);
await poFederationChannel1ForUser2.roomToolbar.openMembersTab();
await poFederationChannel1ForUser2.tabs.members.showAllUsers();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(usernameWithDomainFromServer2)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(userFromServer1UsernameOnly)).toBeVisible();
await expect(poFederationChannel1ForUser2.tabs.members.getUserInList(constants.RC_SERVER_1.username)).toBeVisible();
await page2.close();
});
});
});
test.describe('DMs', () => {
let createdUsernameFromServer2: string;
let usernameWithDomainFromServer2: string;
let fullUsernameFromServer2: string;
const usernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
test.beforeAll(async ({ browser, apiServer2 }) => {
createdUsernameFromServer2 = await registerUser(apiServer2);
const page = await browser.newPage();
const poDmFederationServer1 = new FederationChannel(page);
await doLogin({
page,
server: {
url: constants.RC_SERVER_1.url,
username: constants.RC_SERVER_1.username,
password: constants.RC_SERVER_1.password,
},
});
fullUsernameFromServer2 = formatIntoFullMatrixUsername(createdUsernameFromServer2, constants.RC_SERVER_2.matrixServerName);
usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
await poDmFederationServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);
await page.close();
});
test.describe('Visual Elements', () => {
test('expect the calls button to be disabled', async ({ browser, page }) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.content.sendMessage('hello world');
await expect(poFederationChannelServer1.roomToolbar.btnVoiceCall).toBeDisabled();
await expect(poFederationChannelServer1.roomToolbar.btnVideoCall).toBeDisabled();
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await expect(poFederationChannelServer2.roomToolbar.btnVoiceCall).toBeDisabled();
await expect(poFederationChannelServer1.roomToolbar.btnVideoCall).toBeDisabled();
await pageForServer2.close();
});
test('expect the discussion button to be disabled', async ({ browser, page }) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.content.sendMessage('hello world');
await expect(poFederationChannelServer1.roomToolbar.btnDiscussion).toBeDisabled();
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await expect(poFederationChannelServer2.roomToolbar.btnDiscussion).toBeDisabled();
await pageForServer2.close();
});
});
test.describe('Owner rights', () => {
test('expect neither the owner nor the invitee to be able to edit the channel info (the channel info button should not be visible)', async ({
browser,
page,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.content.sendMessage('hello world');
await expect(poFederationChannelServer1.roomToolbar.btnRoomInfo).not.toBeVisible();
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await expect(poFederationChannelServer2.roomToolbar.btnRoomInfo).not.toBeVisible();
await pageForServer2.close();
});
test('expect the owner nor the invitee to be able to add users to DMs (the button to add users should not be visible)', async ({
browser,
page,
}) => {
const pageForServer2 = await browser.newPage();
const poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(usernameWithDomainFromServer2);
await poFederationChannelServer1.content.sendMessage('hello world');
await expect(poFederationChannelServer1.roomToolbar.btnMembers).not.toBeVisible();
await poFederationChannelServer2.navbar.openChat(usernameWithDomainFromServer1);
await expect(poFederationChannelServer2.roomToolbar.btnMembers).not.toBeVisible();
await pageForServer2.close();
});
});
});
});
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,367 @@
import type { Page } from '@playwright/test';
import * as constants from '../../config/constants';
import { FederationChannel } from '../../page-objects/channel';
import { doLogin } from '../../utils/auth';
import { createGroupAndInviteRemoteUserToCreateLocalUser } from '../../utils/channel';
import { formatIntoFullMatrixUsername, formatUsernameAndDomainIntoMatrixFormat } from '../../utils/format';
import { registerUser } from '../../utils/register-user';
import { test, expect, setupTesting, tearDownTesting } from '../../utils/test';
test.describe('Federation - Threads', () => {
let poFederationChannelServer1: FederationChannel;
let poFederationChannelServer2: FederationChannel;
let userFromServer2UsernameOnly: string;
let createdGroupName: string;
let usernameWithDomainFromServer2: string;
const adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
let pageForServer2: Page;
test.beforeAll(async ({ apiServer1, apiServer2, browser }) => {
await setupTesting(apiServer1);
await setupTesting(apiServer2);
userFromServer2UsernameOnly = await registerUser(apiServer2);
usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);
const page = await browser.newPage();
poFederationChannelServer1 = new FederationChannel(page);
createdGroupName = await createGroupAndInviteRemoteUserToCreateLocalUser({
page,
poFederationChannelServer: poFederationChannelServer1,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
});
});
test.afterAll(async ({ apiServer1, apiServer2 }) => {
await tearDownTesting(apiServer1);
await tearDownTesting(apiServer2);
});
test.beforeEach(async ({ page, browser }) => {
pageForServer2 = await browser.newPage();
poFederationChannelServer1 = new FederationChannel(page);
await doLogin({
page,
server: {
url: constants.RC_SERVER_1.url,
username: constants.RC_SERVER_1.username,
password: constants.RC_SERVER_1.password,
},
});
poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.addInitScript(() => {
window.localStorage.setItem('fuselage-localStorage-members-list-type', JSON.stringify('online'));
});
});
test.afterEach(async ({ page }) => {
await page.close();
await pageForServer2.close();
});
test.describe('Messaging - Threads', () => {
test.describe('Create thread message', () => {
test('expect to send a thread message from Server B to Server A', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer1.content.sendMessage('hello world from server A');
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await expect(pageForServer2).toHaveURL(/.*thread/);
await expect(poFederationChannelServer2.content.threadSendToChannelAlso()).not.toBeVisible();
await poFederationChannelServer2.content.sendThreadMessage('This is a thread message sent from server B');
await expect(poFederationChannelServer2.content.lastThreadMessageText).toContainText('This is a thread message sent from server B');
await expect(poFederationChannelServer2.content.lastUserMessage).toContainText('This is a thread message sent from server B');
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await expect(page).toHaveURL(/.*thread/);
await expect(poFederationChannelServer1.content.lastThreadMessageText).toContainText('This is a thread message sent from server B');
});
test('expect to send a thread message from Server A to Server B', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer2.content.sendMessage('hello world from server B');
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await expect(page).toHaveURL(/.*thread/);
await expect(poFederationChannelServer1.content.threadSendToChannelAlso()).not.toBeVisible();
await poFederationChannelServer1.content.sendThreadMessage('This is a thread message sent from server A');
await expect(poFederationChannelServer1.content.lastThreadMessageText).toContainText('This is a thread message sent from server A');
await expect(poFederationChannelServer1.content.lastUserMessage).toContainText('This is a thread message sent from server A');
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await expect(pageForServer2).toHaveURL(/.*thread/);
await expect(poFederationChannelServer2.content.lastThreadMessageText).toContainText('This is a thread message sent from server A');
});
});
test.describe('Send "Special" messages', () => {
test('expect to send a thread message with emojis from Server A to Server B', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer1.content.sendMessage('hello world from server A');
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await poFederationChannelServer2.content.sendThreadMessage('😀 😀 hello world 🌎 from server B with emojis 😀 😀');
await expect(poFederationChannelServer2.content.lastThreadMessageText).toContainText(
'😀 😀 hello world 🌎 from server B with emojis 😀 😀',
);
await expect(poFederationChannelServer2.content.lastUserMessage).toContainText(
'😀 😀 hello world 🌎 from server B with emojis 😀 😀',
);
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await expect(poFederationChannelServer1.content.lastThreadMessageText).toContainText(
'😀 😀 hello world 🌎 from server B with emojis 😀 😀',
);
});
test('expect to send a thread message with emojis from Server B to Server A', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer2.content.sendMessage('hello world from server B');
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await poFederationChannelServer1.content.sendThreadMessage('😀 😀 hello world 🌎 from server A with emojis 😀 😀');
await expect(poFederationChannelServer1.content.lastThreadMessageText).toContainText(
'😀 😀 hello world 🌎 from server A with emojis 😀 😀',
);
await expect(poFederationChannelServer1.content.lastUserMessage).toContainText(
'😀 😀 hello world 🌎 from server A with emojis 😀 😀',
);
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await expect(poFederationChannelServer2.content.lastThreadMessageText).toContainText(
'😀 😀 hello world 🌎 from server A with emojis 😀 😀',
);
});
test('expect to send an audio message from Server A to Server B', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer1.content.sendMessage('hello world from server A');
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await poFederationChannelServer2.content.sendAudioRecordedInThreadMessage();
await expect(
await (await poFederationChannelServer2.content.getLastFileThreadMessageByFileName('Audio record.mp3')).innerText(),
).toEqual('Audio record.mp3');
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await expect(
await (await poFederationChannelServer1.content.getLastFileThreadMessageByFileName('Audio record.mp3')).innerText(),
).toEqual('Audio record.mp3');
});
test('expect to send an audio message from Server B to Server A', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer2.content.sendMessage('hello world from server B');
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await poFederationChannelServer1.content.sendAudioRecordedInThreadMessage();
await expect(
await (await poFederationChannelServer1.content.getLastFileThreadMessageByFileName('Audio record.mp3')).innerText(),
).toEqual('Audio record.mp3');
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await expect(
await (await poFederationChannelServer2.content.getLastFileThreadMessageByFileName('Audio record.mp3')).innerText(),
).toEqual('Audio record.mp3');
});
test('expect to send a thread message mentioning an user from Server A to Server B', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer1.content.sendMessage('hello world from server A');
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await poFederationChannelServer2.content.sendThreadMessage(
`hello @${adminUsernameWithDomainFromServer1}, here's @${userFromServer2UsernameOnly} from Server B`,
);
await expect(poFederationChannelServer2.content.lastThreadMessageText).toContainText(
`hello ${adminUsernameWithDomainFromServer1}, here's ${userFromServer2UsernameOnly} from Server B`,
);
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await expect(poFederationChannelServer1.content.lastThreadMessageText).toContainText(
`hello ${constants.RC_SERVER_1.username}, here's ${usernameWithDomainFromServer2} from Server B`,
);
});
test('expect to send a thread message mentioning an user Server B to Server A', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await poFederationChannelServer2.content.sendMessage('hello world from server B');
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await poFederationChannelServer1.content.sendThreadMessage(
`hello @${usernameWithDomainFromServer2}, here's @${constants.RC_SERVER_1.username} from Server A`,
);
await expect(poFederationChannelServer1.content.lastThreadMessageText).toContainText(
`hello ${usernameWithDomainFromServer2}, here's ${constants.RC_SERVER_1.username} from Server A`,
);
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await expect(poFederationChannelServer2.content.lastThreadMessageText).toContainText(
`hello ${userFromServer2UsernameOnly}, here's ${adminUsernameWithDomainFromServer1} from Server A`,
);
});
});
test.describe('Message actions', () => {
test('expect to send a thread message quoting a thread message from Server A to Server B', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
const message = `Message for quote - ${Date.now()}`;
await poFederationChannelServer1.content.sendMessage('hello world from server A');
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await poFederationChannelServer2.content.sendThreadMessage(message);
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await poFederationChannelServer1.content.quoteMessageInsideThread('this is a quote message');
await expect(poFederationChannelServer1.content.waitForLastThreadMessageTextAttachmentEqualsText).toContainText(message);
await expect(poFederationChannelServer2.content.waitForLastThreadMessageTextAttachmentEqualsText).toContainText(message);
});
test('expect to send a thread message quoting a thread message Server B to Server A', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
const message = `Message for quote - ${Date.now()}`;
await poFederationChannelServer2.content.sendMessage('hello world from server B');
await poFederationChannelServer1.content.openLastMessageMenu();
await poFederationChannelServer1.content.btnOptionReplyInThread.click();
await poFederationChannelServer1.content.sendThreadMessage(message);
await poFederationChannelServer2.content.openLastMessageMenu();
await poFederationChannelServer2.content.btnOptionReplyInThread.click();
await poFederationChannelServer2.content.quoteMessageInsideThread('this is a quote message');
await expect(poFederationChannelServer1.content.waitForLastThreadMessageTextAttachmentEqualsText).toContainText(message);
await expect(poFederationChannelServer2.content.waitForLastThreadMessageTextAttachmentEqualsText).toContainText(message);
});
});
test.describe('Visual Elements', () => {
test('expect to see the thread list sent in the group on Server A', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdGroupName);
await expect(poFederationChannelServer1.roomToolbar.btnThreads).toBeVisible();
});
test('expect to see the thread list sent in the group on Server B', async () => {
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer2.navbar.openChat(createdGroupName);
await expect(poFederationChannelServer2.roomToolbar.btnThreads).toBeVisible();
});
});
});
});

View File

@@ -0,0 +1,130 @@
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import * as constants from '../../config/constants';
import { FederationAccountProfile } from '../../page-objects/account-profile';
import { FederationChannel } from '../../page-objects/channel';
import { doLogin } from '../../utils/auth';
import { createChannelAndInviteRemoteUserToCreateLocalUser } from '../../utils/channel';
import { formatIntoFullMatrixUsername, formatUsernameAndDomainIntoMatrixFormat } from '../../utils/format';
import { registerUser } from '../../utils/register-user';
import { test, expect, setupTesting, tearDownTesting } from '../../utils/test';
test.describe.parallel('Federation - User Account Pannel', () => {
let poFederationChannelServer1: FederationChannel;
let poFederationChannelServer2: FederationChannel;
let poFederationAccountProfileServer1: FederationAccountProfile;
let userFromServer2UsernameOnly: string;
let createdChannelName: string;
let pageForServer2: Page;
let usernameWithDomainFromServer2: string;
const adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(
constants.RC_SERVER_1.username,
constants.RC_SERVER_1.matrixServerName,
);
test.beforeAll(async ({ apiServer1, apiServer2, browser }) => {
await setupTesting(apiServer1);
await setupTesting(apiServer2);
userFromServer2UsernameOnly = await registerUser(apiServer2);
const page = await browser.newPage();
poFederationChannelServer1 = new FederationChannel(page);
usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(
userFromServer2UsernameOnly,
constants.RC_SERVER_2.matrixServerName,
);
const fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);
createdChannelName = await createChannelAndInviteRemoteUserToCreateLocalUser({
page,
poFederationChannelServer: poFederationChannelServer1,
fullUsernameFromServer: fullUsernameFromServer2,
server: constants.RC_SERVER_1,
});
});
test.afterAll(async ({ apiServer1, apiServer2 }) => {
await tearDownTesting(apiServer1);
await tearDownTesting(apiServer2);
});
test.beforeEach(async ({ browser, page }) => {
pageForServer2 = await browser.newPage();
poFederationAccountProfileServer1 = new FederationAccountProfile(page);
poFederationChannelServer1 = new FederationChannel(page);
await doLogin({
page,
server: {
url: constants.RC_SERVER_1.url,
username: constants.RC_SERVER_1.username,
password: constants.RC_SERVER_1.password,
},
});
poFederationChannelServer2 = new FederationChannel(pageForServer2);
await doLogin({
page: pageForServer2,
server: {
url: constants.RC_SERVER_2.url,
username: userFromServer2UsernameOnly,
password: constants.RC_SERVER_2.password,
},
storeState: false,
});
await page.addInitScript(() => {
window.localStorage.setItem('fuselage-localStorage-members-list-type', JSON.stringify('online'));
});
});
test.afterEach(async ({ page }) => {
await poFederationChannelServer1.navbar.logout();
await page.close();
});
test('expect to be able to edit a name in Server A and it must be reflected on Server B', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const newName = faker.person.fullName();
await page.goto(`${constants.RC_SERVER_1.url}/account/profile`);
await poFederationAccountProfileServer1.inputName.fill(newName);
await poFederationAccountProfileServer1.btnSubmit.click();
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdChannelName);
await poFederationChannelServer2.navbar.openChat(createdChannelName);
await poFederationChannelServer2.roomToolbar.openMembersTab();
await poFederationChannelServer2.tabs.members.showAllUsers();
await expect(poFederationChannelServer2.tabs.members.getUserInList(adminUsernameWithDomainFromServer1)).toContainText(newName);
await pageForServer2.close();
});
test('expect to be able to edit a name in Server B and it must be reflected on Server A', async ({ page }) => {
await page.goto(`${constants.RC_SERVER_1.url}/home`);
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
const poFederationAccountProfileServer2 = new FederationAccountProfile(pageForServer2);
const newName = faker.person.fullName();
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/account/profile`);
await poFederationAccountProfileServer2.inputName.fill(newName);
await poFederationAccountProfileServer2.btnSubmit.click();
await pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);
await poFederationChannelServer1.navbar.openChat(createdChannelName);
await poFederationChannelServer2.navbar.openChat(createdChannelName);
await poFederationChannelServer1.roomToolbar.openMembersTab();
await poFederationChannelServer1.tabs.members.showAllUsers();
await expect(poFederationChannelServer1.tabs.members.getUserInList(usernameWithDomainFromServer2)).toContainText(newName);
await pageForServer2.close();
});
});

View File

@@ -0,0 +1,28 @@
import type { Page } from '@playwright/test';
export const doLogin = async ({
page,
server,
storageNamePrefix,
storeState,
}: {
page: Page;
server: {
username: string;
password: string;
url: string;
};
storageNamePrefix?: string;
storeState?: boolean;
}) => {
await page.goto(`${server.url}/login`);
await page.locator('role=textbox[name=/username/i]').type(server.username);
await page.locator('[name=password]').type(server.password);
await page.locator('role=button[name="Login"]').click();
await page.waitForTimeout(1000);
if (storeState) {
await page.context().storageState({ path: `${storageNamePrefix}-session.json` });
}
};

View File

@@ -0,0 +1,85 @@
import { faker } from '@faker-js/faker';
import type { Page } from '@playwright/test';
import { doLogin } from './auth';
import type { API } from './test';
import type { FederationChannel } from '../page-objects/channel';
const doLoginAndGoToHome = async (
page: Page,
server: {
url: string;
username: string;
password: string;
},
): Promise<void> => {
await doLogin({
page,
server,
});
await page.goto(`${server.url}/home`);
};
export const createChannelAndInviteRemoteUserToCreateLocalUser = async ({
page,
poFederationChannelServer,
fullUsernameFromServer,
server,
closePageAfterCreation = true,
}: {
page: Page;
poFederationChannelServer: FederationChannel;
fullUsernameFromServer: string;
server: {
url: string;
username: string;
password: string;
};
closePageAfterCreation?: boolean;
}): Promise<string> => {
const channelName = faker.string.uuid();
await doLoginAndGoToHome(page, server);
await poFederationChannelServer.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [fullUsernameFromServer]);
if (closePageAfterCreation) {
await page.close();
}
return channelName;
};
export const createGroupAndInviteRemoteUserToCreateLocalUser = async ({
page,
poFederationChannelServer,
fullUsernameFromServer,
server,
}: {
page: Page;
poFederationChannelServer: FederationChannel;
fullUsernameFromServer: string;
server: {
url: string;
username: string;
password: string;
matrixServerName: string;
};
}): Promise<string> => {
const groupName = faker.string.uuid();
await doLoginAndGoToHome(page, server);
await poFederationChannelServer.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [fullUsernameFromServer]);
await page.close();
return groupName;
};
export const createGroupUsingAPI = async (api: API, name: string) => {
await api.post('/groups.create', { name });
};
export const createChannelUsingAPI = async (api: API, name: string) => {
await api.post('/channels.create', { name });
};

View File

@@ -0,0 +1,4 @@
export const formatUsernameAndDomainIntoMatrixFormat = (username: string, domain: string): string => `${username}:${domain}`;
export const formatIntoFullMatrixUsername = (username: string, domain: string): string =>
`@${formatUsernameAndDomainIntoMatrixFormat(username, domain)}`;

View File

@@ -0,0 +1,17 @@
import { faker } from '@faker-js/faker';
import type { API } from './test';
import * as constants from '../config/constants';
export async function registerUser(api: API): Promise<string> {
const username = faker.string.uuid();
await api.post('/users.register', {
username,
email: `${username}@test-rc.com`,
pass: constants.RC_SERVER_2.password,
name: username,
});
return username;
}

View File

@@ -0,0 +1,84 @@
/* eslint-disable react-hooks/rules-of-hooks */
import type { APIResponse } from '@playwright/test';
import { test as baseTest } from '@playwright/test';
import { API_PREFIX } from '../../config/constants';
import * as constants from '../config/constants';
export type AnyObj = { [key: string]: any };
export type API = {
get(uri: string, prefix?: string): Promise<APIResponse>;
post(uri: string, data: AnyObj, prefix?: string): Promise<APIResponse>;
put(uri: string, data: AnyObj, prefix?: string): Promise<APIResponse>;
delete(uri: string, prefix?: string): Promise<APIResponse>;
};
export type BaseTest = {
apiServer1: API;
apiServer2: API;
};
const api = async (request: any, use: any, user: string, password: string, baseUrl: string) => {
const resp = await request.post(`${baseUrl + API_PREFIX}/login`, { data: { user, password } });
const json = await resp.json();
const headers = {
'X-Auth-Token': json.data.authToken,
'X-User-Id': json.data.userId,
};
await use({
get(uri: string, prefix = API_PREFIX) {
return request.get(baseUrl + prefix + uri, { headers });
},
post(uri: string, data: AnyObj, prefix = API_PREFIX) {
return request.post(baseUrl + prefix + uri, { headers, data });
},
put(uri: string, data: AnyObj, prefix = API_PREFIX) {
return request.put(baseUrl + prefix + uri, { headers, data });
},
delete(uri: string, prefix = API_PREFIX) {
return request.delete(baseUrl + prefix + uri, { headers });
},
});
};
export const test = baseTest.extend<BaseTest>({
apiServer1: async ({ request }, use) =>
api(request, use, constants.RC_SERVER_1.username, constants.RC_SERVER_1.password, constants.RC_SERVER_1.url),
apiServer2: async ({ request }, use) =>
api(request, use, constants.RC_SERVER_2.username, constants.RC_SERVER_2.password, constants.RC_SERVER_2.url),
});
export const { expect } = test;
export const setupTesting = async (api: API) => {
await api.post('/settings/Message_AudioRecorderEnabled', { value: true });
await api.post('/settings/Accounts_ManuallyApproveNewUsers', { value: false });
await api.post('/settings/API_Enable_Rate_Limiter', { value: false });
await api.post('/settings/DDP_Rate_Limit_IP_Enabled', { value: false });
await api.post('/settings/DDP_Rate_Limit_User_Enabled', { value: false });
await api.post('/settings/DDP_Rate_Limit_Connection_Enabled', { value: false });
await api.post('/settings/DDP_Rate_Limit_Connection_Interval_Time', { value: false });
await api.post('/settings/DDP_Rate_Limit_User_By_Method_Enabled', { value: false });
await api.post('/settings/DDP_Rate_Limit_Connection_By_Method_Enabled', { value: false });
await api.post('/settings/Accounts_RegistrationForm', { value: 'Public' });
await api.post('/settings/UI_Use_Real_Name', { value: false });
await api.post('/settings/Rate_Limiter_Limit_RegisterUser', { value: 10 });
await api.post('/settings/Hide_System_Messages', { value: [] });
await api.post('/permissions.update', { permissions: [{ _id: 'force-delete-message', roles: ['admin', 'user'] }] });
};
export const tearDownTesting = async (api: API) => {
await api.post('/settings/Accounts_ManuallyApproveNewUsers', { value: true });
await api.post('/settings/API_Enable_Rate_Limiter', { value: true });
await api.post('/settings/DDP_Rate_Limit_IP_Enabled', { value: true });
await api.post('/settings/DDP_Rate_Limit_User_Enabled', { value: true });
await api.post('/settings/DDP_Rate_Limit_Connection_Enabled', { value: true });
await api.post('/settings/DDP_Rate_Limit_Connection_Interval_Time', { value: true });
await api.post('/settings/DDP_Rate_Limit_User_By_Method_Enabled', { value: true });
await api.post('/settings/DDP_Rate_Limit_Connection_By_Method_Enabled', { value: true });
await api.post('/settings/Rate_Limiter_Limit_RegisterUser', { value: 1 });
await api.post('/settings/Accounts_RegistrationForm', { value: 'Disabled' });
};