Edit file attachment e2e tests (#29797)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
528026d6fb
Коммит
f9cff5c8d6
@@ -16,22 +16,27 @@ export default class ChannelsCenterView {
|
||||
readonly postBoxIndicator;
|
||||
readonly scheduledDraftChannelIcon;
|
||||
readonly scheduledDraftChannelInfoMessage;
|
||||
readonly scheduledDraftChannelInfoMessageLocator;
|
||||
readonly scheduledDraftChannelInfoMessageText;
|
||||
readonly scheduledDraftSeeAllLink;
|
||||
readonly postEdit;
|
||||
readonly editedPostIcon;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.scheduledDraftChannelInfoMessageLocator = 'span:has-text("Message scheduled for")';
|
||||
this.header = new components.ChannelsHeader(this.container.locator('.channel-header'));
|
||||
this.postCreate = new components.ChannelsPostCreate(container.getByTestId('post-create'));
|
||||
this.scheduledDraftOptions = new components.ChannelsPostCreate(
|
||||
container.locator('#dropdown_send_post_options'),
|
||||
);
|
||||
this.postEdit = new components.ChannelsPostEdit(container.locator('.post-edit__container'));
|
||||
this.postBoxIndicator = container.locator('div.postBoxIndicator');
|
||||
this.scheduledDraftChannelIcon = container.locator('#create_post i.icon-draft-indicator');
|
||||
this.scheduledDraftChannelInfoMessage = container.locator('div.ScheduledPostIndicator span');
|
||||
this.scheduledDraftChannelInfoMessageText = container.locator('span:has-text("Message scheduled for")');
|
||||
this.scheduledDraftSeeAllLink = container.locator('a:has-text("See all scheduled messages")');
|
||||
this.scheduledDraftChannelInfoMessageText = container.locator(this.scheduledDraftChannelInfoMessageLocator);
|
||||
this.scheduledDraftSeeAllLink = container.locator('a:has-text("See all")');
|
||||
this.editedPostIcon = (postID: string) => container.locator(`#postEdited_${postID}`);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
@@ -65,6 +70,17 @@ export default class ChannelsCenterView {
|
||||
return new components.ChannelsPost(lastPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID of the last post in the Center
|
||||
*/
|
||||
async getLastPostID() {
|
||||
return this.container
|
||||
.getByTestId('postView')
|
||||
.last()
|
||||
.getAttribute('id')
|
||||
.then((id) => (id ? id.split('_')[1] : null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Nth post in the Center from the top
|
||||
* @param index
|
||||
@@ -115,6 +131,12 @@ export default class ChannelsCenterView {
|
||||
const messageLocator = this.scheduledDraftChannelInfoMessage.first();
|
||||
await expect(messageLocator).toContainText('Message scheduled for');
|
||||
}
|
||||
|
||||
async clickOnLastEditedPost(postID: string | null) {
|
||||
if (postID) {
|
||||
await this.editedPostIcon(postID).click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {ChannelsCenterView};
|
||||
|
||||
@@ -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 DeletePostConfirmationDialog {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly cancelButton;
|
||||
readonly confirmButton;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.cancelButton = container.locator('button.btn.btn-tertiary');
|
||||
this.confirmButton = container.locator('button#deletePostModalButton');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.cancelButton).toBeVisible();
|
||||
await expect(this.confirmButton).toBeVisible();
|
||||
}
|
||||
|
||||
async notToBeVisible() {
|
||||
await expect(this.container).not.toBeVisible();
|
||||
await expect(this.cancelButton).not.toBeVisible();
|
||||
await expect(this.confirmButton).not.toBeVisible();
|
||||
}
|
||||
|
||||
async cancelDeletion() {
|
||||
await this.cancelButton.click();
|
||||
}
|
||||
|
||||
async confirmDeletion() {
|
||||
await this.confirmButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
export {DeletePostConfirmationDialog};
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, Locator} from '@playwright/test';
|
||||
import path from 'node:path';
|
||||
|
||||
export default class ChannelsPostCreate {
|
||||
readonly container: Locator;
|
||||
@@ -23,7 +24,7 @@ export default class ChannelsPostCreate {
|
||||
this.input = container.getByTestId('reply_textbox');
|
||||
}
|
||||
|
||||
this.attachmentButton = container.getByLabel('attachment');
|
||||
this.attachmentButton = container.locator('#fileUploadButton');
|
||||
this.emojiButton = container.getByLabel('select an emoji');
|
||||
this.sendMessageButton = container.getByTestId('SendMessageButton');
|
||||
this.scheduleDraftMessageButton = container.getByLabel('Schedule message');
|
||||
@@ -95,8 +96,18 @@ export default class ChannelsPostCreate {
|
||||
/**
|
||||
* Composes and sends a message
|
||||
*/
|
||||
async postMessage(message: string) {
|
||||
async postMessage(message: string, files?: string[]) {
|
||||
await this.writeMessage(message);
|
||||
|
||||
if (files) {
|
||||
const filePaths = files.map((file) => path.join(path.resolve(__dirname), '../../../asset', file));
|
||||
this.container.page().once('filechooser', async (fileChooser) => {
|
||||
await fileChooser.setFiles(filePaths);
|
||||
});
|
||||
|
||||
await this.attachmentButton.click();
|
||||
}
|
||||
|
||||
await this.sendMessage();
|
||||
}
|
||||
|
||||
|
||||
94
e2e-tests/playwright/support/ui/components/channels/post_edit.ts
Обычный файл
94
e2e-tests/playwright/support/ui/components/channels/post_edit.ts
Обычный файл
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, Locator} from '@playwright/test';
|
||||
import path from 'node:path';
|
||||
import {components} from '@e2e-support/ui/components';
|
||||
|
||||
export default class ChannelsPostEdit {
|
||||
readonly container: Locator;
|
||||
readonly input;
|
||||
|
||||
readonly attachmentButton;
|
||||
readonly emojiButton;
|
||||
readonly sendMessageButton;
|
||||
readonly deleteConfirmationDialog;
|
||||
readonly restorePostConfirmationDialog;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.input = container.getByTestId('edit_textbox');
|
||||
|
||||
this.attachmentButton = container.locator('#fileUploadButton');
|
||||
this.emojiButton = container.getByLabel('select an emoji');
|
||||
this.sendMessageButton = container.locator('.save');
|
||||
this.deleteConfirmationDialog = new components.DeletePostConfirmationDialog(
|
||||
container.page().locator('#deletePostModal'),
|
||||
);
|
||||
this.restorePostConfirmationDialog = new components.RestorePostConfirmationDialog(
|
||||
container.page().locator('#restorePostModal'),
|
||||
);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
|
||||
await this.input.waitFor();
|
||||
await expect(this.input).toBeVisible();
|
||||
}
|
||||
|
||||
async toNotBeVisible() {
|
||||
await expect(this.input).not.toBeVisible();
|
||||
}
|
||||
|
||||
async writeMessage(message: string) {
|
||||
await this.input.waitFor();
|
||||
await expect(this.input).toBeVisible();
|
||||
|
||||
await this.input.clear();
|
||||
await this.input.fill(message);
|
||||
}
|
||||
|
||||
async addFiles(files: string[]) {
|
||||
const filePaths = files.map((file) => path.join(path.resolve(__dirname), '../../../asset', file));
|
||||
this.container.page().once('filechooser', async (fileChooser) => {
|
||||
await fileChooser.setFiles(filePaths);
|
||||
});
|
||||
|
||||
await this.attachmentButton.click();
|
||||
}
|
||||
|
||||
async removeFile(fileName: string) {
|
||||
const files = await this.container.locator(`.file-preview`).all();
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const textContent = await files[i].textContent();
|
||||
if (textContent?.includes(fileName)) {
|
||||
const removeButton = files[i].locator('.icon-close');
|
||||
await removeButton.click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async sendMessage() {
|
||||
await this.input.scrollIntoViewIfNeeded();
|
||||
|
||||
await expect(this.sendMessageButton).toBeVisible();
|
||||
await expect(this.sendMessageButton).toBeEnabled();
|
||||
|
||||
await this.sendMessageButton.click();
|
||||
}
|
||||
|
||||
async postMessage(message: string) {
|
||||
await this.writeMessage(message);
|
||||
await this.sendMessage();
|
||||
}
|
||||
|
||||
async toContainText(text: string) {
|
||||
await expect(this.container).toContainText(text);
|
||||
}
|
||||
}
|
||||
|
||||
export {ChannelsPostEdit};
|
||||
@@ -47,6 +47,13 @@ export default class PostMenu {
|
||||
await this.dotMenuButton.waitFor();
|
||||
await this.dotMenuButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on dot menu button.
|
||||
*/
|
||||
async clickOnDotMenu() {
|
||||
await this.dotMenuButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
export {PostMenu};
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, Locator} from '@playwright/test';
|
||||
|
||||
export default class RestorePostConfirmationDialog {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly cancelButton;
|
||||
readonly confirmButton;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.cancelButton = container.locator('button.btn.btn-tertiary');
|
||||
this.confirmButton = container.locator('button.GenericModal__button.btn.btn-primary.confirm');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.cancelButton).toBeVisible();
|
||||
await expect(this.confirmButton).toBeVisible();
|
||||
}
|
||||
|
||||
async notToBeVisible() {
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
|
||||
async confirmRestore() {
|
||||
await this.confirmButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
export {RestorePostConfirmationDialog};
|
||||
@@ -71,7 +71,7 @@ export default class ScheduledDraftModal {
|
||||
*/
|
||||
async selectTime() {
|
||||
await this.timeLocator.click();
|
||||
const timeButton = this.timeDropdownOptions.first();
|
||||
const timeButton = this.timeDropdownOptions.nth(1);
|
||||
await expect(timeButton).toBeVisible();
|
||||
await timeButton.click();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ export default class ChannelsSidebarLeft {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async assertNoPendingScheduledDraft() {
|
||||
await expect(this.scheduledDraftCountonLHS).not.toBeVisible();
|
||||
}
|
||||
|
||||
async assertscheduledDraftCountLHS(count: string) {
|
||||
await expect(this.scheduledDraftCountonLHS).toBeVisible();
|
||||
await expect(this.scheduledDraftCountonLHS).toHaveText(count);
|
||||
|
||||
@@ -15,17 +15,27 @@ export default class ChannelsSidebarRight {
|
||||
readonly scheduledDraftChannelInfoMessage;
|
||||
readonly scheduledDraftSeeAllLink;
|
||||
readonly scheduledDraftChannelInfoMessageText;
|
||||
readonly editTextbox;
|
||||
readonly postEdit;
|
||||
readonly currentVersionEditedPosttext;
|
||||
readonly restorePreviousPostVersionIcon;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.postBoxIndicator = container.locator('div.postBoxIndicator');
|
||||
this.scheduledDraftChannelInfoMessage = container.locator('div.ScheduledPostIndicator span');
|
||||
this.scheduledDraftSeeAllLink = container.locator('a:has-text("See all scheduled messages")');
|
||||
this.scheduledDraftSeeAllLink = container.locator('a:has-text("See all")');
|
||||
this.scheduledDraftChannelInfoMessageText = container.locator('span:has-text("Message scheduled for")');
|
||||
this.rhsPostBody = container.locator('.post-message__text');
|
||||
this.postCreate = new components.ChannelsPostCreate(container.getByTestId('comment-create'), true);
|
||||
this.closeButton = container.locator('#rhsCloseButton');
|
||||
this.editTextbox = container.locator('#edit_textbox');
|
||||
this.postEdit = new components.ChannelsPostEdit(container.locator('.post-edit__container'));
|
||||
this.currentVersionEditedPosttext = (postID: any) => container.locator(`#rhsPostMessageText_${postID} p`);
|
||||
this.restorePreviousPostVersionIcon = container.locator(
|
||||
'button[aria-label="Select to restore an old message."]',
|
||||
);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
@@ -51,6 +61,12 @@ export default class ChannelsSidebarRight {
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
async getFirstPost() {
|
||||
const post = this.container.getByTestId('rhsPostView').first();
|
||||
await post.waitFor();
|
||||
return new components.ChannelsPost(post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the RHS
|
||||
*/
|
||||
@@ -65,6 +81,19 @@ export default class ChannelsSidebarRight {
|
||||
await this.scheduledDraftSeeAllLink.isVisible();
|
||||
await this.scheduledDraftSeeAllLink.click();
|
||||
}
|
||||
|
||||
async toContainText(text: string) {
|
||||
await expect(this.container).toContainText(text);
|
||||
}
|
||||
|
||||
async verifyCurrentVersionPostMessage(postID: string | null, postMessageContent: string) {
|
||||
expect(await this.currentVersionEditedPosttext(postID).textContent()).toBe(postMessageContent);
|
||||
}
|
||||
|
||||
async restorePreviousPostVersion() {
|
||||
await this.restorePreviousPostVersionIcon.isVisible();
|
||||
await this.restorePreviousPostVersionIcon.click();
|
||||
}
|
||||
}
|
||||
|
||||
export {ChannelsSidebarRight};
|
||||
|
||||
@@ -33,6 +33,9 @@ import {SystemUsers} from './system_console/sections/system_users/system_users';
|
||||
import {SystemUsersFilterPopover} from './system_console/sections/system_users/filter_popover';
|
||||
import {SystemUsersFilterMenu} from './system_console/sections/system_users/filter_menu';
|
||||
import {SystemUsersColumnToggleMenu} from './system_console/sections/system_users/column_toggle_menu';
|
||||
import ChannelsPostEdit from '@e2e-support/ui/components/channels/post_edit';
|
||||
import DeletePostConfirmationDialog from '@e2e-support/ui/components/channels/delete_post_confirmation_dialog';
|
||||
import RestorePostConfirmationDialog from '@e2e-support/ui/components/channels/restore_post_confirmation_dialog';
|
||||
|
||||
const components = {
|
||||
GlobalHeader,
|
||||
@@ -43,6 +46,7 @@ const components = {
|
||||
ChannelsAppBar,
|
||||
ChannelsHeader,
|
||||
ChannelsPostCreate,
|
||||
ChannelsPostEdit,
|
||||
ChannelsPost,
|
||||
FindChannelsModal,
|
||||
DeletePostModal,
|
||||
@@ -65,6 +69,8 @@ const components = {
|
||||
SystemUsersColumnToggleMenu,
|
||||
MessagePriority,
|
||||
UserProfilePopover,
|
||||
DeletePostConfirmationDialog,
|
||||
RestorePostConfirmationDialog,
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -76,6 +82,7 @@ export {
|
||||
ChannelsAppBar,
|
||||
ChannelsHeader,
|
||||
ChannelsPostCreate,
|
||||
ChannelsPostEdit,
|
||||
ChannelsPost,
|
||||
FindChannelsModal,
|
||||
DeletePostModal,
|
||||
@@ -83,4 +90,5 @@ export {
|
||||
PostMenu,
|
||||
ThreadFooter,
|
||||
MessagePriority,
|
||||
DeletePostConfirmationDialog,
|
||||
};
|
||||
|
||||
Ссылка в новой задаче
Block a user