diff --git a/e2e-tests/playwright/support/ui/components/channels/post_create.ts b/e2e-tests/playwright/support/ui/components/channels/post_create.ts
index b43a213e91..82299d903d 100644
--- a/e2e-tests/playwright/support/ui/components/channels/post_create.ts
+++ b/e2e-tests/playwright/support/ui/components/channels/post_create.ts
@@ -20,7 +20,7 @@ export default class ChannelsPostCreate {
this.sendMessageButton = container.getByTestId('SendMessageButton');
}
- async postMessage(message: string) {
+ async writeMessage(message: string) {
await this.input.fill(message);
}
diff --git a/e2e-tests/playwright/support/ui/components/channels/post_dot_menu.ts b/e2e-tests/playwright/support/ui/components/channels/post_dot_menu.ts
index 600aaef636..ca95324777 100644
--- a/e2e-tests/playwright/support/ui/components/channels/post_dot_menu.ts
+++ b/e2e-tests/playwright/support/ui/components/channels/post_dot_menu.ts
@@ -6,22 +6,43 @@ import {expect, Locator} from '@playwright/test';
export default class PostDotMenu {
readonly container: Locator;
+ readonly replyMenuItem;
+ readonly forwardMenuItem;
+ readonly followMessageMenuItem;
+ readonly markAsUnreadMenuItem;
+ readonly remindMenuItem;
+ readonly saveMenuItem;
+ readonly removeFromSavedMenuItem;
+ readonly pinToChannelMenuItem;
+ readonly unpinFromChannelMenuItem;
+ readonly copyLinkMenuItem;
+ readonly editMenuItem;
+ readonly copyTextMenuItem;
readonly deleteMenuItem;
constructor(container: Locator) {
this.container = container;
- this.deleteMenuItem = this.container.getByText('Delete', {exact: true});
+ const getMenuItem = (hasText: string) => container.getByRole('menuitem').filter({hasText});
+
+ this.replyMenuItem = getMenuItem('Reply');
+ this.forwardMenuItem = getMenuItem('Forward');
+ this.followMessageMenuItem = getMenuItem('Follow message');
+ this.markAsUnreadMenuItem = getMenuItem('Mark as Unread');
+ this.remindMenuItem = getMenuItem('Remind');
+ this.saveMenuItem = getMenuItem('Save');
+ this.removeFromSavedMenuItem = getMenuItem('Remove from Saved');
+ this.pinToChannelMenuItem = getMenuItem('Pin to Channel');
+ this.unpinFromChannelMenuItem = getMenuItem('Unpin from Channel');
+ this.copyLinkMenuItem = getMenuItem('Copy Link');
+ this.editMenuItem = getMenuItem('Edit');
+ this.copyTextMenuItem = getMenuItem('Copy Text');
+ this.deleteMenuItem = getMenuItem('Delete');
}
async toBeVisible() {
await expect(this.container).toBeVisible();
}
-
- async delete() {
- await this.deleteMenuItem.waitFor();
- await this.deleteMenuItem.click();
- }
}
export {PostDotMenu};
diff --git a/e2e-tests/playwright/support/ui/components/channels/post_menu.ts b/e2e-tests/playwright/support/ui/components/channels/post_menu.ts
index ba97b07b66..6e28058308 100644
--- a/e2e-tests/playwright/support/ui/components/channels/post_menu.ts
+++ b/e2e-tests/playwright/support/ui/components/channels/post_menu.ts
@@ -6,12 +6,24 @@ import {expect, Locator} from '@playwright/test';
export default class PostMenu {
readonly container: Locator;
+ readonly plusOneEmojiButton;
+ readonly grinningEmojiButton;
+ readonly whiteCheckMarkEmojiButton;
+ readonly addReactionButton;
+ readonly saveButton;
readonly replyButton;
+ readonly actionsButton;
readonly dotMenuButton;
constructor(container: Locator) {
this.container = container;
+ this.plusOneEmojiButton = container.getByRole('button', {name: '+1 emoji'});
+ this.grinningEmojiButton = container.getByRole('button', {name: 'grinning emoji'});
+ this.whiteCheckMarkEmojiButton = container.getByRole('button', {name: 'white check mark emoji'});
+ this.addReactionButton = container.getByRole('button', {name: 'add reaction'});
+ this.saveButton = container.getByRole('button', {name: 'save'});
+ this.actionsButton = container.getByRole('button', {name: 'actions'});
this.replyButton = container.getByRole('button', {name: 'reply'});
this.dotMenuButton = container.getByRole('button', {name: 'more'});
}
diff --git a/e2e-tests/playwright/support/ui/components/channels/post_reminder_menu.ts b/e2e-tests/playwright/support/ui/components/channels/post_reminder_menu.ts
new file mode 100644
index 0000000000..08e3e53f33
--- /dev/null
+++ b/e2e-tests/playwright/support/ui/components/channels/post_reminder_menu.ts
@@ -0,0 +1,32 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {expect, Locator} from '@playwright/test';
+
+export default class PostReminderMenu {
+ readonly container: Locator;
+
+ readonly thirtyMinsMenuItem;
+ readonly oneHourMenuItem;
+ readonly twoHoursMenuItem;
+ readonly tomorrowMenuItem;
+ readonly customMenuItem;
+
+ constructor(container: Locator) {
+ this.container = container;
+
+ const getMenuItem = (hasText: string) => container.getByRole('menuitem').filter({hasText});
+
+ this.thirtyMinsMenuItem = getMenuItem('30 mins');
+ this.oneHourMenuItem = getMenuItem('1 hour');
+ this.twoHoursMenuItem = getMenuItem('2 hours');
+ this.tomorrowMenuItem = getMenuItem('Tomorrow');
+ this.customMenuItem = getMenuItem('Custom');
+ }
+
+ async toBeVisible() {
+ await expect(this.container).toBeVisible();
+ }
+}
+
+export {PostReminderMenu};
diff --git a/e2e-tests/playwright/support/ui/components/channels/sidebar_right.ts b/e2e-tests/playwright/support/ui/components/channels/sidebar_right.ts
index 852d94d6e1..fd1f3586bd 100644
--- a/e2e-tests/playwright/support/ui/components/channels/sidebar_right.ts
+++ b/e2e-tests/playwright/support/ui/components/channels/sidebar_right.ts
@@ -26,6 +26,11 @@ export default class ChannelsSidebarRight {
}
async postMessage(message: string) {
+ await this.writeMessage(message);
+ await this.sendMessage();
+ }
+
+ async writeMessage(message: string) {
await this.input.fill(message);
}
diff --git a/e2e-tests/playwright/support/ui/components/index.ts b/e2e-tests/playwright/support/ui/components/index.ts
index 806c21aaec..a1b86de033 100644
--- a/e2e-tests/playwright/support/ui/components/index.ts
+++ b/e2e-tests/playwright/support/ui/components/index.ts
@@ -9,12 +9,13 @@ import {ChannelsPostCreate} from './channels/post_create';
import {ChannelsPost} from './channels/post';
import {ChannelsSidebarLeft} from './channels/sidebar_left';
import {ChannelsSidebarRight} from './channels/sidebar_right';
+import {DeletePostModal} from './channels/delete_post_modal';
import {FindChannelsModal} from './channels/find_channels_modal';
import {Footer} from './footer';
import {GlobalHeader} from './global_header';
import {MainHeader} from './main_header';
import {PostDotMenu} from './channels/post_dot_menu';
-import {DeletePostModal} from './channels/delete_post_modal';
+import {PostReminderMenu} from './channels/post_reminder_menu';
import {PostMenu} from './channels/post_menu';
import {ThreadFooter} from './channels/thread_footer';
@@ -27,12 +28,13 @@ const components = {
ChannelsPost,
ChannelsSidebarLeft,
ChannelsSidebarRight,
+ DeletePostModal,
FindChannelsModal,
Footer,
GlobalHeader,
MainHeader,
PostDotMenu,
- DeletePostModal,
+ PostReminderMenu,
PostMenu,
ThreadFooter,
};
diff --git a/e2e-tests/playwright/support/ui/pages/channels.ts b/e2e-tests/playwright/support/ui/pages/channels.ts
index 5ec00ae40b..c96a841ea3 100644
--- a/e2e-tests/playwright/support/ui/pages/channels.ts
+++ b/e2e-tests/playwright/support/ui/pages/channels.ts
@@ -19,6 +19,7 @@ export default class ChannelsPage {
readonly sidebarLeft;
readonly sidebarRight;
readonly postDotMenu;
+ readonly postReminderMenu;
readonly deletePostModal;
constructor(page: Page) {
@@ -32,6 +33,7 @@ export default class ChannelsPage {
this.sidebarLeft = new components.ChannelsSidebarLeft(page.locator('#SidebarContainer'));
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
this.postDotMenu = new components.PostDotMenu(page.getByRole('menu', {name: 'Post extra options'}));
+ this.postReminderMenu = new components.PostReminderMenu(page.getByRole('menu', {name: 'Set a reminder for:'}));
this.deletePostModal = new components.DeletePostModal(page.locator('#deletePostModal'));
}
@@ -55,8 +57,13 @@ export default class ChannelsPage {
}
async postMessage(message: string) {
+ await this.writeMessage(message);
+ await this.sendMessage();
+ }
+
+ async writeMessage(message: string) {
await this.postCreate.input.waitFor();
- await this.postCreate.postMessage(message);
+ await this.postCreate.writeMessage(message);
}
async sendMessage() {
diff --git a/e2e-tests/playwright/tests/accessibility/channels/intro_channel.spec.ts b/e2e-tests/playwright/tests/accessibility/channels/intro_channel.spec.ts
index a8ce81c196..9ecfe64cd4 100644
--- a/e2e-tests/playwright/tests/accessibility/channels/intro_channel.spec.ts
+++ b/e2e-tests/playwright/tests/accessibility/channels/intro_channel.spec.ts
@@ -3,19 +3,18 @@
import {expect, test} from '@e2e-support/test_fixture';
-test('Intro to channel', async ({pw, pages, axe}) => {
- // Create and sign in a new user
+test('Base channel accessibility', async ({pw, pages, axe}) => {
+ // # Create and sign in a new user
const {user} = await pw.initSetup();
- // Log in a user in new browser context
+ // # Log in a user in new browser context
const {page} = await pw.testBrowser.login(user);
- // Visit a default channel page
+ // # Visit a default channel page
const channelsPage = new pages.ChannelsPage(page);
await channelsPage.goto();
await channelsPage.toBeVisible();
await channelsPage.postMessage('hello');
- await channelsPage.sendMessage();
// # Analyze the page
// Disable 'color-contrast' to be addressed by MM-53814
@@ -24,3 +23,136 @@ test('Intro to channel', async ({pw, pages, axe}) => {
// * Should have no violation
expect(accessibilityScanResults.violations).toHaveLength(0);
});
+
+test('Post actions tab support', async ({pw, pages, axe}) => {
+ // # Create and sign in a new user
+ const {user} = await pw.initSetup();
+
+ // # Log in a user in new browser context
+ const {page} = await pw.testBrowser.login(user);
+
+ // # Visit a default channel page
+ const channelsPage = new pages.ChannelsPage(page);
+ await channelsPage.goto();
+ await channelsPage.toBeVisible();
+ await channelsPage.postMessage('hello');
+
+ const post = await channelsPage.getLastPost();
+ await post.hover();
+ await post.postMenu.toBeVisible();
+
+ // # Open the dot menu
+ await post.postMenu.dotMenuButton.click();
+
+ // * Dot menu should be visible and have focused
+ await channelsPage.postDotMenu.toBeVisible();
+ await expect(channelsPage.postDotMenu.container).toBeFocused();
+
+ // # Analyze the page
+ const accessibilityScanResults = await axe
+ .builder(page, {disableColorContrast: true})
+ .include('.MuiMenu-list')
+ .analyze();
+
+ // * Should have no violation
+ expect(accessibilityScanResults.violations).toHaveLength(0);
+
+ // * Should move focus to Reply after arrow down
+ await channelsPage.postDotMenu.container.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.replyMenuItem).toBeFocused();
+
+ // * Should move focus to Forward after arrow down
+ await channelsPage.postDotMenu.replyMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.forwardMenuItem).toBeFocused();
+
+ // * Should move focus to Follow message after arrow down
+ await channelsPage.postDotMenu.forwardMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.followMessageMenuItem).toBeFocused();
+
+ // * Should move focus to Mark as Unread after arrow down
+ await channelsPage.postDotMenu.followMessageMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.markAsUnreadMenuItem).toBeFocused();
+
+ // * Should move focus to Remind after arrow down
+ await channelsPage.postDotMenu.markAsUnreadMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.remindMenuItem).toBeFocused();
+
+ // * Should move focus to Save after arrow down
+ await channelsPage.postDotMenu.remindMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.saveMenuItem).toBeFocused();
+
+ // * Should move focus to Pin to Channel after arrow down
+ await channelsPage.postDotMenu.saveMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.pinToChannelMenuItem).toBeFocused();
+
+ // * Should move focus to Copy Link after arrow down
+ await channelsPage.postDotMenu.pinToChannelMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.copyLinkMenuItem).toBeFocused();
+
+ // * Should move focus to Edit after arrow down
+ await channelsPage.postDotMenu.copyLinkMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.editMenuItem).toBeFocused();
+
+ // * Should move focus to Copy Text after arrow down
+ await channelsPage.postDotMenu.editMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.copyTextMenuItem).toBeFocused();
+
+ // * Should move focus to Delete after arrow down
+ await channelsPage.postDotMenu.copyTextMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.deleteMenuItem).toBeFocused();
+
+ // * Then, should move focus back to Reply after arrow down
+ await channelsPage.postDotMenu.deleteMenuItem.press('ArrowDown');
+ await expect(channelsPage.postDotMenu.replyMenuItem).toBeFocused();
+
+ // * Should move focus to Delete after arrow uo
+ await channelsPage.postDotMenu.container.press('ArrowUp');
+ expect(await channelsPage.postDotMenu.deleteMenuItem).toBeFocused();
+
+ // # Set focus to Remind
+ await channelsPage.postDotMenu.remindMenuItem.focus();
+ await expect(channelsPage.postDotMenu.remindMenuItem).toBeFocused();
+
+ // * Reminder menu should still be hidden
+ await expect(channelsPage.postReminderMenu.container).toBeHidden();
+
+ // # Press arrow right
+ await channelsPage.postDotMenu.remindMenuItem.press('ArrowRight');
+
+ // * Reminder menu should be visible and have focused
+ channelsPage.postReminderMenu.toBeVisible();
+ await expect(channelsPage.postReminderMenu.container).toBeFocused();
+
+ // * Should move focus to 30 mins after arrow down
+ await channelsPage.postReminderMenu.container.press('ArrowDown');
+ expect(await channelsPage.postReminderMenu.thirtyMinsMenuItem).toBeFocused();
+
+ // * Should move focus to 1 hour after arrow down
+ await channelsPage.postReminderMenu.thirtyMinsMenuItem.press('ArrowDown');
+ expect(await channelsPage.postReminderMenu.oneHourMenuItem).toBeFocused();
+
+ // * Should move focus to 2 hours after arrow down
+ await channelsPage.postReminderMenu.oneHourMenuItem.press('ArrowDown');
+ expect(await channelsPage.postReminderMenu.twoHoursMenuItem).toBeFocused();
+
+ // * Should move focus to Tomorrow after arrow down
+ await channelsPage.postReminderMenu.twoHoursMenuItem.press('ArrowDown');
+ expect(await channelsPage.postReminderMenu.tomorrowMenuItem).toBeFocused();
+
+ // * Should move focus to Custom after arrow down
+ await channelsPage.postReminderMenu.tomorrowMenuItem.press('ArrowDown');
+ expect(await channelsPage.postReminderMenu.customMenuItem).toBeFocused();
+
+ // * Then, should move focus back to 30 mins after arrow down
+ await channelsPage.postReminderMenu.customMenuItem.press('ArrowDown');
+ expect(await channelsPage.postReminderMenu.thirtyMinsMenuItem).toBeFocused();
+
+ // * Should hide Reminder menu and focus to Remind menu after arrow left
+ await channelsPage.postReminderMenu.container.press('ArrowLeft');
+ await expect(channelsPage.postReminderMenu.container).toBeHidden();
+ await expect(channelsPage.postDotMenu.remindMenuItem).toBeFocused();
+
+ // * Should hide Dot menu of Escape
+ await channelsPage.postDotMenu.container.press('Escape');
+ await expect(channelsPage.postDotMenu.container).toBeHidden();
+});
diff --git a/e2e-tests/playwright/tests/functional/channels/drafts/drafts_on_deleted_message.spec.ts b/e2e-tests/playwright/tests/functional/channels/drafts/drafts_on_deleted_message.spec.ts
index 77a642252e..0ad7e9dbba 100644
--- a/e2e-tests/playwright/tests/functional/channels/drafts/drafts_on_deleted_message.spec.ts
+++ b/e2e-tests/playwright/tests/functional/channels/drafts/drafts_on_deleted_message.spec.ts
@@ -41,15 +41,14 @@ test('MM-T5435_1 Global Drafts link in sidebar should be hidden when another use
await lastPostByAdmin.postMenu.toBeVisible();
await lastPostByAdmin.postMenu.reply();
- // # Write a message as a user
+ // # Post a message as a user
const sidebarRight = channelPage.sidebarRight;
await sidebarRight.toBeVisible();
await sidebarRight.postMessage('Replying to a thread');
- await sidebarRight.sendMessage();
// # 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.postMessage(draftMessageByUser);
+ await sidebarRight.writeMessage(draftMessageByUser);
// # Close the RHS for draft to be saved
await sidebarRight.close();
@@ -92,7 +91,6 @@ test('MM-T5435_2 Global Drafts link in sidebar should be hidden when user delete
// # Post a message in the channel
await channelPage.postMessage('Message which will be deleted');
- await channelPage.sendMessage();
// # Start a thread by clicking on reply menuitem from post options menu
const post = await channelPage.getLastPost();
@@ -103,12 +101,11 @@ test('MM-T5435_2 Global Drafts link in sidebar should be hidden when user delete
const sidebarRight = channelPage.sidebarRight;
await sidebarRight.toBeVisible();
- // # Write a message in the thread
+ // # Post a message in the thread
await sidebarRight.postMessage('Replying to a thread');
- await sidebarRight.sendMessage();
// # Write a message in the reply thread but don't send it
- await sidebarRight.postMessage('I should be in drafts');
+ await sidebarRight.writeMessage('I should be in drafts');
// # Close the RHS for draft to be saved
await sidebarRight.close();
@@ -121,7 +118,7 @@ test('MM-T5435_2 Global Drafts link in sidebar should be hidden when user delete
await post.postMenu.toBeVisible();
await post.postMenu.openDotMenu();
await channelPage.postDotMenu.toBeVisible();
- await channelPage.postDotMenu.delete();
+ await channelPage.postDotMenu.deleteMenuItem.click();
// # Confirm the delete from the modal
await channelPage.deletePostModal.toBeVisible();
diff --git a/e2e-tests/playwright/tests/visual/channels/intro_channel.spec.ts b/e2e-tests/playwright/tests/visual/channels/intro_channel.spec.ts
index 86ebf18acc..86fd10ef54 100644
--- a/e2e-tests/playwright/tests/visual/channels/intro_channel.spec.ts
+++ b/e2e-tests/playwright/tests/visual/channels/intro_channel.spec.ts
@@ -2,7 +2,6 @@
// See LICENSE.txt for license information.
import {expect, test} from '@e2e-support/test_fixture';
-import {duration, wait} from '@e2e-support/util';
test('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => {
// Create and sign in a new user
@@ -17,9 +16,10 @@ test('Intro to channel as regular user', async ({pw, pages, browserName, viewpor
await channelsPage.toBeVisible();
// Wait for Boards' bot image to be loaded
- const boardsWelcomePost = await channelsPage.getFirstPost();
- await expect(await boardsWelcomePost.getProfileImage('boards')).toBeVisible();
- await wait(duration.one_sec);
+ // await pw.shouldHaveFeatureFlag('OnboardingAutoShowLinkedBoard', true);
+ // const boardsWelcomePost = await channelsPage.getFirstPost();
+ // await expect(await boardsWelcomePost.getProfileImage('boards')).toBeVisible();
+ // await wait(duration.one_sec);
// Wait for Playbooks icon to be loaded in App bar, except in iphone
if (!pw.isSmallScreen()) {
diff --git a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap
index 0df7a1dd84..1d6fe94b37 100644
--- a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap
+++ b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap
@@ -184,15 +184,6 @@ exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
/>
}
/>
-