[MM-53127] e2e-tests : Drafts badge doesn't clear when parent message deleted and removed (#23705)

Этот коммит содержится в:
M-ZubairAhmed
2023-07-05 17:13:55 +05:30
коммит произвёл GitHub
родитель 33565dc118
Коммит b153a39d3e
14 изменённых файлов: 440 добавлений и 9 удалений

Просмотреть файл

@@ -0,0 +1,28 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {expect, Locator} from '@playwright/test';
export default class DeletePostModal {
readonly container: Locator;
readonly confirmButton: Locator;
constructor(container: Locator) {
this.container = container;
this.confirmButton = this.container.locator('#deletePostModalButton');
}
async toBeVisible() {
await expect(this.container).toBeVisible();
}
async confirm() {
await this.confirmButton.waitFor();
await this.confirmButton.click();
// Wait for the modal to disappear
await expect(this.container).not.toBeVisible();
}
}
export {DeletePostModal};

Просмотреть файл

@@ -3,25 +3,43 @@
import {expect, Locator} from '@playwright/test';
import {components} from '@e2e-support/ui/components';
export default class ChannelsPost {
readonly container: Locator;
readonly body;
readonly profileIcon;
readonly replyButton;
readonly removePostButton;
readonly postMenu;
readonly threadFooter;
constructor(container: Locator) {
this.container = container;
this.body = container.locator('.post__body');
this.profileIcon = container.locator('.profile-icon');
this.replyButton = container.getByRole('button', {name: 'reply'});
this.removePostButton = container.locator('.post__remove');
this.postMenu = new components.PostMenu(container.locator('.post-menu'));
this.threadFooter = new components.ThreadFooter(container.locator('.ThreadFooter'));
}
async toBeVisible() {
await expect(this.container).toBeVisible();
}
/**
* Hover over the post. Can be used for post menu to appear.
*/
async hover() {
await this.container.hover();
}
async getId() {
const id = await this.container.getAttribute('id');
expect(id, 'No post ID found.').toBeTruthy();
@@ -29,13 +47,21 @@ export default class ChannelsPost {
}
async getProfileImage(username: string) {
return await this.profileIcon.getByAltText(`${username} profile image`);
return this.profileIcon.getByAltText(`${username} profile image`);
}
async openRHS() {
/**
* Clicks on the deleted post's remove 'x' button.
* Also verifies that the post is a deleted post.
*/
async remove() {
// Verify the post is a deleted post
await expect(this.container).toContainText(/\(message deleted\)/);
// Hover over the post and click on the remove post button
await this.container.hover();
await this.replyButton.waitFor();
await this.replyButton.click();
await this.removePostButton.waitFor();
await this.removePostButton.click();
}
}

Просмотреть файл

@@ -9,7 +9,7 @@ export default class ChannelsPostCreate {
readonly input;
readonly attachmentButton;
readonly emojiButton;
readonly sendButton: Locator;
readonly sendMessageButton;
constructor(container: Locator) {
this.container = container;
@@ -17,7 +17,7 @@ export default class ChannelsPostCreate {
this.input = container.getByTestId('post_textbox');
this.attachmentButton = container.getByLabel('attachment');
this.emojiButton = container.getByLabel('select an emoji');
this.sendButton = container.getByTestId('SendMessageButton');
this.sendMessageButton = container.getByTestId('SendMessageButton');
}
async postMessage(message: string) {
@@ -25,7 +25,7 @@ export default class ChannelsPostCreate {
}
async sendMessage() {
await this.sendButton.click();
await this.sendMessageButton.click();
}
async toBeVisible() {

Просмотреть файл

@@ -0,0 +1,27 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {expect, Locator} from '@playwright/test';
export default class PostDotMenu {
readonly container: Locator;
readonly deleteMenuItem;
constructor(container: Locator) {
this.container = container;
this.deleteMenuItem = this.container.getByText('Delete', {exact: true});
}
async toBeVisible() {
await expect(this.container).toBeVisible();
}
async delete() {
await this.deleteMenuItem.waitFor();
await this.deleteMenuItem.click();
}
}
export {PostDotMenu};

Просмотреть файл

@@ -0,0 +1,40 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {expect, Locator} from '@playwright/test';
export default class PostMenu {
readonly container: Locator;
readonly replyButton;
readonly dotMenuButton;
constructor(container: Locator) {
this.container = container;
this.replyButton = container.getByRole('button', {name: 'reply'});
this.dotMenuButton = container.getByRole('button', {name: 'more'});
}
async toBeVisible() {
await expect(this.container).toBeVisible();
}
/**
* Clicks on the reply button from the post menu.
*/
async reply() {
await this.replyButton.waitFor();
await this.replyButton.click();
}
/**
* Clicks on the dot menu button from the post menu.
*/
async openDotMenu() {
await this.dotMenuButton.waitFor();
await this.dotMenuButton.click();
}
}
export {PostMenu};

Просмотреть файл

@@ -16,6 +16,34 @@ export default class ChannelsSidebarLeft {
async toBeVisible() {
await expect(this.container).toBeVisible();
}
/**
* Clicks on the sidebar channel link with the given name.
* It can be any sidebar item name including channels, direct messages, or group messages, threads, etc.
* @param channelName
*/
async goToItem(channelName: string) {
const channel = this.container.locator(`#sidebarItem_${channelName}`);
await channel.waitFor();
await channel.click();
}
/**
* Verifies 'Drafts' as a sidebar link exists in LHS.
*/
async draftsVisible() {
const draftSidebarLink = this.container.getByText('Drafts', {exact: true});
await draftSidebarLink.waitFor();
await expect(draftSidebarLink).toBeVisible();
}
/**
* Verifies 'Drafts' as a sidebar link does not exist in LHS.
*/
async draftsNotVisible() {
const channel = this.container.getByText('Drafts', {exact: true});
await expect(channel).not.toBeVisible();
}
}
export {ChannelsSidebarLeft};

Просмотреть файл

@@ -3,16 +3,62 @@
import {expect, Locator} from '@playwright/test';
import {components} from '@e2e-support/ui/components';
export default class ChannelsSidebarRight {
readonly container: Locator;
readonly input;
readonly sendMessageButton;
readonly closeButton;
constructor(container: Locator) {
this.container = container;
this.input = container.getByTestId('reply_textbox');
this.sendMessageButton = container.getByTestId('SendMessageButton');
this.closeButton = container.locator('#rhsCloseButton');
}
async toBeVisible() {
await expect(this.container).toBeVisible();
}
async postMessage(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);
}
/**
* Closes the RHS
*/
async close() {
await this.closeButton.waitFor();
await this.closeButton.click();
await expect(this.container).not.toBeVisible();
}
}
export {ChannelsSidebarRight};

Просмотреть файл

@@ -0,0 +1,30 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {expect, Locator} from '@playwright/test';
export default class ThreadFooter {
readonly container: Locator;
readonly replyButton: Locator;
constructor(container: Locator) {
this.container = container;
this.replyButton = container.locator('.ReplyButton');
}
async toBeVisible() {
await expect(this.container).toBeVisible();
}
/**
* Clicks on the reply button in the thread footer to open the thread in RHS.
*/
async reply() {
await this.replyButton.waitFor();
await this.replyButton.click();
}
}
export {ThreadFooter};

Просмотреть файл

@@ -11,6 +11,10 @@ import {ChannelsSidebarLeft} from './channels/sidebar_left';
import {ChannelsSidebarRight} from './channels/sidebar_right';
import {FindChannelsModal} from './channels/find_channels_modal';
import {GlobalHeader} from './global_header';
import {PostDotMenu} from './channels/post_dot_menu';
import {DeletePostModal} from './channels/delete_post_modal';
import {PostMenu} from './channels/post_menu';
import {ThreadFooter} from './channels/thread_footer';
const components = {
BoardsSidebar,
@@ -23,6 +27,10 @@ const components = {
ChannelsSidebarRight,
FindChannelsModal,
GlobalHeader,
PostDotMenu,
DeletePostModal,
PostMenu,
ThreadFooter,
};
export {
@@ -37,4 +45,8 @@ export {
ChannelsSidebarRight,
FindChannelsModal,
GlobalHeader,
PostDotMenu,
DeletePostModal,
PostMenu,
ThreadFooter,
};

Просмотреть файл

@@ -18,6 +18,8 @@ export default class ChannelsPage {
readonly appBar;
readonly sidebarLeft;
readonly sidebarRight;
readonly postDotMenu;
readonly deletePostModal;
constructor(page: Page) {
this.page = page;
@@ -29,6 +31,8 @@ export default class ChannelsPage {
this.appBar = new components.ChannelsAppBar(page.locator('.app-bar'));
this.sidebarLeft = new components.ChannelsSidebarLeft(page.locator('#SidebarContainer'));
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
this.postDotMenu = new components.PostDotMenu(page.getByRole('menu', {name: 'Post extra options'}));
this.deletePostModal = new components.DeletePostModal(page.locator('#deletePostModal'));
}
async goto(teamName = '', channelName = '') {