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
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:
@@ -0,0 +1,49 @@
|
||||
import type { Locator } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class EditAdminRoomFlexTab extends FlexTab {
|
||||
constructor(locator: Locator) {
|
||||
super(locator);
|
||||
}
|
||||
|
||||
get roomNameInput(): Locator {
|
||||
return this.root.locator('input[name="roomName"]');
|
||||
}
|
||||
|
||||
get privateLabel(): Locator {
|
||||
return this.root.locator(`label >> text=Private`);
|
||||
}
|
||||
|
||||
get privateInput(): Locator {
|
||||
return this.root.locator('input[name="roomType"]');
|
||||
}
|
||||
|
||||
get roomOwnerInput(): Locator {
|
||||
return this.root.locator('input[name="roomOwner"]');
|
||||
}
|
||||
|
||||
get archivedLabel(): Locator {
|
||||
return this.root.locator('label >> text=Archived');
|
||||
}
|
||||
|
||||
get archivedInput(): Locator {
|
||||
return this.root.locator('input[name="archived"]');
|
||||
}
|
||||
|
||||
get favoriteLabel(): Locator {
|
||||
return this.root.locator('label >> text=Favorite');
|
||||
}
|
||||
|
||||
get favoriteInput(): Locator {
|
||||
return this.root.locator('input[name="favorite"]');
|
||||
}
|
||||
|
||||
get defaultLabel(): Locator {
|
||||
return this.root.locator('label >> text=Default');
|
||||
}
|
||||
|
||||
get defaultInput(): Locator {
|
||||
return this.root.locator('input[name="isDefault"]');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class AddEmojiFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Add New Emoji' }));
|
||||
}
|
||||
}
|
||||
|
||||
export class EditEmojiFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Custom Emoji Info' }));
|
||||
}
|
||||
|
||||
async delete() {
|
||||
await this.btnDelete.click();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class AutoTranslateFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Auto-Translate' }));
|
||||
}
|
||||
|
||||
get checkboxAutomaticTranslation(): Locator {
|
||||
return this.root.getByRole('checkbox', { name: 'Automatic Translation' });
|
||||
}
|
||||
|
||||
get textAutomaticTranslation(): Locator {
|
||||
return this.root.getByText('Automatic Translation', { exact: true });
|
||||
}
|
||||
|
||||
get textEncryptedRoomCallout(): Locator {
|
||||
return this.root.getByText('Automatic translation not available');
|
||||
}
|
||||
|
||||
async setAutomaticTranslation(enabled: boolean): Promise<void> {
|
||||
if ((await this.checkboxAutomaticTranslation.isChecked()) === enabled) {
|
||||
return;
|
||||
}
|
||||
await this.textAutomaticTranslation.click();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { Listbox } from '../listbox';
|
||||
import { ConfirmDeleteRoomModal, ConfirmRemoveModal } from '../modals';
|
||||
import { Modal } from '../modals/modal';
|
||||
|
||||
class AddExistingChannelModal extends Modal {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Add Existing Channels' }));
|
||||
}
|
||||
|
||||
get inputChannels(): Locator {
|
||||
return this.root.getByRole('textbox');
|
||||
}
|
||||
|
||||
get btnAdd(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Add', exact: true });
|
||||
}
|
||||
|
||||
async confirmAdd() {
|
||||
await this.btnAdd.click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
export class ChannelsFlexTab extends FlexTab {
|
||||
readonly confirmRemoveModal: ConfirmRemoveModal;
|
||||
|
||||
readonly confirmDeleteModal: ConfirmDeleteRoomModal;
|
||||
|
||||
readonly addExistingChannelModal: AddExistingChannelModal;
|
||||
|
||||
readonly listbox: Listbox;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Team Channels' }));
|
||||
this.confirmRemoveModal = new ConfirmRemoveModal(page.getByRole('dialog', { name: 'Are you sure?' }));
|
||||
this.confirmDeleteModal = new ConfirmDeleteRoomModal(page);
|
||||
this.addExistingChannelModal = new AddExistingChannelModal(page);
|
||||
this.listbox = new Listbox(page);
|
||||
}
|
||||
|
||||
get btnAddExisting(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Add Existing', exact: true });
|
||||
}
|
||||
|
||||
get btnCreateNew(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Create new', exact: true });
|
||||
}
|
||||
|
||||
get channelsList(): Locator {
|
||||
return this.root.getByRole('list');
|
||||
}
|
||||
|
||||
getListboxOption(name: string): Locator {
|
||||
return this.listbox.getOption(name);
|
||||
}
|
||||
|
||||
channelOption(name: string) {
|
||||
return this.root.locator('li', { hasText: name });
|
||||
}
|
||||
|
||||
async openChannelOptionMoreActions(name: string) {
|
||||
await this.channelOption(name).hover();
|
||||
await this.channelOption(name).getByRole('button', { name: 'More' }).click();
|
||||
}
|
||||
|
||||
async confirmRemoveChannel() {
|
||||
return this.confirmRemoveModal.confirmRemove();
|
||||
}
|
||||
|
||||
async confirmDeleteRoom() {
|
||||
return this.confirmDeleteModal.confirmDelete();
|
||||
}
|
||||
|
||||
async addExistingChannel(name: string) {
|
||||
await this.btnAddExisting.click();
|
||||
await this.addExistingChannelModal.inputChannels.fill(name);
|
||||
await this.listbox.selectOption(name);
|
||||
await this.addExistingChannelModal.confirmAdd();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { Locator } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class DeviceInfoFlexTab extends FlexTab {
|
||||
constructor(locator: Locator) {
|
||||
super(locator);
|
||||
}
|
||||
|
||||
get btnLogoutDevice(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Log out device' });
|
||||
}
|
||||
|
||||
getDeviceInfoId(deviceId: string): Locator {
|
||||
return this.root.getByText(deviceId, { exact: true });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class OmnichannelEditContactFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'contact' }));
|
||||
}
|
||||
|
||||
get inputEmail(): Locator {
|
||||
return this.root.locator('input[name="emails.0.address"]');
|
||||
}
|
||||
|
||||
get inputPhone(): Locator {
|
||||
return this.root.locator('input[name="phones.0.phoneNumber"]');
|
||||
}
|
||||
|
||||
get inputContactManager(): Locator {
|
||||
return this.root.locator('input[name=contactManager]');
|
||||
}
|
||||
|
||||
get btnAddEmail(): Locator {
|
||||
return this.root.locator('role=button[name="Add email"]');
|
||||
}
|
||||
|
||||
get btnAddPhone(): Locator {
|
||||
return this.root.locator('role=button[name="Add phone"]');
|
||||
}
|
||||
|
||||
getErrorMessage(message: string): Locator {
|
||||
return this.root.locator(`role=alert >> text="${message}"`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { Listbox } from '../listbox';
|
||||
|
||||
export class EditRoomFlexTab extends FlexTab {
|
||||
constructor(locator: Locator) {
|
||||
super(locator);
|
||||
}
|
||||
|
||||
get inputTopic(): Locator {
|
||||
return this.root.getByRole('textbox', { name: 'Topic' });
|
||||
}
|
||||
|
||||
get inputAnnouncement(): Locator {
|
||||
return this.root.getByRole('textbox', { name: 'Announcement' });
|
||||
}
|
||||
|
||||
get inputDescription(): Locator {
|
||||
return this.root.getByRole('textbox', { name: 'Description' });
|
||||
}
|
||||
|
||||
get checkboxReadOnly(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Read-only' });
|
||||
}
|
||||
|
||||
get calloutRetentionPolicy(): Locator {
|
||||
return this.root.getByRole('alert', { name: 'Retention policy warning callout' });
|
||||
}
|
||||
|
||||
get advancedSettingsAccordion(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Advanced settings' });
|
||||
}
|
||||
|
||||
get pruneAccordion(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Prune', exact: true });
|
||||
}
|
||||
|
||||
getMaxAgeLabel(maxAge = '30') {
|
||||
return this.root.getByText(`Maximum message age in days (default: ${maxAge})`);
|
||||
}
|
||||
|
||||
get inputRetentionMaxAge(): Locator {
|
||||
return this.root.locator('input[name="retentionMaxAge"]');
|
||||
}
|
||||
|
||||
get checkboxPruneMessages(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Automatically prune old messages' });
|
||||
}
|
||||
|
||||
get checkboxOverrideGlobalRetention(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Override global retention policy' });
|
||||
}
|
||||
|
||||
get checkboxIgnoreThreads(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Do not prune Threads' });
|
||||
}
|
||||
|
||||
get checkboxChannels(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Channels' });
|
||||
}
|
||||
|
||||
get checkboxDiscussions(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Discussions' });
|
||||
}
|
||||
|
||||
async toggleSidepanelItems() {
|
||||
await this.checkboxChannels.click();
|
||||
await this.checkboxDiscussions.click();
|
||||
}
|
||||
}
|
||||
|
||||
export class EditTeamFlexTab extends EditRoomFlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Edit team' }));
|
||||
}
|
||||
}
|
||||
|
||||
export class OmnichannelEditRoomFlexTab extends EditRoomFlexTab {
|
||||
private readonly tagsListbox: Listbox;
|
||||
|
||||
private readonly slaListbox: Listbox;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Edit Room' }));
|
||||
this.tagsListbox = new Listbox(page);
|
||||
this.slaListbox = new Listbox(page, 'SLA Policy');
|
||||
}
|
||||
|
||||
get inputSLAPolicy(): Locator {
|
||||
return this.root.getByRole('button', { name: 'SLA Policy', exact: true });
|
||||
}
|
||||
|
||||
optionTag(name: string): Locator {
|
||||
return this.tagsListbox.getOption(name);
|
||||
}
|
||||
|
||||
async selectTag(name: string) {
|
||||
await this.tagsListbox.selectOption(name);
|
||||
}
|
||||
|
||||
async selectSLA(name: string) {
|
||||
await this.inputSLAPolicy.click();
|
||||
await this.slaListbox.selectOption(name, true);
|
||||
}
|
||||
|
||||
get inputTags(): Locator {
|
||||
return this.root.getByRole('textbox', { name: 'Select an option' });
|
||||
}
|
||||
|
||||
getRoomCustomField(label: string): Locator {
|
||||
return this.root.getByRole('group', { name: 'Custom Fields' }).getByLabel(label);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class EditUserFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog'));
|
||||
}
|
||||
|
||||
get btnAddUser(): Locator {
|
||||
return this.root.locator('role=button[name="Add user"]');
|
||||
}
|
||||
|
||||
get btnSaveUser(): Locator {
|
||||
return this.root.locator('role=button[name="Save user"]');
|
||||
}
|
||||
|
||||
get inputUserName(): Locator {
|
||||
return this.root.getByRole('textbox', { name: 'Username', exact: true });
|
||||
}
|
||||
|
||||
get inputEmail(): Locator {
|
||||
return this.root.getByRole('textbox', { name: 'Email', exact: true });
|
||||
}
|
||||
|
||||
get inputSetManually(): Locator {
|
||||
return this.root.locator('//label[text()="Set manually"]');
|
||||
}
|
||||
|
||||
get inputPassword(): Locator {
|
||||
return this.root.getByPlaceholder('Password', { exact: true });
|
||||
}
|
||||
|
||||
get inputConfirmPassword(): Locator {
|
||||
return this.root.getByPlaceholder('Confirm password', { exact: true });
|
||||
}
|
||||
|
||||
get joinDefaultChannels(): Locator {
|
||||
return this.root.locator('//label[text()="Join default channels"]');
|
||||
}
|
||||
|
||||
get chipUserRole(): Locator {
|
||||
return this.root.getByRole('button', { name: 'user', exact: true });
|
||||
}
|
||||
|
||||
get setupSmtpLink(): Locator {
|
||||
return this.root.getByRole('link', { name: 'Set up SMTP' });
|
||||
}
|
||||
|
||||
getCustomField(fieldName: string): Locator {
|
||||
return this.root.getByRole('textbox', { name: fieldName, exact: true });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class ExportMessagesFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Export Messages' }));
|
||||
}
|
||||
|
||||
async exposeMethods() {
|
||||
await this.method.click();
|
||||
}
|
||||
|
||||
async setMethod(optionName: string) {
|
||||
await this.exposeMethods();
|
||||
await this.root.page().getByRole('option', { name: optionName }).click();
|
||||
}
|
||||
|
||||
async exposeOutputFormats() {
|
||||
await this.outputFormat.click();
|
||||
}
|
||||
|
||||
async setOutputFormat(optionName: string) {
|
||||
await this.exposeOutputFormats();
|
||||
await this.root.page().getByRole('option', { name: optionName }).click();
|
||||
}
|
||||
|
||||
getMethodOptionByName(name: string) {
|
||||
return this.root.page().getByRole('option', { name });
|
||||
}
|
||||
|
||||
getOutputFormatOptionByName(name: string) {
|
||||
return this.root.page().getByRole('option', { name });
|
||||
}
|
||||
|
||||
async selectAllMessages() {
|
||||
await this.root
|
||||
.page()
|
||||
.getByRole('button', { name: /Select \d+ messages/ })
|
||||
.click();
|
||||
}
|
||||
|
||||
async downloadMessages() {
|
||||
const [download] = await Promise.all([this.root.page().waitForEvent('download'), this.downloadButton.click()]);
|
||||
return download;
|
||||
}
|
||||
|
||||
async send() {
|
||||
await this.sendButton.click();
|
||||
}
|
||||
|
||||
async setAdditionalEmail(email: string) {
|
||||
await this.inputAdditionalEmails.fill(email);
|
||||
}
|
||||
|
||||
getMessageCheckbox(messageText: string): Locator {
|
||||
return this.root.page().getByRole('listitem').filter({ hasText: messageText }).getByRole('checkbox');
|
||||
}
|
||||
|
||||
get inputUsers() {
|
||||
return this.root.getByRole('combobox', { name: 'To users' });
|
||||
}
|
||||
|
||||
get inputAdditionalEmails() {
|
||||
return this.root.getByRole('textbox', { name: 'To additional emails' });
|
||||
}
|
||||
|
||||
get method() {
|
||||
return this.root.getByTestId('export-messages-method');
|
||||
}
|
||||
|
||||
get outputFormat() {
|
||||
return this.root.page().getByTestId('export-messages-output-format');
|
||||
}
|
||||
|
||||
get downloadButton() {
|
||||
return this.root.getByRole('button', { name: 'Download', exact: true });
|
||||
}
|
||||
|
||||
get sendButton() {
|
||||
return this.root.getByRole('button', { name: 'Send', exact: true });
|
||||
}
|
||||
|
||||
get clearSelectionButton() {
|
||||
return this.root.page().getByRole('button', { name: 'Clear selection' });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { MenuMore } from '../menu';
|
||||
import { ConfirmDeleteModal } from '../modals';
|
||||
|
||||
export class FilesFlexTab extends FlexTab {
|
||||
readonly menu: MenuMore;
|
||||
|
||||
readonly confirmDeleteModal: ConfirmDeleteModal;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Files' }));
|
||||
this.menu = new MenuMore(page);
|
||||
this.confirmDeleteModal = new ConfirmDeleteModal(page.getByRole('dialog', { name: 'Are you sure?' }));
|
||||
}
|
||||
|
||||
get fileList() {
|
||||
return this.root.getByRole('list', { name: 'Files list' });
|
||||
}
|
||||
|
||||
getFileByName(name: string) {
|
||||
return this.fileList.getByRole('listitem').filter({ hasText: name });
|
||||
}
|
||||
|
||||
async deleteFile(name: string) {
|
||||
await this.getFileByName(name).getByRole('button', { name: 'More' }).click();
|
||||
await this.menu.selectMenuItem('Delete');
|
||||
await this.confirmDeleteModal.confirmDelete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import type { Locator } from '@playwright/test';
|
||||
|
||||
import { expect } from '../../../utils/test';
|
||||
|
||||
export abstract class FlexTab {
|
||||
/**
|
||||
* @param root should be protected, but for now there are a lot of tests relying on accessing it directly, * so we need to keep it public until we can refactor those tests
|
||||
*/
|
||||
constructor(public root: Locator) {}
|
||||
|
||||
waitForDisplay() {
|
||||
return expect(this.root).toBeVisible();
|
||||
}
|
||||
|
||||
waitForDismissal() {
|
||||
return expect(this.root).not.toBeVisible();
|
||||
}
|
||||
|
||||
private get btnClose() {
|
||||
return this.root.getByRole('button', { name: 'Close', exact: true });
|
||||
}
|
||||
|
||||
get inputName() {
|
||||
return this.root.getByRole('textbox', { name: 'Name', exact: true });
|
||||
}
|
||||
|
||||
get btnSave() {
|
||||
return this.root.getByRole('button', { name: 'Save', exact: true });
|
||||
}
|
||||
|
||||
get btnCancel() {
|
||||
return this.root.getByRole('button', { name: 'Cancel', exact: true });
|
||||
}
|
||||
|
||||
get btnDelete() {
|
||||
return this.root.getByRole('button', { name: 'Delete', exact: true });
|
||||
}
|
||||
|
||||
get btnReset() {
|
||||
return this.root.getByRole('button', { name: 'Reset', exact: true });
|
||||
}
|
||||
|
||||
errorMessage(message: string): Locator {
|
||||
return this.root.locator('[role="alert"]', { hasText: message });
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.btnClose.click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
|
||||
async save() {
|
||||
await this.btnSave.click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export * from './auto-translate-flextab';
|
||||
export * from './admin-flextab-emoji';
|
||||
export * from './admin-edit-room-flextab';
|
||||
export * from './channels-flextab';
|
||||
export * from './device-info-flextab';
|
||||
export * from './edit-room-flextab';
|
||||
export * from './edit-user-flextab';
|
||||
export * from './edit-contact-flextab';
|
||||
export * from './export-messages-flextab';
|
||||
export * from './files-flextab';
|
||||
export * from './members-flextab';
|
||||
export * from './notification-preferences-flextab';
|
||||
export * from './prune-messages-flextab';
|
||||
export * from './room-info-flextab';
|
||||
export * from './threads-flextab';
|
||||
export * from './search-messages-flextab';
|
||||
export * from './user-info-flextab';
|
||||
@@ -0,0 +1,179 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { Listbox } from '../listbox';
|
||||
import { MenuMore } from '../menu';
|
||||
import { ConfirmRemoveModal } from '../modals';
|
||||
import { UserInfoFlexTab } from './user-info-flextab';
|
||||
import { Modal } from '../modals/modal';
|
||||
|
||||
export class ConfirmMuteModal extends Modal {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Are you sure' }));
|
||||
}
|
||||
|
||||
private get btnMute() {
|
||||
return this.root.getByRole('button', { name: 'Yes, mute user!' });
|
||||
}
|
||||
|
||||
async confirmMute() {
|
||||
await this.btnMute.click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveTeamMemberModal extends Modal {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Removing Member' }));
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this.root.getByText('Select the channels you want the user to be removed from');
|
||||
}
|
||||
|
||||
channel(channelName: string) {
|
||||
return this.root.getByText(channelName);
|
||||
}
|
||||
|
||||
channelCheckbox(channelName: string) {
|
||||
return this.root.getByRole('row', { name: channelName }).getByRole('checkbox');
|
||||
}
|
||||
|
||||
async selectChannel(channelName: string) {
|
||||
await this.channel(channelName).click();
|
||||
}
|
||||
|
||||
private get btnContinue() {
|
||||
return this.root.getByRole('button', { name: 'Continue' });
|
||||
}
|
||||
|
||||
async continue() {
|
||||
await this.btnContinue.click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
class AddUsersFlexTab extends FlexTab {
|
||||
readonly listbox: Listbox;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Add users' }));
|
||||
this.listbox = new Listbox(page);
|
||||
}
|
||||
|
||||
private btnAddUsers() {
|
||||
return this.root.getByRole('button', { name: 'Add users' });
|
||||
}
|
||||
|
||||
async addUser(username: string) {
|
||||
await this.root.getByRole('combobox', { name: 'Choose users' }).pressSequentially(username);
|
||||
await this.listbox.selectOption(username);
|
||||
await this.btnAddUsers().click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
export class MembersFlexTab extends FlexTab {
|
||||
readonly listbox: Listbox;
|
||||
|
||||
readonly removeModal: ConfirmRemoveModal;
|
||||
|
||||
readonly removeTeamMemberModal: RemoveTeamMemberModal;
|
||||
|
||||
readonly menu: MenuMore;
|
||||
|
||||
readonly confirmMuteModal: ConfirmMuteModal;
|
||||
|
||||
readonly addUsersFlexTab: AddUsersFlexTab;
|
||||
|
||||
readonly userInfo: UserInfoFlexTab;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Members' }));
|
||||
this.removeModal = new ConfirmRemoveModal(page.getByRole('dialog', { name: 'Confirmation', exact: true }));
|
||||
this.removeTeamMemberModal = new RemoveTeamMemberModal(page);
|
||||
this.listbox = new Listbox(page);
|
||||
this.menu = new MenuMore(page);
|
||||
this.confirmMuteModal = new ConfirmMuteModal(page);
|
||||
this.addUsersFlexTab = new AddUsersFlexTab(page);
|
||||
this.userInfo = new UserInfoFlexTab(page);
|
||||
}
|
||||
|
||||
memberOption(username: string) {
|
||||
return this.root.locator('li', { hasText: username });
|
||||
}
|
||||
|
||||
getMenuItemAction(action: string) {
|
||||
return this.menu.getMenuItem(action);
|
||||
}
|
||||
|
||||
async openMemberInfo(username: string) {
|
||||
await this.memberOption(username).click();
|
||||
}
|
||||
|
||||
async openMoreActions() {
|
||||
await this.root.getByRole('button', { name: 'More' }).click();
|
||||
}
|
||||
|
||||
async openMemberOptionMoreActions(username: string) {
|
||||
await this.memberOption(username).hover();
|
||||
await this.memberOption(username).getByRole('button', { name: 'More' }).click();
|
||||
}
|
||||
|
||||
async addUser(username: string) {
|
||||
await this.root.getByRole('button', { name: 'Add' }).click();
|
||||
await this.addUsersFlexTab.addUser(username);
|
||||
}
|
||||
|
||||
private get btnInviteLink() {
|
||||
return this.root.getByRole('button', { name: 'Invite Link' });
|
||||
}
|
||||
|
||||
async inviteUser() {
|
||||
await this.btnInviteLink.click();
|
||||
}
|
||||
|
||||
async muteUser(username: string) {
|
||||
await this.openMemberOptionMoreActions(username);
|
||||
await this.menu.selectMenuItem('Mute user');
|
||||
await this.confirmMuteModal.confirmMute();
|
||||
}
|
||||
|
||||
async unmuteUser(username: string) {
|
||||
await this.openMemberOptionMoreActions(username);
|
||||
await this.menu.selectMenuItem('Unmute user');
|
||||
}
|
||||
|
||||
async setUserAsModerator(username: string) {
|
||||
await this.openMemberOptionMoreActions(username);
|
||||
await this.menu.selectMenuItem('Set as moderator');
|
||||
}
|
||||
|
||||
async setUserAsOwner(username: string) {
|
||||
await this.openMemberOptionMoreActions(username);
|
||||
await this.menu.selectMenuItem('Set as owner');
|
||||
}
|
||||
|
||||
async showAllUsers() {
|
||||
await this.root.getByRole('button', { name: 'Online' }).click();
|
||||
await this.listbox.selectOption('All');
|
||||
}
|
||||
|
||||
private async ignoreUserAction(action: string, username: string) {
|
||||
await this.openMemberInfo(username);
|
||||
await this.userInfo.openMoreActions();
|
||||
await this.userInfo.menu.selectMenuItem(action);
|
||||
}
|
||||
|
||||
async ignoreUser(username: string) {
|
||||
await this.ignoreUserAction('Ignore', username);
|
||||
}
|
||||
|
||||
async unignoreUser(username: string) {
|
||||
await this.ignoreUserAction('Unignore', username);
|
||||
}
|
||||
|
||||
async confirmRemoveUser() {
|
||||
return this.removeModal.confirmRemove();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { Listbox } from '../listbox';
|
||||
|
||||
export class NotificationPreferencesFlexTab extends FlexTab {
|
||||
readonly listbox: Listbox;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Notifications Preferences' }));
|
||||
this.listbox = new Listbox(page);
|
||||
}
|
||||
|
||||
getPreferenceByDevice(device: string): Locator {
|
||||
return this.root.locator(`//div[@id="${device}Alert"]`);
|
||||
}
|
||||
|
||||
async selectDropdownById(text: string): Promise<void> {
|
||||
await this.root.locator(`//div[@id="${text}"]`).click();
|
||||
}
|
||||
|
||||
async selectOptionByLabel(text: string): Promise<void> {
|
||||
await this.listbox.selectOption(text);
|
||||
}
|
||||
|
||||
async selectDevice(text: string): Promise<void> {
|
||||
await this.root.getByRole('button', { name: text }).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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { Modal } from '../modals/modal';
|
||||
|
||||
class ConfirmPruneMessageModal extends Modal {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Are you sure?' }));
|
||||
}
|
||||
|
||||
async pruneConfirm(): Promise<void> {
|
||||
await this.root.getByRole('button', { name: 'Yes, prune them!' }).click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
export class PruneMessagesFlexTab extends FlexTab {
|
||||
readonly confirmPruneModal: ConfirmPruneMessageModal;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Prune Messages' }));
|
||||
this.confirmPruneModal = new ConfirmPruneMessageModal(page);
|
||||
}
|
||||
|
||||
get labelDoNotPrunePinned(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Do not prune pinned messages' });
|
||||
}
|
||||
|
||||
get labelFilesOnly(): Locator {
|
||||
return this.root.locator('label', { hasText: 'Only remove the attached files, keep messages' });
|
||||
}
|
||||
|
||||
async prune(): Promise<void> {
|
||||
await this.root.getByRole('button', { name: 'Prune' }).click();
|
||||
await this.confirmPruneModal.pruneConfirm();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { MenuMore } from '../menu';
|
||||
import { ConfirmDeleteTeamModal, ConfirmDeleteRoomModal } from '../modals';
|
||||
import { Modal } from '../modals/modal';
|
||||
|
||||
class ConfirmLeaveRoomModal extends Modal {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Confirmation', exact: true }));
|
||||
}
|
||||
|
||||
private get btnLeave() {
|
||||
return this.root.getByRole('button', { name: 'Leave', exact: true });
|
||||
}
|
||||
|
||||
async confirmLeave() {
|
||||
await this.btnLeave.click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
export class RoomInfoFlexTab extends FlexTab {
|
||||
readonly menu: MenuMore;
|
||||
|
||||
readonly confirmLeaveModal: ConfirmLeaveRoomModal;
|
||||
|
||||
readonly confirmDeleteModal: ConfirmDeleteRoomModal;
|
||||
|
||||
constructor(root: Locator) {
|
||||
super(root);
|
||||
this.menu = new MenuMore(root.page());
|
||||
this.confirmLeaveModal = new ConfirmLeaveRoomModal(root.page());
|
||||
this.confirmDeleteModal = new ConfirmDeleteRoomModal(root.page());
|
||||
}
|
||||
|
||||
get btnEdit(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Edit' });
|
||||
}
|
||||
|
||||
get btnLeave(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Leave' });
|
||||
}
|
||||
|
||||
get btnMore(): Locator {
|
||||
return this.root.getByRole('button', { name: 'More' });
|
||||
}
|
||||
|
||||
get optionDelete(): Locator {
|
||||
return this.menu.getMenuItem('Delete');
|
||||
}
|
||||
|
||||
async leaveRoom() {
|
||||
await this.btnLeave.click();
|
||||
await this.confirmLeaveModal.confirmLeave();
|
||||
}
|
||||
|
||||
async deleteRoom() {
|
||||
await this.btnMore.click();
|
||||
await this.menu.selectMenuItem('Delete');
|
||||
await this.confirmDeleteModal.confirmDelete();
|
||||
}
|
||||
}
|
||||
|
||||
class ConfirmConvertIntoChannelModal extends Modal {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Confirmation', exact: true }));
|
||||
}
|
||||
|
||||
private get btnConvert() {
|
||||
return this.root.getByRole('button', { name: 'Convert', exact: true });
|
||||
}
|
||||
|
||||
async confirmConvert() {
|
||||
await this.btnConvert.click();
|
||||
await this.waitForDismissal();
|
||||
}
|
||||
}
|
||||
|
||||
export class TeamInfoFlexTab extends RoomInfoFlexTab {
|
||||
readonly confirmDeleteTeamModal: ConfirmDeleteTeamModal;
|
||||
|
||||
readonly confirmConvertIntoChannelModal: ConfirmConvertIntoChannelModal;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Team info' }));
|
||||
this.confirmDeleteTeamModal = new ConfirmDeleteTeamModal(page);
|
||||
this.confirmConvertIntoChannelModal = new ConfirmConvertIntoChannelModal(page);
|
||||
}
|
||||
|
||||
async deleteTeam() {
|
||||
await this.btnMore.click();
|
||||
await this.menu.selectMenuItem('Delete');
|
||||
return this.confirmDeleteTeamModal.confirmDelete();
|
||||
}
|
||||
|
||||
async convertIntoChannel() {
|
||||
await this.btnMore.click();
|
||||
await this.menu.selectMenuItem('Convert to Channel');
|
||||
await this.confirmConvertIntoChannelModal.confirmConvert();
|
||||
}
|
||||
}
|
||||
|
||||
export class OmnichannelRoomInfoFlexTab extends RoomInfoFlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Room Information' }));
|
||||
}
|
||||
|
||||
getInfo(value: string): Locator {
|
||||
return this.root.locator(`span >> text="${value}"`);
|
||||
}
|
||||
|
||||
getLabel(label: string): Locator {
|
||||
return this.root.locator(`div >> text="${label}"`);
|
||||
}
|
||||
|
||||
getInfoByLabel(label: string): Locator {
|
||||
return this.root.getByLabel(label);
|
||||
}
|
||||
|
||||
getTagInfoByLabel(label: string): Locator {
|
||||
return this.root.getByRole('list', { name: 'Tags' }).getByText(label, { exact: true });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class SearchMessagesFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'Search Messages' }));
|
||||
}
|
||||
|
||||
async search(text: string, { global = false }: { global?: boolean } = {}) {
|
||||
if (global) {
|
||||
await this.root.getByText('Global search').click();
|
||||
}
|
||||
await this.root.getByPlaceholder('Search Messages').fill(text);
|
||||
}
|
||||
|
||||
async getResultItem(messageText: string) {
|
||||
return this.root.getByRole('listitem', { name: messageText });
|
||||
}
|
||||
|
||||
async jumpToMessage(messageText: string) {
|
||||
const message = (await this.getResultItem(messageText)).first();
|
||||
await message.hover();
|
||||
await message.getByRole('button', { name: 'Jump to message' }).click();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
|
||||
export class ThreadsFlexTab extends FlexTab {
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog'));
|
||||
}
|
||||
|
||||
private get listThreadMessages(): Locator {
|
||||
return this.root.getByRole('list', { name: 'Thread message list' });
|
||||
}
|
||||
|
||||
get lastThreadMessage(): Locator {
|
||||
return this.listThreadMessages.locator('[data-qa-type="message"]').last().locator('[data-qa-type="message-body"]');
|
||||
}
|
||||
|
||||
getThreadMessageByText(messageText: string): Locator {
|
||||
return this.listThreadMessages.getByRole('listitem').getByText(messageText);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
|
||||
import { FlexTab } from './flextab';
|
||||
import { MenuMore } from '../menu';
|
||||
|
||||
export class UserInfoFlexTab extends FlexTab {
|
||||
readonly menu: MenuMore;
|
||||
|
||||
constructor(page: Page) {
|
||||
super(page.getByRole('dialog', { name: 'User Info' }));
|
||||
this.menu = new MenuMore(page);
|
||||
}
|
||||
|
||||
get btnEdit(): Locator {
|
||||
return this.root.getByRole('button', { name: 'Edit' });
|
||||
}
|
||||
|
||||
get btnMoreActions(): Locator {
|
||||
return this.root.getByRole('button', { name: 'More' });
|
||||
}
|
||||
|
||||
get menuItemDeleteUser(): Locator {
|
||||
return this.menu.root.getByRole('menuitem', { name: 'Delete' });
|
||||
}
|
||||
|
||||
get username(): Locator {
|
||||
return this.root.getByLabel('Username');
|
||||
}
|
||||
|
||||
async openMoreActions() {
|
||||
await this.btnMoreActions.click();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user