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
Этот коммит содержится в:
Saturnino Abril
2025-04-07 22:26:29 +08:00
коммит произвёл GitHub
родитель 62753a1481
Коммит a35a6d7a3a
80 изменённых файлов: 165 добавлений и 154 удалений

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

@@ -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,
);
});