MM-54458 : Refactor playwright test with app areas (#24527)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c887381318
Коммит
6109330beb
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, Locator} from '@playwright/test';
|
||||
|
||||
import {components} from '@e2e-support/ui/components';
|
||||
import {waitUntil} from '@e2e-support/test_action';
|
||||
import {duration} from '@e2e-support/util';
|
||||
|
||||
export default class ChannelsCenterView {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly header;
|
||||
readonly headerMobile;
|
||||
readonly postCreate;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.header = new components.ChannelsHeader(this.container.locator('.channel-header'));
|
||||
this.headerMobile = new components.ChannelsHeaderMobile(this.container.locator('.navbar'));
|
||||
this.postCreate = new components.ChannelsPostCreate(container.getByTestId('post-create'));
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await this.postCreate.toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first post in the Center
|
||||
*/
|
||||
async getFirstPost() {
|
||||
const firstPost = this.container.getByTestId('postView').first();
|
||||
await firstPost.waitFor();
|
||||
return new components.ChannelsPost(firstPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last post in the Center
|
||||
*/
|
||||
async getLastPost() {
|
||||
const lastPost = this.container.getByTestId('postView').last();
|
||||
await lastPost.waitFor();
|
||||
return new components.ChannelsPost(lastPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Nth post in the Center from the top
|
||||
* @param index
|
||||
* @returns
|
||||
*/
|
||||
async getNthPost(index: number) {
|
||||
const nthPost = this.container.getByTestId('postView').nth(index);
|
||||
await nthPost.waitFor();
|
||||
return new components.ChannelsPost(nthPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Center post by post's id
|
||||
* @param postId Just the ID without the prefix
|
||||
*/
|
||||
async getPostById(id: string) {
|
||||
const postById = this.container.locator(`[id="post_${id}"]`);
|
||||
await postById.waitFor();
|
||||
return new components.ChannelsPost(postById);
|
||||
}
|
||||
|
||||
async waitUntilLastPostContains(text: string, timeout = duration.ten_sec) {
|
||||
await waitUntil(
|
||||
async () => {
|
||||
const post = await this.getLastPost();
|
||||
const content = await post.container.textContent();
|
||||
return content?.includes(text);
|
||||
},
|
||||
{timeout}
|
||||
);
|
||||
}
|
||||
|
||||
async waitUntilPostWithIdContains(id: string, text: string, timeout = duration.ten_sec) {
|
||||
await waitUntil(
|
||||
async () => {
|
||||
const post = await this.getPostById(id);
|
||||
const content = await post.container.textContent();
|
||||
|
||||
return content?.includes(text);
|
||||
},
|
||||
{timeout}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {ChannelsCenterView};
|
||||
@@ -10,13 +10,13 @@ export default class ChannelsHeaderMobile {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
async toggleSidebar() {
|
||||
await this.container.getByRole('button', {name: 'Toggle sidebar Menu Icon'}).click();
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async toggleSidebar() {
|
||||
await this.container.getByRole('button', {name: 'Toggle sidebar Menu Icon'}).click();
|
||||
}
|
||||
}
|
||||
|
||||
export {ChannelsHeaderMobile};
|
||||
|
||||
@@ -7,30 +7,76 @@ export default class ChannelsPostCreate {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly input;
|
||||
|
||||
readonly attachmentButton;
|
||||
readonly emojiButton;
|
||||
readonly sendMessageButton;
|
||||
|
||||
constructor(container: Locator) {
|
||||
constructor(container: Locator, isRHS = false) {
|
||||
this.container = container;
|
||||
|
||||
this.input = container.getByTestId('post_textbox');
|
||||
if (!isRHS) {
|
||||
this.input = container.getByTestId('post_textbox');
|
||||
} else {
|
||||
this.input = container.getByTestId('reply_textbox');
|
||||
}
|
||||
|
||||
this.attachmentButton = container.getByLabel('attachment');
|
||||
this.emojiButton = container.getByLabel('select an emoji');
|
||||
this.sendMessageButton = container.getByTestId('SendMessageButton');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
|
||||
await this.input.waitFor();
|
||||
await expect(this.input).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* It just writes the message in the input and doesn't send it
|
||||
* @param message : Message to be written in the input
|
||||
*/
|
||||
async writeMessage(message: string) {
|
||||
await this.input.waitFor();
|
||||
await expect(this.input).toBeVisible();
|
||||
|
||||
await this.input.fill(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the message input
|
||||
*/
|
||||
async getInputValue() {
|
||||
await expect(this.input).toBeVisible();
|
||||
return await this.input.inputValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the message already written in the input
|
||||
*/
|
||||
async sendMessage() {
|
||||
await expect(this.input).toBeVisible();
|
||||
const messageInputValue = await this.getInputValue();
|
||||
expect(messageInputValue).not.toBe('');
|
||||
|
||||
await expect(this.sendMessageButton).toBeVisible();
|
||||
await expect(this.sendMessageButton).toBeEnabled();
|
||||
|
||||
await this.sendMessageButton.click();
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.input).toBeVisible();
|
||||
/**
|
||||
* Composes and sends a message
|
||||
*/
|
||||
async postMessage(message: string) {
|
||||
await this.writeMessage(message);
|
||||
await this.sendMessage();
|
||||
}
|
||||
|
||||
async openEmojiPicker() {
|
||||
await expect(this.emojiButton).toBeVisible();
|
||||
await this.emojiButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,16 +8,13 @@ import {components} from '@e2e-support/ui/components';
|
||||
export default class ChannelsSidebarRight {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly input;
|
||||
readonly sendMessageButton;
|
||||
readonly postCreate;
|
||||
readonly closeButton;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.input = container.getByTestId('reply_textbox');
|
||||
this.sendMessageButton = container.getByTestId('SendMessageButton');
|
||||
|
||||
this.postCreate = new components.ChannelsPostCreate(container.getByTestId('comment-create'), true);
|
||||
this.closeButton = container.locator('#rhsCloseButton');
|
||||
}
|
||||
|
||||
@@ -25,34 +22,23 @@ export default class ChannelsSidebarRight {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async postMessage(message: string) {
|
||||
await this.writeMessage(message);
|
||||
await this.sendMessage();
|
||||
}
|
||||
|
||||
async writeMessage(message: string) {
|
||||
await this.input.fill(message);
|
||||
}
|
||||
|
||||
async sendMessage() {
|
||||
await this.sendMessageButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the textbox in RHS
|
||||
*/
|
||||
async getInputValue() {
|
||||
return await this.input.inputValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RHS post by post id
|
||||
* @param postId Just the ID without the prefix
|
||||
*/
|
||||
async getRHSPostById(postId: string) {
|
||||
const rhsPostId = `rhsPost_${postId}`;
|
||||
const postLocator = this.container.locator(`#${rhsPostId}`);
|
||||
return new components.ChannelsPost(postLocator);
|
||||
async getPostById(postId: string) {
|
||||
const post = this.container.locator(`[id="rhsPost_${postId}"]`);
|
||||
await post.waitFor();
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last post in the RHS
|
||||
*/
|
||||
async getLastPost() {
|
||||
const post = this.container.getByTestId('rhsPostView').last();
|
||||
await post.waitFor();
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ import {ChannelsHeaderMobile} from './channels/header_mobile';
|
||||
import {ChannelsAppBar} from './channels/app_bar';
|
||||
import {ChannelsPostCreate} from './channels/post_create';
|
||||
import {ChannelsPost} from './channels/post';
|
||||
import {ChannelsCenterView} from './channels/center_view'
|
||||
import {ChannelsSidebarLeft} from './channels/sidebar_left';
|
||||
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
||||
import {DeletePostModal} from './channels/delete_post_modal';
|
||||
@@ -21,38 +22,40 @@ import {ThreadFooter} from './channels/thread_footer';
|
||||
|
||||
const components = {
|
||||
BoardsSidebar,
|
||||
GlobalHeader,
|
||||
ChannelsCenterView,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
ChannelsAppBar,
|
||||
ChannelsHeader,
|
||||
ChannelsHeaderMobile,
|
||||
ChannelsPostCreate,
|
||||
ChannelsPost,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
DeletePostModal,
|
||||
FindChannelsModal,
|
||||
Footer,
|
||||
GlobalHeader,
|
||||
MainHeader,
|
||||
DeletePostModal,
|
||||
PostDotMenu,
|
||||
PostReminderMenu,
|
||||
PostMenu,
|
||||
ThreadFooter,
|
||||
Footer,
|
||||
MainHeader,
|
||||
PostReminderMenu,
|
||||
};
|
||||
|
||||
export {
|
||||
components,
|
||||
BoardsSidebar,
|
||||
GlobalHeader,
|
||||
ChannelsCenterView,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
ChannelsAppBar,
|
||||
ChannelsHeader,
|
||||
ChannelsHeaderMobile,
|
||||
ChannelsPostCreate,
|
||||
ChannelsPost,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
FindChannelsModal,
|
||||
GlobalHeader,
|
||||
PostDotMenu,
|
||||
DeletePostModal,
|
||||
PostDotMenu,
|
||||
PostMenu,
|
||||
ThreadFooter,
|
||||
};
|
||||
|
||||
@@ -3,38 +3,51 @@
|
||||
|
||||
import {Page} from '@playwright/test';
|
||||
|
||||
import {waitUntil} from '@e2e-support/test_action';
|
||||
import {components} from '@e2e-support/ui/components';
|
||||
import {duration, isSmallScreen} from '@e2e-support/util';
|
||||
import {isSmallScreen} from '@e2e-support/util';
|
||||
|
||||
export default class ChannelsPage {
|
||||
readonly channels = 'Channels';
|
||||
|
||||
readonly page: Page;
|
||||
readonly postCreate;
|
||||
readonly findChannelsModal;
|
||||
|
||||
readonly globalHeader;
|
||||
readonly header;
|
||||
readonly headerMobile;
|
||||
readonly appBar;
|
||||
readonly centerView;
|
||||
readonly sidebarLeft;
|
||||
readonly sidebarRight;
|
||||
readonly appBar;
|
||||
|
||||
readonly findChannelsModal;
|
||||
readonly deletePostModal;
|
||||
|
||||
readonly postDotMenu;
|
||||
readonly postReminderMenu;
|
||||
readonly deletePostModal;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.postCreate = new components.ChannelsPostCreate(page.locator('#post-create'));
|
||||
this.findChannelsModal = new components.FindChannelsModal(page.getByRole('dialog', {name: 'Find Channels'}));
|
||||
|
||||
// The main areas of the app
|
||||
this.globalHeader = new components.GlobalHeader(page.locator('#global-header'));
|
||||
this.header = new components.ChannelsHeader(page.locator('.channel-header'));
|
||||
this.headerMobile = new components.ChannelsHeaderMobile(page.locator('.navbar'));
|
||||
this.appBar = new components.ChannelsAppBar(page.locator('.app-bar'));
|
||||
this.centerView = new components.ChannelsCenterView(page.getByTestId('channel_view'));
|
||||
this.sidebarLeft = new components.ChannelsSidebarLeft(page.locator('#SidebarContainer'));
|
||||
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
|
||||
this.appBar = new components.ChannelsAppBar(page.locator('.app-bar'));
|
||||
|
||||
// Modals
|
||||
this.findChannelsModal = new components.FindChannelsModal(page.getByRole('dialog', {name: 'Find Channels'}));
|
||||
this.deletePostModal = new components.DeletePostModal(page.locator('#deletePostModal'));
|
||||
|
||||
// Menus
|
||||
this.postDotMenu = new components.PostDotMenu(page.getByRole('menu', {name: 'Post extra options'}));
|
||||
this.postReminderMenu = new components.PostReminderMenu(page.getByRole('menu', {name: 'Set a reminder for:'}));
|
||||
this.deletePostModal = new components.DeletePostModal(page.locator('#deletePostModal'));
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
if (!isSmallScreen(this.page.viewportSize())) {
|
||||
await this.globalHeader.toBeVisible(this.channels);
|
||||
}
|
||||
|
||||
await this.centerView.toBeVisible();
|
||||
}
|
||||
|
||||
async goto(teamName = '', channelName = '') {
|
||||
@@ -48,80 +61,6 @@ export default class ChannelsPage {
|
||||
|
||||
await this.page.goto(channelsUrl);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
if (!isSmallScreen(this.page.viewportSize())) {
|
||||
await this.globalHeader.toBeVisible(this.channels);
|
||||
}
|
||||
await this.postCreate.toBeVisible();
|
||||
}
|
||||
|
||||
async postMessage(message: string) {
|
||||
await this.writeMessage(message);
|
||||
await this.sendMessage();
|
||||
}
|
||||
|
||||
async writeMessage(message: string) {
|
||||
await this.postCreate.input.waitFor();
|
||||
await this.postCreate.writeMessage(message);
|
||||
}
|
||||
|
||||
async sendMessage() {
|
||||
await this.postCreate.sendMessage();
|
||||
}
|
||||
|
||||
async getFirstPost() {
|
||||
await this.page.getByTestId('postView').first().waitFor();
|
||||
const post = await this.page.getByTestId('postView').first();
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
async getLastPost() {
|
||||
await this.page.getByTestId('postView').last().waitFor();
|
||||
const post = await this.page.getByTestId('postView').last();
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
async getNthPost(index: number) {
|
||||
await this.page.getByTestId('postView').nth(index).waitFor();
|
||||
const post = await this.page.getByTestId('postView').nth(index);
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
async getPostById(id: string) {
|
||||
await this.page.locator(`[id="post_${id}"]`).waitFor();
|
||||
const post = await this.page.locator(`[id="post_${id}"]`);
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
async getRHSPostById(id: string) {
|
||||
await this.page.locator(`[id="rhsPost_${id}"]`).waitFor();
|
||||
const post = await this.page.locator(`[id="rhsPost_${id}"]`);
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
async waitUntilLastPostContains(text: string, timeout = duration.ten_sec) {
|
||||
await waitUntil(
|
||||
async () => {
|
||||
const post = await this.getLastPost();
|
||||
const content = await post.container.textContent();
|
||||
return content?.includes(text);
|
||||
},
|
||||
{timeout}
|
||||
);
|
||||
}
|
||||
|
||||
async waitUntilPostWithIdContains(id: string, text: string, timeout = duration.ten_sec) {
|
||||
await waitUntil(
|
||||
async () => {
|
||||
const post = await this.getPostById(id);
|
||||
const content = await post.container.textContent();
|
||||
|
||||
return content?.includes(text);
|
||||
},
|
||||
{timeout}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {ChannelsPage};
|
||||
|
||||
Ссылка в новой задаче
Block a user