MM-63669 E2E/Playwright: Move "e2e-tests/playwright/test" to "e2e-tests/playwright" folder (#30647)
* move "e2e-tests/playwright/test" to "e2e-tests/playwright/test" and expose "ensurePluginsLoaded" * add test setup, and expose ensurePluginsLoaded and ensureServerDeployment to pw
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
62753a1481
Коммит
a35a6d7a3a
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T53377 Profile popover should show correct fields after at-mention autocomplete', async ({pw}) => {
|
||||
// # Initialize with specific config and get admin client
|
||||
const {user, adminClient, team} = await pw.initSetup();
|
||||
|
||||
await adminClient.patchConfig({
|
||||
PrivacySettings: {
|
||||
ShowEmailAddress: false,
|
||||
ShowFullName: false,
|
||||
},
|
||||
});
|
||||
|
||||
// # Create and add another user using admin client
|
||||
const testUser2 = await adminClient.createUser(pw.random.user(), '', '');
|
||||
await adminClient.addToTeam(team.id, testUser2.id);
|
||||
|
||||
// # Log in as user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Send mentions quickly
|
||||
await channelsPage.centerView.postCreate.postMessage(`@${user.username} @${testUser2.username}`);
|
||||
|
||||
// # Open profile popover for current user
|
||||
const firstMention = channelsPage.centerView.container.getByText(`@${user.username}`, {exact: true});
|
||||
await firstMention.click();
|
||||
|
||||
// * Verify all fields are visible for current user
|
||||
const popover = channelsPage.userProfilePopover;
|
||||
await expect(popover.container.getByText(`@${user.username}`)).toBeVisible();
|
||||
await expect(popover.container.getByText(`${user.first_name} ${user.last_name}`)).toBeVisible();
|
||||
await expect(popover.container.getByText(user.email)).toBeVisible();
|
||||
|
||||
// # Close profile popover
|
||||
await popover.close();
|
||||
|
||||
// # Open profile popover for other user
|
||||
const secondMention = channelsPage.centerView.container.getByText(`@${testUser2.username}`, {exact: true});
|
||||
await secondMention.click();
|
||||
|
||||
// * Verify only username is visible for other user
|
||||
await expect(popover.container.getByText(`@${testUser2.username}`)).toBeVisible();
|
||||
await expect(popover.container.getByText(testUser2.email)).not.toBeVisible();
|
||||
|
||||
// # Close profile popover
|
||||
await popover.close();
|
||||
|
||||
// # Trigger autocomplete
|
||||
await channelsPage.centerView.postCreate.writeMessage(`@${user.username}`);
|
||||
|
||||
// # Wait for autocomplete
|
||||
const suggestionList = channelsPage.centerView.postCreate.suggestionList;
|
||||
await expect(suggestionList.getByText(`@${user.username}`)).toBeVisible();
|
||||
|
||||
// # Clear textbox
|
||||
await channelsPage.centerView.postCreate.writeMessage('');
|
||||
|
||||
// # Open profile popover for current user again
|
||||
await firstMention.click();
|
||||
|
||||
// * Verify all fields are still visible
|
||||
await expect(popover.container.getByText(`@${user.username}`)).toBeVisible();
|
||||
await expect(popover.container.getByText(`${user.first_name} ${user.last_name}`)).toBeVisible();
|
||||
await expect(popover.container.getByText(user.email)).toBeVisible();
|
||||
});
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another user deleted root post and user removes the deleted post ', async ({
|
||||
pw,
|
||||
}) => {
|
||||
const {adminClient, team, adminUser, user} = await pw.initSetup();
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Get the default channel of the team for getting the channel id
|
||||
const channel = await adminClient.getChannelByName(team.id, 'town-square');
|
||||
|
||||
// # Create a post in the channel by admin
|
||||
const adminPost = await adminClient.createPost(
|
||||
pw.random.post({
|
||||
channel_id: channel.id,
|
||||
user_id: adminUser.id,
|
||||
}),
|
||||
);
|
||||
|
||||
// # Log in as user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
const lastPostByAdmin = await channelsPage.centerView.getLastPost();
|
||||
await lastPostByAdmin.toBeVisible();
|
||||
|
||||
// # Open the last post sent by admin in RHS
|
||||
await lastPostByAdmin.hover();
|
||||
await lastPostByAdmin.postMenu.toBeVisible();
|
||||
await lastPostByAdmin.postMenu.reply();
|
||||
|
||||
// # Post a message as a user
|
||||
const sidebarRight = channelsPage.sidebarRight;
|
||||
await sidebarRight.toBeVisible();
|
||||
await sidebarRight.postCreate.postMessage('Replying to a thread');
|
||||
|
||||
// # Write a message in the reply thread but don't send it now so that it becomes a draft
|
||||
const draftMessageByUser = 'I should be in drafts by User';
|
||||
await sidebarRight.postCreate.writeMessage(draftMessageByUser);
|
||||
|
||||
// # Close the RHS for draft to be saved
|
||||
await sidebarRight.close();
|
||||
|
||||
// * Verify drafts link in channel sidebar is visible
|
||||
await channelsPage.sidebarLeft.draftsVisible();
|
||||
|
||||
// # Delete the last post by admin
|
||||
try {
|
||||
await adminClient.deletePost(adminPost.id);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to delete post by admin: ${error}`);
|
||||
}
|
||||
|
||||
// # Open the last post in the channel sent by admin again
|
||||
await lastPostByAdmin.body.click();
|
||||
|
||||
// * Verify drafts in user's textbox is still visible
|
||||
const rhsTextboxValue = await sidebarRight.postCreate.getInputValue();
|
||||
expect(rhsTextboxValue).toBe(draftMessageByUser);
|
||||
|
||||
// # Click on remove post
|
||||
const deletedPostByAdminInRHS = await sidebarRight.getPostById(adminPost.id);
|
||||
await deletedPostByAdminInRHS.remove();
|
||||
|
||||
// * Verify the drafts links should also be removed from sidebar
|
||||
await channelsPage.sidebarLeft.draftsNotVisible();
|
||||
});
|
||||
|
||||
test('MM-T5435_2 Global Drafts link in sidebar should be hidden when user deletes root post ', async ({pw}) => {
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Post a message in the channel
|
||||
await channelsPage.centerView.postCreate.postMessage('Message which will be deleted');
|
||||
|
||||
// # Start a thread by clicking on reply menuitem from post options menu
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
await post.postMenu.reply();
|
||||
|
||||
const sidebarRight = channelsPage.sidebarRight;
|
||||
await sidebarRight.toBeVisible();
|
||||
|
||||
// # Post a message in the thread
|
||||
await sidebarRight.postCreate.postMessage('Replying to a thread');
|
||||
|
||||
// # Write a message in the reply thread but don't send it
|
||||
await sidebarRight.postCreate.writeMessage('I should be in drafts');
|
||||
|
||||
// # Close the RHS for draft to be saved
|
||||
await sidebarRight.close();
|
||||
|
||||
// * Verify drafts link in channel sidebar is visible
|
||||
await channelsPage.sidebarLeft.draftsVisible();
|
||||
|
||||
// # Click on the dot menu of the post and select delete
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
await post.postMenu.openDotMenu();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.deleteMenuItem.click();
|
||||
|
||||
// # Confirm the delete from the modal
|
||||
await channelsPage.deletePostModal.toBeVisible();
|
||||
await channelsPage.deletePostModal.confirm();
|
||||
|
||||
// * Verify drafts link in channel sidebar is visible
|
||||
await channelsPage.sidebarLeft.draftsNotVisible();
|
||||
});
|
||||
@@ -0,0 +1,354 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Page} from '@playwright/test';
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T5654_1 should be able to add attachments while editing a post', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
|
||||
// open the dot menu
|
||||
await post.postMenu.dotMenuButton.click();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.writeMessage('Edited message');
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
const updatedPost = await channelsPage.centerView.getLastPost();
|
||||
await updatedPost.toBeVisible();
|
||||
await updatedPost.toContainText('Edited message');
|
||||
});
|
||||
|
||||
test('MM-T5654_2 should be able to add attachments while editing a threaded post', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage, page} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
|
||||
// open the dot menu
|
||||
await post.postMenu.dotMenuButton.click();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.replyMenuItem.click();
|
||||
await channelsPage.sidebarRight.toBeVisible();
|
||||
await channelsPage.sidebarRight.postCreate.toBeVisible();
|
||||
await channelsPage.sidebarRight.postCreate.postMessage('Replying to the post');
|
||||
await channelsPage.sidebarRight.toContainText('Replying to the post');
|
||||
|
||||
const replyPost = await channelsPage.sidebarRight.getLastPost();
|
||||
await replyPost.toBeVisible();
|
||||
await replyPost.hover();
|
||||
await replyPost.postMenu.toBeVisible();
|
||||
await replyPost.postMenu.dotMenuButton.click();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.sidebarRight.postEdit.toBeVisible();
|
||||
await channelsPage.sidebarRight.postEdit.writeMessage('Edited reply message');
|
||||
await channelsPage.sidebarRight.postEdit.sendMessage();
|
||||
|
||||
let updatedReplyPost = await channelsPage.sidebarRight.getLastPost();
|
||||
await updatedReplyPost.toBeVisible();
|
||||
await updatedReplyPost.toContainText('Edited reply message');
|
||||
|
||||
// now we'll edit the reply post and files to it
|
||||
await updatedReplyPost.hover();
|
||||
await updatedReplyPost.postMenu.toBeVisible();
|
||||
await updatedReplyPost.postMenu.dotMenuButton.click();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.sidebarRight.postEdit.toBeVisible();
|
||||
await channelsPage.sidebarRight.postEdit.writeMessage('Edited reply message with files');
|
||||
await channelsPage.sidebarRight.postEdit.addFiles(['sample_text_file.txt', 'mattermost.png']);
|
||||
await pw.wait(pw.duration.half_sec);
|
||||
await channelsPage.sidebarRight.postEdit.sendMessage();
|
||||
await pw.wait(pw.duration.half_sec);
|
||||
await channelsPage.sidebarRight.postEdit.toNotBeVisible();
|
||||
await updatedReplyPost.toBeVisible();
|
||||
await updatedReplyPost.toContainText('Edited reply message with files');
|
||||
await updatedReplyPost.toContainText('sample_text_file.txt');
|
||||
await updatedReplyPost.toContainText('mattermost.png');
|
||||
|
||||
// now we'll remove the files
|
||||
await updatedReplyPost.hover();
|
||||
await updatedReplyPost.postMenu.toBeVisible();
|
||||
await updatedReplyPost.postMenu.clickOnDotMenu();
|
||||
await moveMouseToCenter(page);
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.sidebarRight.postEdit.toBeVisible();
|
||||
await channelsPage.sidebarRight.postEdit.removeFile('sample_text_file.txt');
|
||||
await pw.wait(pw.duration.half_sec);
|
||||
await channelsPage.sidebarRight.postEdit.removeFile('mattermost.png');
|
||||
await pw.wait(pw.duration.half_sec);
|
||||
await channelsPage.sidebarRight.postEdit.sendMessage();
|
||||
|
||||
updatedReplyPost = await channelsPage.sidebarRight.getLastPost();
|
||||
await updatedReplyPost.toBeVisible();
|
||||
await updatedReplyPost.toContainText('Edited reply message with files');
|
||||
expect(updatedReplyPost).not.toContain('sample_text_file.txt');
|
||||
expect(updatedReplyPost).not.toContain('mattermost.png');
|
||||
});
|
||||
|
||||
test('MM-T5654_3 should be able to edit post message originally containing files', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage, ['sample_text_file.txt']);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
|
||||
// open the dot menu
|
||||
await post.postMenu.dotMenuButton.click();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.writeMessage('Edited message');
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
const updatedPost = await channelsPage.centerView.getLastPost();
|
||||
await updatedPost.toBeVisible();
|
||||
await updatedPost.toContainText('Edited message');
|
||||
});
|
||||
|
||||
test('MM-T5654_4 should be able to add files when editing a post', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
|
||||
// open the dot menu
|
||||
await post.postMenu.dotMenuButton.click();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.writeMessage('Edited message');
|
||||
await channelsPage.centerView.postEdit.addFiles(['sample_text_file.txt']);
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
const updatedPost = await channelsPage.centerView.getLastPost();
|
||||
await updatedPost.toBeVisible();
|
||||
await updatedPost.toContainText('Edited message');
|
||||
await updatedPost.toContainText('sample_text_file.txt');
|
||||
|
||||
// now we'll add multiple files
|
||||
await post.postMenu.dotMenuButton.click();
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.addFiles(['mattermost.png', 'archive.zip']);
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
const secondUpdatedPost = await channelsPage.centerView.getLastPost();
|
||||
await secondUpdatedPost.toBeVisible();
|
||||
await secondUpdatedPost.toContainText('Edited message');
|
||||
await secondUpdatedPost.toContainText('sample_text_file.txt');
|
||||
await secondUpdatedPost.toContainText('mattermost.png');
|
||||
await secondUpdatedPost.toContainText('archive.zip');
|
||||
});
|
||||
|
||||
test('MM-5654_5 should be able to remove attachments while editing a post', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage, page} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage, [
|
||||
'sample_text_file.txt',
|
||||
'mattermost.png',
|
||||
'archive.zip',
|
||||
]);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.toContainText(originalMessage);
|
||||
await post.toContainText('sample_text_file.txt');
|
||||
await post.toContainText('mattermost.png');
|
||||
await post.toContainText('archive.zip');
|
||||
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
await post.postMenu.clickOnDotMenu();
|
||||
await moveMouseToCenter(page);
|
||||
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.removeFile('sample_text_file.txt');
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
const updatedPost = await channelsPage.centerView.getLastPost();
|
||||
await updatedPost.toBeVisible();
|
||||
await updatedPost.toContainText(originalMessage);
|
||||
await updatedPost.toContainText('mattermost.png');
|
||||
await updatedPost.toContainText('archive.zip');
|
||||
expect(updatedPost).not.toContain('archive.zip');
|
||||
});
|
||||
|
||||
test('MM-T5655_1 removing message content and files should delete the post', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage, ['sample_text_file.txt']);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.toContainText(originalMessage);
|
||||
await post.toContainText('sample_text_file.txt');
|
||||
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
await post.postMenu.dotMenuButton.click();
|
||||
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.removeFile('sample_text_file.txt');
|
||||
await channelsPage.centerView.postEdit.writeMessage('');
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
await channelsPage.centerView.postEdit.deleteConfirmationDialog.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.deleteConfirmationDialog.confirmDeletion();
|
||||
await channelsPage.centerView.postEdit.deleteConfirmationDialog.notToBeVisible();
|
||||
|
||||
expect(channelsPage).not.toContain(originalMessage);
|
||||
expect(channelsPage).not.toContain('sample_text_file.txt');
|
||||
});
|
||||
|
||||
test('MM-T5655_2 should be able to remove all files when editing a post', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage, page} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage, [
|
||||
'sample_text_file.txt',
|
||||
'mattermost.png',
|
||||
'archive.zip',
|
||||
]);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.toContainText(originalMessage);
|
||||
await post.toContainText('sample_text_file.txt');
|
||||
await post.toContainText('mattermost.png');
|
||||
await post.toContainText('archive.zip');
|
||||
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
await post.postMenu.clickOnDotMenu();
|
||||
await moveMouseToCenter(page);
|
||||
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.removeFile('sample_text_file.txt');
|
||||
await channelsPage.centerView.postEdit.removeFile('mattermost.png');
|
||||
await channelsPage.centerView.postEdit.removeFile('archive.zip');
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
const updatedPost = await channelsPage.centerView.getLastPost();
|
||||
await updatedPost.toBeVisible();
|
||||
await updatedPost.toContainText(originalMessage);
|
||||
expect(updatedPost).not.toContain('archive.zip');
|
||||
expect(updatedPost).not.toContain('mattermost.png');
|
||||
expect(updatedPost).not.toContain('sample_text_file.txt');
|
||||
});
|
||||
|
||||
test('MM-T5656_1 should be able to restore previously edited post version that contains attachments', async ({pw}) => {
|
||||
const originalMessage = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';
|
||||
const newMessage = 'New Message';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.postMessage(originalMessage, ['sample_text_file.txt']);
|
||||
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await post.toBeVisible();
|
||||
await post.toContainText(originalMessage);
|
||||
await post.toContainText('sample_text_file.txt');
|
||||
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
await post.postMenu.dotMenuButton.click();
|
||||
|
||||
await channelsPage.postDotMenu.toBeVisible();
|
||||
await channelsPage.postDotMenu.editMenuItem.click();
|
||||
await channelsPage.centerView.postEdit.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.removeFile('sample_text_file.txt');
|
||||
await channelsPage.centerView.postEdit.writeMessage(newMessage);
|
||||
await channelsPage.centerView.postEdit.sendMessage();
|
||||
|
||||
const updatedPost = await channelsPage.centerView.getLastPost();
|
||||
await updatedPost.toBeVisible();
|
||||
await updatedPost.toContainText(newMessage);
|
||||
expect(updatedPost).not.toContain('sample_text_file.txt');
|
||||
|
||||
const postID = await channelsPage.centerView.getLastPostID();
|
||||
await channelsPage.centerView.clickOnLastEditedPost(postID);
|
||||
|
||||
await channelsPage.sidebarRight.toBeVisible();
|
||||
await channelsPage.sidebarRight.verifyCurrentVersionPostMessage(postID, newMessage);
|
||||
|
||||
await channelsPage.sidebarRight.restorePreviousPostVersion();
|
||||
|
||||
await channelsPage.centerView.postEdit.restorePostConfirmationDialog.toBeVisible();
|
||||
await channelsPage.centerView.postEdit.restorePostConfirmationDialog.confirmRestore();
|
||||
await channelsPage.centerView.postEdit.restorePostConfirmationDialog.notToBeVisible();
|
||||
|
||||
const restoredPost = await channelsPage.centerView.getLastPost();
|
||||
await restoredPost.toBeVisible();
|
||||
expect(restoredPost.toContainText('sample_text_file.txt'));
|
||||
});
|
||||
|
||||
async function moveMouseToCenter(page: Page) {
|
||||
await page.mouse.move(0, 0);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test.fixme(
|
||||
'MM-T5445 Should search, select and post correct Gif when Gif picker is opened from center textbox',
|
||||
async ({pw}) => {
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Open emoji/gif picker
|
||||
await channelsPage.centerView.postCreate.openEmojiPicker();
|
||||
await channelsPage.emojiGifPickerPopup.toBeVisible();
|
||||
|
||||
// # Open gif tab
|
||||
await channelsPage.emojiGifPickerPopup.openGifTab();
|
||||
|
||||
// # Search for gif
|
||||
await channelsPage.emojiGifPickerPopup.searchGif('hello');
|
||||
|
||||
// # Select the first gif
|
||||
const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} =
|
||||
await channelsPage.emojiGifPickerPopup.getNthGif(0);
|
||||
await firstSearchGifResult.click();
|
||||
|
||||
// # Send the selected gif as a message
|
||||
await channelsPage.centerView.postCreate.sendMessage();
|
||||
|
||||
// * Verify that last message has the gif
|
||||
const lastPost = await channelsPage.centerView.getLastPost();
|
||||
await lastPost.toBeVisible();
|
||||
await expect(lastPost.body.getByLabel('file thumbnail')).toHaveAttribute('alt', altOfFirstSearchGifResult);
|
||||
},
|
||||
);
|
||||
|
||||
test.fixme(
|
||||
'MM-T5446 Should search, select and post correct Gif when Gif picker is opened from RHS textbox',
|
||||
async ({pw}) => {
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Send a message
|
||||
await channelsPage.centerView.postCreate.postMessage('Message to open RHS');
|
||||
|
||||
// # Open the last post sent in RHS
|
||||
const lastPost = await channelsPage.centerView.getLastPost();
|
||||
await lastPost.hover();
|
||||
await lastPost.postMenu.toBeVisible();
|
||||
await lastPost.postMenu.reply();
|
||||
|
||||
const sidebarRight = channelsPage.sidebarRight;
|
||||
await sidebarRight.toBeVisible();
|
||||
|
||||
// # Send a message in the thread
|
||||
await sidebarRight.postCreate.toBeVisible();
|
||||
await sidebarRight.postCreate.writeMessage('Replying to a thread');
|
||||
await sidebarRight.postCreate.sendMessage();
|
||||
|
||||
// # Open emoji/gif picker
|
||||
await sidebarRight.postCreate.openEmojiPicker();
|
||||
await channelsPage.emojiGifPickerPopup.toBeVisible();
|
||||
|
||||
// # Open gif tab
|
||||
await channelsPage.emojiGifPickerPopup.openGifTab();
|
||||
|
||||
// # Search for gif
|
||||
await channelsPage.emojiGifPickerPopup.searchGif('hello');
|
||||
|
||||
// # Select the first gif
|
||||
const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} =
|
||||
await channelsPage.emojiGifPickerPopup.getNthGif(0);
|
||||
await firstSearchGifResult.click();
|
||||
|
||||
// # Send the selected gif as a message in the thread
|
||||
await sidebarRight.postCreate.sendMessage();
|
||||
|
||||
// * Verify that last message has the gif
|
||||
const lastPostInRHS = await sidebarRight.getLastPost();
|
||||
await lastPostInRHS.toBeVisible();
|
||||
await expect(lastPostInRHS.body.getByLabel('file thumbnail')).toHaveAttribute('alt', altOfFirstSearchGifResult);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T5139: Message Priority - Standard message priority and system setting', async ({pw}) => {
|
||||
// # Setup test environment
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// Open menu
|
||||
await channelsPage.centerView.postCreate.openPriorityMenu();
|
||||
|
||||
// Use messagePriority for dialog interactions
|
||||
await channelsPage.messagePriority.verifyPriorityDialog();
|
||||
await channelsPage.messagePriority.verifyStandardOptionSelected();
|
||||
|
||||
// # Close menu and post message
|
||||
await channelsPage.messagePriority.closePriorityMenu();
|
||||
|
||||
const testMessage = 'This is just a test message';
|
||||
await channelsPage.postMessage(testMessage);
|
||||
|
||||
// # Verify message posts without priority label
|
||||
const lastPost = await channelsPage.centerView.getLastPost();
|
||||
await lastPost.toBeVisible();
|
||||
await lastPost.toContainText(testMessage);
|
||||
await expect(lastPost.container.locator('.post-priority')).not.toBeVisible();
|
||||
|
||||
// # Open post in RHS and verify
|
||||
await lastPost.container.click();
|
||||
await channelsPage.sidebarRight.toBeVisible();
|
||||
|
||||
// # Get RHS post and verify content
|
||||
const rhsPost = await channelsPage.sidebarRight.getLastPost();
|
||||
await rhsPost.toBeVisible();
|
||||
await rhsPost.toContainText(testMessage);
|
||||
await expect(rhsPost.container.locator('.post-priority')).not.toBeVisible();
|
||||
|
||||
// # Verify RHS formatting bar doesn't have priority button
|
||||
await expect(channelsPage.sidebarRight.postCreate.priorityButton).not.toBeVisible();
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T483 Channel-wide mentions with uppercase letters', async ({pw, headless, browserName}) => {
|
||||
test.skip(
|
||||
headless && browserName !== 'firefox',
|
||||
'Works across browsers and devices, except in headless mode, where stubbing the Notification API is supported only in Firefox and WebKit.',
|
||||
);
|
||||
|
||||
// Initialize setup and get the required users and team
|
||||
const {team, adminUser, user} = await pw.initSetup();
|
||||
|
||||
// Log in as the admin in one browser session and navigate to the "town-square" channel
|
||||
const {page: adminPage, channelsPage: adminChannelsPage} = await pw.testBrowser.login(adminUser);
|
||||
await adminChannelsPage.goto(team.name, 'town-square');
|
||||
await adminChannelsPage.toBeVisible();
|
||||
|
||||
// Stub the Notification in the admin's browser to capture notifications
|
||||
await pw.stubNotification(adminPage, 'granted');
|
||||
|
||||
// Log in as the regular user in a separate browser and navigate to the "off-topic" channel
|
||||
const {channelsPage: otherChannelsPage} = await pw.testBrowser.login(user);
|
||||
await otherChannelsPage.goto(team.name, 'off-topic');
|
||||
await otherChannelsPage.toBeVisible();
|
||||
|
||||
// Post a channel-wide mention message "@ALL" in uppercase from the user's browser
|
||||
const message = `@ALL good morning, ${team.name}!`;
|
||||
await otherChannelsPage.postMessage(message);
|
||||
|
||||
// Wait for a notification to be received in the admin's browser and verify its content
|
||||
const notifications = await pw.waitForNotification(adminPage);
|
||||
expect(notifications.length).toBe(1);
|
||||
|
||||
const notification = notifications[0];
|
||||
expect(notification.title).toBe('Off-Topic');
|
||||
expect(notification.body).toBe(`@${user.username}: ${message}`);
|
||||
expect(notification.tag).toBe(`@${user.username}: ${message}`);
|
||||
expect(notification.icon).toContain('.png');
|
||||
expect(notification.requireInteraction).toBe(false);
|
||||
expect(notification.silent).toBe(false);
|
||||
|
||||
// Verify the last post as viewed by the regular user in the "off-topic" channel contains the message and is highlighted
|
||||
const otherLastPost = await otherChannelsPage.centerView.getLastPost();
|
||||
await otherLastPost.toContainText(message);
|
||||
await expect(otherLastPost.container.locator('.mention--highlight')).toBeVisible();
|
||||
await expect(otherLastPost.container.locator('.mention--highlight').getByText('@ALL')).toBeVisible();
|
||||
|
||||
// Admin navigates to the "off-topic" channel and verifies the message is posted and highlighted correctly
|
||||
await adminChannelsPage.goto(team.name, 'off-topic');
|
||||
const adminLastPost = await adminChannelsPage.centerView.getLastPost();
|
||||
await adminLastPost.toContainText(message);
|
||||
await expect(adminLastPost.container.locator('.mention--highlight')).toBeVisible();
|
||||
await expect(adminLastPost.container.locator('.mention--highlight').getByText('@ALL')).toBeVisible();
|
||||
});
|
||||
@@ -0,0 +1,411 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {Page} from '@playwright/test';
|
||||
|
||||
import {expect, PlaywrightExtended, test} from '@mattermost/playwright-lib';
|
||||
import type {ChannelsPage, ScheduledDraftPage} from '@mattermost/playwright-lib';
|
||||
|
||||
test.skip('MM-T5643_1 should create a scheduled message from a channel', async ({pw}) => {
|
||||
test.setTimeout(pw.duration.four_min);
|
||||
|
||||
const draftMessage = 'Scheduled Draft';
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await setupChannelPage(channelsPage, draftMessage);
|
||||
await scheduleMessage(channelsPage);
|
||||
|
||||
await channelsPage.centerView.verifyscheduledDraftChannelInfo();
|
||||
|
||||
const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
|
||||
await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
|
||||
|
||||
// # Hover and verify options
|
||||
await scheduledDraftPage.verifyOnHoverActionItems(draftMessage);
|
||||
|
||||
// # Go back and wait for message to arrive
|
||||
await goBackToChannelAndWaitForMessageToArrive(pw, page);
|
||||
|
||||
// * Verify the message has been sent and there's no more scheduled messages
|
||||
await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
|
||||
await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
|
||||
await expect(await channelsPage.getLastPost()).toHaveText(draftMessage);
|
||||
await channelsPage.sidebarLeft.assertNoPendingScheduledDraft();
|
||||
});
|
||||
|
||||
test('MM-T5643_6 should create a scheduled message under a thread post ', async ({pw}) => {
|
||||
const draftMessage = 'Scheduled Threaded Message';
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
await channelsPage.centerView.postCreate.postMessage('Root Message');
|
||||
|
||||
// # Start a thread by clicking on reply menuitem from post options menu
|
||||
const post = await channelsPage.centerView.getLastPost();
|
||||
await replyToLastPost(post);
|
||||
|
||||
const sidebarRight = channelsPage.sidebarRight;
|
||||
await sidebarRight.toBeVisible();
|
||||
|
||||
// # Post a message in the thread
|
||||
await sidebarRight.postCreate.postMessage('Replying to a thread');
|
||||
|
||||
// # Write a message in the reply thread but don't send it
|
||||
await sidebarRight.postCreate.writeMessage(draftMessage);
|
||||
await expect(sidebarRight.postCreate.input).toHaveText(draftMessage);
|
||||
|
||||
await sidebarRight.postCreate.scheduleDraftMessageButton.isVisible();
|
||||
await sidebarRight.postCreate.scheduleDraftMessageButton.click();
|
||||
|
||||
await scheduleMessage(channelsPage);
|
||||
|
||||
await sidebarRight.postBoxIndicator.isVisible();
|
||||
const messageLocator = sidebarRight.scheduledDraftChannelInfoMessage.first();
|
||||
await expect(messageLocator).toContainText('Message scheduled for');
|
||||
|
||||
// Save the time displayed in the thread
|
||||
const scheduledDraftThreadedPanelInfo = await sidebarRight.postBoxIndicator.innerText();
|
||||
|
||||
await channelsPage.sidebarRight.clickOnSeeAllscheduledDrafts();
|
||||
const scheduledDraftPageInfo = await scheduledDraftPage.scheduledDraftPageInfo.innerHTML();
|
||||
await channelsPage.sidebarLeft.assertscheduledDraftCountLHS('1');
|
||||
|
||||
await scheduledDraftPage.toBeVisible();
|
||||
await scheduledDraftPage.assertBadgeCountOnTab('1');
|
||||
|
||||
await scheduledDraftPage.assertscheduledDraftBody(draftMessage);
|
||||
|
||||
await compareMessageTimestamps(scheduledDraftThreadedPanelInfo, scheduledDraftPageInfo, scheduledDraftPage);
|
||||
|
||||
// # Hover and verify options
|
||||
await scheduledDraftPage.verifyOnHoverActionItems(draftMessage);
|
||||
|
||||
await scheduledDraftPage.sendScheduledMessage(draftMessage);
|
||||
|
||||
await sidebarRight.toBeVisible();
|
||||
(await sidebarRight.getLastPost()).toContainText(draftMessage);
|
||||
|
||||
await expect(channelsPage.sidebarRight.scheduledDraftChannelInfoMessage.first()).not.toBeVisible();
|
||||
await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
|
||||
await channelsPage.sidebarLeft.assertNoPendingScheduledDraft();
|
||||
});
|
||||
|
||||
test('MM-T5644 should reschedule a scheduled message', async ({pw}) => {
|
||||
const draftMessage = 'Scheduled Draft';
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await setupChannelPage(channelsPage, draftMessage);
|
||||
await scheduleMessage(channelsPage);
|
||||
|
||||
// * Verify the Initial Date and time of scheduled Draft
|
||||
await channelsPage.centerView.verifyscheduledDraftChannelInfo();
|
||||
const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
|
||||
|
||||
await scheduledDraftPage.openRescheduleModal(draftMessage);
|
||||
|
||||
// # Reschedule it to 2 days from today
|
||||
await channelsPage.scheduledDraftModal.selectDay(2);
|
||||
await channelsPage.scheduledDraftModal.confirm();
|
||||
|
||||
// # Note the new Scheduled time
|
||||
const scheduledDraftPageInfo = await scheduledDraftPage.getTimeStampOfMessage(draftMessage);
|
||||
|
||||
// # Go to Channel
|
||||
await channelsPage.goto();
|
||||
|
||||
// * Verify the New Time reflecting in the channel
|
||||
const rescheduledDraftChannelInfo = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
await compareMessageTimestamps(rescheduledDraftChannelInfo, scheduledDraftPageInfo, scheduledDraftPage);
|
||||
});
|
||||
|
||||
test('MM-T5645 should delete a scheduled message', async ({pw}) => {
|
||||
const draftMessage = 'Scheduled Draft';
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await setupChannelPage(channelsPage, draftMessage);
|
||||
await scheduleMessage(channelsPage);
|
||||
const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
|
||||
await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
|
||||
|
||||
await scheduledDraftPage.deleteScheduledMessage(draftMessage);
|
||||
|
||||
await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible();
|
||||
await expect(scheduledDraftPage.noscheduledDraftIcon).toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5643_9 should send a scheduled message immediately', async ({pw}) => {
|
||||
const draftMessage = 'Scheduled Draft';
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await setupChannelPage(channelsPage, draftMessage);
|
||||
await scheduleMessage(channelsPage);
|
||||
const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
|
||||
await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
|
||||
|
||||
await scheduledDraftPage.sendScheduledMessage(draftMessage);
|
||||
await pw.wait(pw.duration.two_sec);
|
||||
|
||||
await expect(scheduledDraftPage.scheduledDraftPanel(draftMessage)).not.toBeVisible();
|
||||
|
||||
// Verify message has arrived
|
||||
await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
|
||||
await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
|
||||
await expect(await channelsPage.getLastPost()).toHaveText(draftMessage);
|
||||
});
|
||||
|
||||
test('MM-T5643_3 should create a scheduled message from a DM', async ({pw}) => {
|
||||
const draftMessage = 'Scheduled Draft';
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user, team} = await pw.initSetup();
|
||||
const {user: user2} = await pw.initSetup();
|
||||
|
||||
const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await setupChannelPage(channelsPage, draftMessage, team.name, `@${user2.username}`);
|
||||
await scheduleMessage(channelsPage);
|
||||
|
||||
await channelsPage.centerView.verifyscheduledDraftChannelInfo();
|
||||
|
||||
const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
|
||||
await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
|
||||
|
||||
// # Hover and verify options
|
||||
await scheduledDraftPage.verifyOnHoverActionItems(draftMessage);
|
||||
|
||||
await scheduledDraftPage.sendScheduledMessage(draftMessage);
|
||||
await page.waitForSelector(channelsPage.centerView.scheduledDraftChannelInfoMessageLocator, {state: 'hidden'});
|
||||
|
||||
// * Verify the message has been sent and there's no more scheduled messages
|
||||
await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
|
||||
await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
|
||||
await expect(await channelsPage.getLastPost()).toHaveText(draftMessage);
|
||||
|
||||
await channelsPage.sidebarLeft.assertNoPendingScheduledDraft();
|
||||
});
|
||||
|
||||
test('MM-T5648 should create a draft and then schedule it', async ({pw}) => {
|
||||
const draftMessage = 'Draft to be Scheduled';
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user, team} = await pw.initSetup();
|
||||
const {channelsPage, draftPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// await setupChannelPage(channelsPage, draftMessage);
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
await channelsPage.centerView.postCreate.writeMessage(draftMessage);
|
||||
|
||||
// go to drafts page
|
||||
await draftPage.goTo(team.name);
|
||||
await draftPage.toBeVisible();
|
||||
await draftPage.assertBadgeCountOnTab('1');
|
||||
await draftPage.assertDraftBody(draftMessage);
|
||||
await draftPage.verifyScheduleIcon(draftMessage);
|
||||
await draftPage.openScheduleModal(draftMessage);
|
||||
|
||||
// # Reschedule it to 2 days from today
|
||||
await channelsPage.scheduledDraftModal.selectDay(2);
|
||||
await channelsPage.scheduledDraftModal.confirm();
|
||||
|
||||
await scheduledDraftPage.goTo(team.name);
|
||||
await scheduledDraftPage.toBeVisible();
|
||||
await scheduledDraftPage.assertBadgeCountOnTab('1');
|
||||
await scheduledDraftPage.assertscheduledDraftBody(draftMessage);
|
||||
});
|
||||
|
||||
test('MM-T5644 should edit scheduled message', async ({pw}) => {
|
||||
const draftMessage = 'Scheduled Draft';
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await setupChannelPage(channelsPage, draftMessage);
|
||||
await scheduleMessage(channelsPage);
|
||||
|
||||
await channelsPage.centerView.verifyscheduledDraftChannelInfo();
|
||||
|
||||
const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
|
||||
await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
|
||||
|
||||
// # Hover and verify options
|
||||
await scheduledDraftPage.verifyOnHoverActionItems(draftMessage);
|
||||
|
||||
const updatedText = 'updated text';
|
||||
await scheduledDraftPage.editText(updatedText);
|
||||
|
||||
await scheduledDraftPage.sendScheduledMessage(updatedText);
|
||||
|
||||
// * Verify the message has been sent and there's no more scheduled messages
|
||||
await page.waitForSelector(channelsPage.centerView.scheduledDraftChannelInfoMessageLocator, {state: 'hidden'});
|
||||
await expect(channelsPage.centerView.scheduledDraftChannelInfoMessage).not.toBeVisible();
|
||||
await expect(channelsPage.sidebarLeft.scheduledDraftCountonLHS).not.toBeVisible();
|
||||
await expect(await channelsPage.getLastPost()).toHaveText(updatedText);
|
||||
|
||||
await channelsPage.sidebarLeft.assertNoPendingScheduledDraft();
|
||||
});
|
||||
|
||||
test('MM-T5650 should copy scheduled message', async ({pw, browserName}) => {
|
||||
// Skip this test in Firefox clipboard permissions are not supported
|
||||
test.skip(browserName === 'firefox', 'Test not supported in Firefox');
|
||||
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const draftMessage = 'Scheduled Draft';
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
const {page, channelsPage, scheduledDraftPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await setupChannelPage(channelsPage, draftMessage);
|
||||
await scheduleMessage(channelsPage);
|
||||
|
||||
await channelsPage.centerView.verifyscheduledDraftChannelInfo();
|
||||
|
||||
const postBoxIndicator = await channelsPage.centerView.scheduledDraftChannelInfoMessageText.innerText();
|
||||
|
||||
await verifyScheduledDraft(channelsPage, scheduledDraftPage, draftMessage, postBoxIndicator);
|
||||
|
||||
await scheduledDraftPage.copyScheduledMessage(draftMessage);
|
||||
|
||||
await page.goBack();
|
||||
|
||||
await channelsPage.centerView.postCreate.input.focus();
|
||||
|
||||
await page.keyboard.down('ControlOrMeta');
|
||||
await page.keyboard.press('V');
|
||||
await page.keyboard.up('ControlOrMeta');
|
||||
|
||||
// * Assert the message typed is same as the copied message
|
||||
await expect(channelsPage.centerView.postCreate.input).toHaveText(draftMessage);
|
||||
});
|
||||
|
||||
async function goBackToChannelAndWaitForMessageToArrive(pw: PlaywrightExtended, page: Page): Promise<void> {
|
||||
await page.goBack();
|
||||
await pw.wait(pw.duration.two_min);
|
||||
await page.reload();
|
||||
}
|
||||
|
||||
async function replyToLastPost(post: any): Promise<void> {
|
||||
await post.hover();
|
||||
await post.postMenu.toBeVisible();
|
||||
await post.postMenu.reply();
|
||||
}
|
||||
|
||||
async function setupChannelPage(
|
||||
channelsPage: ChannelsPage,
|
||||
draftMessage: string,
|
||||
teamName?: string,
|
||||
channelName?: string,
|
||||
): Promise<void> {
|
||||
await channelsPage.goto(teamName, channelName);
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
await channelsPage.centerView.postCreate.writeMessage(draftMessage);
|
||||
await channelsPage.centerView.postCreate.clickOnScheduleDraftDropdownButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a draft message by selecting a custom time and confirming.
|
||||
*/
|
||||
async function scheduleMessage(channelsPage: ChannelsPage): Promise<void> {
|
||||
await channelsPage.scheduledDraftDropdown.toBeVisible();
|
||||
await channelsPage.scheduledDraftDropdown.selectCustomTime();
|
||||
|
||||
await channelsPage.scheduledDraftModal.toBeVisible();
|
||||
await channelsPage.scheduledDraftModal.selectDay();
|
||||
await channelsPage.scheduledDraftModal.selectTime();
|
||||
await channelsPage.scheduledDraftModal.confirm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts and verifies the scheduled message on the scheduled page and in the channel.
|
||||
*/
|
||||
async function verifyScheduledDraft(
|
||||
channelsPage: ChannelsPage,
|
||||
scheduledDraftPage: ScheduledDraftPage,
|
||||
draftMessage: string,
|
||||
postBoxIndicator: string,
|
||||
): Promise<void> {
|
||||
await verifyscheduledDraftCount(channelsPage, '1');
|
||||
await scheduledDraftPage.toBeVisible();
|
||||
await scheduledDraftPage.assertBadgeCountOnTab('1');
|
||||
await scheduledDraftPage.assertscheduledDraftBody(draftMessage);
|
||||
|
||||
const scheduledDraftPageInfo = await scheduledDraftPage.getTimeStampOfMessage(draftMessage);
|
||||
await compareMessageTimestamps(postBoxIndicator, scheduledDraftPageInfo, scheduledDraftPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the scheduled message count on the sidebar.
|
||||
*/
|
||||
async function verifyscheduledDraftCount(page: ChannelsPage, expectedCount: string): Promise<void> {
|
||||
await page.centerView.clickOnSeeAllscheduledDrafts();
|
||||
await page.sidebarLeft.assertscheduledDraftCountLHS(expectedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the time in the channel and the scheduled page to ensure consistency.
|
||||
*/
|
||||
async function compareMessageTimestamps(
|
||||
timeInChannel: string,
|
||||
scheduledDraftPageInfo: string,
|
||||
scheduledDraftPage: ScheduledDraftPage,
|
||||
): Promise<void> {
|
||||
// Extract time from channel using the same date pattern
|
||||
const matchedTimeInChannel = timeInChannel.match(scheduledDraftPage.datePattern);
|
||||
const timeInSchedulePage = extractTimeFromHtml(scheduledDraftPageInfo, scheduledDraftPage);
|
||||
|
||||
if (!matchedTimeInChannel || !timeInSchedulePage) {
|
||||
throw new Error('Could not extract date and time from one or both elements.');
|
||||
}
|
||||
|
||||
const firstElementTime = matchedTimeInChannel[0];
|
||||
const secondElementTime = timeInSchedulePage[0];
|
||||
|
||||
// Compare extracted times
|
||||
expect(firstElementTime).toBe(secondElementTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes HTML tags from the scheduled message content and extracts the time pattern.
|
||||
*/
|
||||
function extractTimeFromHtml(htmlContent: string, scheduledDraftPage: ScheduledDraftPage): RegExpMatchArray | null {
|
||||
// Remove all HTML tags and match the expected time pattern using the datePattern from scheduledDraftPage
|
||||
const cleanedText = htmlContent.replace(/<\/?[^>]+(>|$)/g, '');
|
||||
|
||||
// Use the datePattern to extract the exact match for time
|
||||
const matchedTime = cleanedText.match(scheduledDraftPage.datePattern);
|
||||
return matchedTime;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T5424 Find channel search returns only 50 results when there are more than 50 channels with similar names', async ({
|
||||
pw,
|
||||
}) => {
|
||||
const {adminClient, user, team} = await pw.initSetup();
|
||||
|
||||
const commonName = 'test_channel';
|
||||
|
||||
// # Create more than 50 channels with similar names
|
||||
const channelsRes = [];
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let suffix = i.toString();
|
||||
if (i < 10) {
|
||||
suffix = `0${i}`;
|
||||
}
|
||||
const channel = pw.random.channel({
|
||||
teamId: team.id,
|
||||
name: `${commonName}_${suffix}`,
|
||||
displayName: `Test Channel ${suffix}`,
|
||||
});
|
||||
channelsRes.push(adminClient.createChannel(channel));
|
||||
}
|
||||
await Promise.all(channelsRes);
|
||||
|
||||
// # Log in a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit a default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Click on "Find channel" and type "test_channel"
|
||||
await channelsPage.sidebarLeft.findChannelButton.click();
|
||||
|
||||
await channelsPage.findChannelsModal.toBeVisible();
|
||||
await channelsPage.findChannelsModal.input.fill(commonName);
|
||||
|
||||
const limitCount = 50;
|
||||
|
||||
// # Only 50 results for similar name should be displayed.
|
||||
await expect(channelsPage.findChannelsModal.searchList).toHaveCount(limitCount);
|
||||
|
||||
for (let i = 0; i < limitCount; i++) {
|
||||
let suffix = i.toString();
|
||||
if (i < 10) {
|
||||
suffix = `0${i}`;
|
||||
}
|
||||
|
||||
await expect(channelsPage.findChannelsModal.container.getByTestId(`${commonName}_${suffix}`)).toBeVisible();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('Search box suggestion must be case insensitive', async ({pw}) => {
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit a default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Open the search UI
|
||||
await channelsPage.globalHeader.openSearch();
|
||||
|
||||
const searchWord = 'off';
|
||||
const searchOutput = 'In:off-topic';
|
||||
const channelName = 'Off-Topic';
|
||||
|
||||
// Should work as expected when using lowercase
|
||||
// # Type in lowercase "off" to search for the "Off-Topic" channel
|
||||
const {searchInput} = channelsPage.searchPopover;
|
||||
await searchInput.pressSequentially(`In:${searchWord}`);
|
||||
|
||||
// * The suggestion should be visible
|
||||
await expect(channelsPage.searchPopover.selectedSuggestion).toBeVisible();
|
||||
await expect(channelsPage.searchPopover.selectedSuggestion).toHaveText(channelName);
|
||||
|
||||
// # Press Enter to select the suggestion and another Enter to search
|
||||
await searchInput.press('Enter');
|
||||
await searchInput.press('Enter');
|
||||
|
||||
// * The search box should contain the selected suggestion
|
||||
await expect(channelsPage.globalHeader.searchBox.getByText(searchOutput, {exact: true})).toBeVisible();
|
||||
|
||||
// Should work as expected when using uppercase
|
||||
// # Open the search bar
|
||||
await channelsPage.globalHeader.openSearch();
|
||||
|
||||
// # Clear its content
|
||||
await channelsPage.searchPopover.clearIfPossible();
|
||||
|
||||
// # Type in uppercase "OFF" to search for the "Off-Topic" channel
|
||||
await searchInput.pressSequentially(`In:${searchWord.toUpperCase()}`);
|
||||
|
||||
// * The suggestion should be visible
|
||||
await expect(channelsPage.searchPopover.selectedSuggestion).toBeVisible();
|
||||
await expect(channelsPage.searchPopover.selectedSuggestion).toHaveText(channelName);
|
||||
|
||||
// # Press Enter to select the suggestion and another Enter to search
|
||||
await searchInput.press('Enter');
|
||||
await searchInput.press('Enter');
|
||||
|
||||
// * The search box should contain the selected suggestion
|
||||
await expect(channelsPage.globalHeader.searchBox.getByText(searchOutput, {exact: true})).toBeVisible();
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('team selector must show all my teams', async ({pw}) => {
|
||||
const {adminClient, user, team} = await pw.initSetup();
|
||||
|
||||
// # create 2 more teams and add the user to them
|
||||
const teams = [team];
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const newTeam = await adminClient.createTeam(pw.random.team('team', 'Team', 'O', true));
|
||||
await adminClient.addUsersToTeam(newTeam.id, [user.id]);
|
||||
teams.push(newTeam);
|
||||
}
|
||||
|
||||
// # Log in a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit a default channel page
|
||||
await channelsPage.goto(team.name);
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Open the search UI
|
||||
await channelsPage.globalHeader.openSearch();
|
||||
|
||||
// * Check that the team selector is visible
|
||||
const page = channelsPage.page;
|
||||
await expect(page.getByTestId('searchTeamsSelectorMenuButton')).toBeVisible();
|
||||
|
||||
// # Click on the team selector
|
||||
await page.getByTestId('searchTeamsSelectorMenuButton').click();
|
||||
|
||||
// * Check that the team selector is visible
|
||||
const teamSelector = page.getByRole('menu', {name: 'Select team'});
|
||||
await expect(teamSelector).toBeVisible();
|
||||
// * Check that the team selector has the 3 teams
|
||||
teams.forEach(async (t) => {
|
||||
await expect(teamSelector.getByText(t.display_name)).toBeVisible();
|
||||
});
|
||||
// * Check that All teams is also visible
|
||||
await expect(teamSelector.getByText('All teams')).toBeVisible();
|
||||
// * No <input> should be visible in the menu
|
||||
await expect(teamSelector.getByLabel('Search teams')).not.toBeVisible();
|
||||
|
||||
// now create and join 3 more teams
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const newTeam = await adminClient.createTeam(pw.random.team('team', 'Team', 'O', true));
|
||||
await adminClient.addUsersToTeam(newTeam.id, [user.id]);
|
||||
teams.push(newTeam);
|
||||
}
|
||||
|
||||
// refresh the page
|
||||
await channelsPage.goto(team.name);
|
||||
|
||||
// # Open the search UI
|
||||
await channelsPage.globalHeader.openSearch();
|
||||
|
||||
// # Click on the team selector
|
||||
await page.getByTestId('searchTeamsSelectorMenuButton').click();
|
||||
|
||||
// * Check that the team selector is visible
|
||||
await expect(teamSelector).toBeVisible();
|
||||
// * Check that the team selector has the 6 teams
|
||||
teams.forEach(async (t) => {
|
||||
await expect(teamSelector.getByText(t.display_name)).toBeVisible();
|
||||
});
|
||||
// * Check that All teams is also visible
|
||||
await expect(teamSelector.getByText('All teams')).toBeVisible();
|
||||
|
||||
// because there's more than 4 teams, the filter input should be visible
|
||||
await expect(teamSelector.getByLabel('Search teams')).toBeVisible();
|
||||
|
||||
// # Type the name of the first team
|
||||
await page.getByLabel('Search teams').fill(teams[3].display_name);
|
||||
|
||||
// * Check that the team selector is visible
|
||||
await expect(teamSelector).toBeVisible();
|
||||
|
||||
// * Noew team [0] and [3] should be visible - 0 is visible because it was currently selected.
|
||||
await expect(teamSelector.getByText(teams[0].display_name)).toBeVisible();
|
||||
await expect(teamSelector.getByText(teams[3].display_name)).toBeVisible();
|
||||
// * Check that All teams is also visible
|
||||
await expect(teamSelector.getByText('All teams')).toBeVisible();
|
||||
// * Check that the other teams are not visible
|
||||
teams.slice(1, 3).forEach(async (t) => {
|
||||
await expect(teamSelector.getByText(t.display_name)).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,279 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
let keywords: string[];
|
||||
const highlightWithoutNotificationClass = 'non-notification-highlight';
|
||||
|
||||
test.beforeAll(async ({pw}) => {
|
||||
keywords = [`AB${pw.random.id()}`, `CD${pw.random.id()}`, `EF${pw.random.id()}`, `Highlight me ${pw.random.id()}`];
|
||||
});
|
||||
|
||||
test('MM-T5465-1 Should add the keyword when enter, comma or tab is pressed on the textbox', async ({pw}) => {
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
await channelsPage.centerView.postCreate.postMessage('Hello World');
|
||||
|
||||
// # Open settings modal
|
||||
await channelsPage.globalHeader.openSettings();
|
||||
await channelsPage.settingsModal.toBeVisible();
|
||||
|
||||
// # Open notifications tab
|
||||
await channelsPage.settingsModal.openNotificationsTab();
|
||||
|
||||
// # Open keywords that get highlighted section
|
||||
await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||
|
||||
const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||
|
||||
// # Enter keyword 1
|
||||
await keywordsInput.fill(keywords[0]);
|
||||
|
||||
// # Press Comma on the textbox
|
||||
await keywordsInput.press(',');
|
||||
|
||||
// # Enter keyword 2
|
||||
await keywordsInput.fill(keywords[1]);
|
||||
|
||||
// # Press Tab on the textbox
|
||||
await keywordsInput.press('Tab');
|
||||
|
||||
// # Enter keyword 3
|
||||
await keywordsInput.fill(keywords[2]);
|
||||
|
||||
// # Press Enter on the textbox
|
||||
await keywordsInput.press('Enter');
|
||||
|
||||
// * Verify that the keywords have been added to the collapsed description
|
||||
const keysWithHighlightDesc = channelsPage.settingsModal.notificationsSettings.keysWithHighlightDesc;
|
||||
await keysWithHighlightDesc.waitFor();
|
||||
for (const keyword of keywords.slice(0, 3)) {
|
||||
expect(await keysWithHighlightDesc).toContainText(keyword);
|
||||
}
|
||||
});
|
||||
|
||||
test('MM-T5465-2 Should highlight the keywords when a message is sent with the keyword in center', async ({pw}) => {
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Open settings modal
|
||||
await channelsPage.globalHeader.openSettings();
|
||||
await channelsPage.settingsModal.toBeVisible();
|
||||
|
||||
// # Open notifications tab
|
||||
await channelsPage.settingsModal.openNotificationsTab();
|
||||
|
||||
// # Open keywords that get highlighted section
|
||||
await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||
|
||||
// # Enter the keyword
|
||||
const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||
await keywordsInput.fill(keywords[3]);
|
||||
await keywordsInput.press('Tab');
|
||||
|
||||
// # Save the keyword
|
||||
await channelsPage.settingsModal.notificationsSettings.save();
|
||||
|
||||
// # Close the settings modal
|
||||
await channelsPage.settingsModal.closeModal();
|
||||
|
||||
// # Post a message without the keyword
|
||||
const messageWithoutKeyword = 'This message does not contain the keyword';
|
||||
await channelsPage.centerView.postCreate.postMessage(messageWithoutKeyword);
|
||||
const lastPostWithoutHighlight = await channelsPage.centerView.getLastPost();
|
||||
|
||||
// * Verify that the keywords are not highlighted
|
||||
await expect(lastPostWithoutHighlight.container.getByText(messageWithoutKeyword)).toBeVisible();
|
||||
await expect(lastPostWithoutHighlight.container.getByText(messageWithoutKeyword)).not.toHaveClass(
|
||||
highlightWithoutNotificationClass,
|
||||
);
|
||||
|
||||
// # Post a message with the keyword
|
||||
const messageWithKeyword = `This message contains the keyword ${keywords[3]}`;
|
||||
await channelsPage.centerView.postCreate.postMessage(messageWithKeyword);
|
||||
const lastPostWithHighlight = await channelsPage.centerView.getLastPost();
|
||||
|
||||
// * Verify that the keywords are highlighted
|
||||
await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible();
|
||||
await expect(lastPostWithHighlight.container.getByText(keywords[3])).toHaveClass(highlightWithoutNotificationClass);
|
||||
});
|
||||
|
||||
test('MM-T5465-3 Should highlight the keywords when a message is sent with the keyword in rhs', async ({pw}) => {
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Open settings modal
|
||||
await channelsPage.globalHeader.openSettings();
|
||||
await channelsPage.settingsModal.toBeVisible();
|
||||
|
||||
// # Open notifications tab
|
||||
await channelsPage.settingsModal.openNotificationsTab();
|
||||
|
||||
// # Open keywords that get highlighted section
|
||||
await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||
|
||||
// # Enter the keyword
|
||||
const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||
await keywordsInput.fill(keywords[3]);
|
||||
await keywordsInput.press('Tab');
|
||||
|
||||
// # Save the keyword
|
||||
await channelsPage.settingsModal.notificationsSettings.save();
|
||||
|
||||
// # Close the settings modal
|
||||
await channelsPage.settingsModal.closeModal();
|
||||
|
||||
// # Post a message without the keyword
|
||||
const messageWithoutKeyword = 'This message does not contain the keyword';
|
||||
await channelsPage.centerView.postCreate.postMessage(messageWithoutKeyword);
|
||||
const lastPostWithoutHighlight = await channelsPage.centerView.getLastPost();
|
||||
|
||||
// # Open the message in the RHS
|
||||
await lastPostWithoutHighlight.hover();
|
||||
await lastPostWithoutHighlight.postMenu.toBeVisible();
|
||||
await lastPostWithoutHighlight.postMenu.reply();
|
||||
await channelsPage.sidebarRight.toBeVisible();
|
||||
|
||||
// # Post a message with the keyword in the RHS
|
||||
const messageWithKeyword = `This message contains the keyword ${keywords[3]}`;
|
||||
await channelsPage.sidebarRight.postCreate.postMessage(messageWithKeyword);
|
||||
|
||||
// * Verify that the keywords are highlighted
|
||||
const lastPostWithHighlightInRHS = await channelsPage.sidebarRight.getLastPost();
|
||||
await expect(lastPostWithHighlightInRHS.container.getByText(messageWithKeyword)).toBeVisible();
|
||||
await expect(lastPostWithHighlightInRHS.container.getByText(keywords[3])).toHaveClass(
|
||||
highlightWithoutNotificationClass,
|
||||
);
|
||||
});
|
||||
|
||||
test('MM-T5465-4 Highlighted keywords should not appear in the Recent Mentions', async ({pw}) => {
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {user} = await pw.initSetup();
|
||||
|
||||
// # Log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Open settings modal
|
||||
await channelsPage.globalHeader.openSettings();
|
||||
await channelsPage.settingsModal.toBeVisible();
|
||||
|
||||
// # Open notifications tab
|
||||
await channelsPage.settingsModal.openNotificationsTab();
|
||||
|
||||
// # Open keywords that get highlighted section
|
||||
await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||
|
||||
// # Enter the keyword
|
||||
const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||
await keywordsInput.fill(keywords[0]);
|
||||
await keywordsInput.press('Tab');
|
||||
|
||||
// # Save the keyword
|
||||
await channelsPage.settingsModal.notificationsSettings.save();
|
||||
|
||||
// # Close the settings modal
|
||||
await channelsPage.settingsModal.closeModal();
|
||||
|
||||
// # Open the recent mentions
|
||||
await channelsPage.globalHeader.openRecentMentions();
|
||||
|
||||
// * Verify recent mentions is empty
|
||||
await channelsPage.sidebarRight.toBeVisible();
|
||||
await expect(channelsPage.sidebarRight.container.getByText('No mentions yet')).toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5465-5 Should highlight keywords in message sent from another user', async ({pw}) => {
|
||||
// # Skip test if no license
|
||||
await pw.skipIfNoLicense();
|
||||
|
||||
const {adminClient, team, adminUser, user} = await pw.initSetup();
|
||||
|
||||
if (!adminUser) {
|
||||
throw new Error('Failed to create admin user');
|
||||
}
|
||||
|
||||
// # Get the default channel of the team for getting the channel id
|
||||
const channel = await adminClient.getChannelByName(team.id, 'town-square');
|
||||
|
||||
const highlightKeyword = keywords[0];
|
||||
const messageWithKeyword = `This received message contains the ${highlightKeyword} keyword `;
|
||||
|
||||
// # Create a post containing the keyword in the channel by admin
|
||||
await adminClient.createPost(
|
||||
pw.random.post({
|
||||
message: messageWithKeyword,
|
||||
channel_id: channel.id,
|
||||
user_id: adminUser.id,
|
||||
}),
|
||||
);
|
||||
|
||||
// # Now log in as a user in new browser context
|
||||
const {channelsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
// # Visit default channel page
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Open settings modal
|
||||
await channelsPage.globalHeader.openSettings();
|
||||
await channelsPage.settingsModal.toBeVisible();
|
||||
|
||||
// # Open notifications tab
|
||||
await channelsPage.settingsModal.openNotificationsTab();
|
||||
|
||||
// # Open keywords that get highlighted section
|
||||
await channelsPage.settingsModal.notificationsSettings.expandSection('keysWithHighlight');
|
||||
|
||||
// # Enter the keyword
|
||||
const keywordsInput = await channelsPage.settingsModal.notificationsSettings.getKeywordsInput();
|
||||
await keywordsInput.fill(keywords[0]);
|
||||
await keywordsInput.press('Tab');
|
||||
|
||||
// # Save the keyword
|
||||
await channelsPage.settingsModal.notificationsSettings.save();
|
||||
|
||||
// # Close the settings modal
|
||||
await channelsPage.settingsModal.closeModal();
|
||||
|
||||
// * Verify that the keywords are highlighted in the last message received
|
||||
const lastPostWithHighlight = await channelsPage.centerView.getLastPost();
|
||||
await expect(lastPostWithHighlight.container.getByText(messageWithKeyword)).toBeVisible();
|
||||
await expect(lastPostWithHighlight.container.getByText(highlightKeyword)).toHaveClass(
|
||||
highlightWithoutNotificationClass,
|
||||
);
|
||||
});
|
||||
Ссылка в новой задаче
Block a user