mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
MM-53999 Fix keyboard support for Menu components (#24282)
* Cherry-pick test changes from #24243 * Add required change from Saturn's PR to make reminder menu accessible * MM-53999 Flip provider order so that MUI props are passed * MM-53999 Pass MUI props through custom MenuItem components * Address feedback * Update snapshots
This commit is contained in:
parent
e48efdc5da
commit
e2a5293e2e
@ -20,7 +20,7 @@ export default class ChannelsPostCreate {
|
|||||||
this.sendMessageButton = container.getByTestId('SendMessageButton');
|
this.sendMessageButton = container.getByTestId('SendMessageButton');
|
||||||
}
|
}
|
||||||
|
|
||||||
async postMessage(message: string) {
|
async writeMessage(message: string) {
|
||||||
await this.input.fill(message);
|
await this.input.fill(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,22 +6,43 @@ import {expect, Locator} from '@playwright/test';
|
|||||||
export default class PostDotMenu {
|
export default class PostDotMenu {
|
||||||
readonly container: Locator;
|
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;
|
readonly deleteMenuItem;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
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() {
|
async toBeVisible() {
|
||||||
await expect(this.container).toBeVisible();
|
await expect(this.container).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete() {
|
|
||||||
await this.deleteMenuItem.waitFor();
|
|
||||||
await this.deleteMenuItem.click();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {PostDotMenu};
|
export {PostDotMenu};
|
||||||
|
@ -6,12 +6,24 @@ import {expect, Locator} from '@playwright/test';
|
|||||||
export default class PostMenu {
|
export default class PostMenu {
|
||||||
readonly container: Locator;
|
readonly container: Locator;
|
||||||
|
|
||||||
|
readonly plusOneEmojiButton;
|
||||||
|
readonly grinningEmojiButton;
|
||||||
|
readonly whiteCheckMarkEmojiButton;
|
||||||
|
readonly addReactionButton;
|
||||||
|
readonly saveButton;
|
||||||
readonly replyButton;
|
readonly replyButton;
|
||||||
|
readonly actionsButton;
|
||||||
readonly dotMenuButton;
|
readonly dotMenuButton;
|
||||||
|
|
||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
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.replyButton = container.getByRole('button', {name: 'reply'});
|
||||||
this.dotMenuButton = container.getByRole('button', {name: 'more'});
|
this.dotMenuButton = container.getByRole('button', {name: 'more'});
|
||||||
}
|
}
|
||||||
|
@ -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};
|
@ -26,6 +26,11 @@ export default class ChannelsSidebarRight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async postMessage(message: string) {
|
async postMessage(message: string) {
|
||||||
|
await this.writeMessage(message);
|
||||||
|
await this.sendMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeMessage(message: string) {
|
||||||
await this.input.fill(message);
|
await this.input.fill(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,12 +9,13 @@ import {ChannelsPostCreate} from './channels/post_create';
|
|||||||
import {ChannelsPost} from './channels/post';
|
import {ChannelsPost} from './channels/post';
|
||||||
import {ChannelsSidebarLeft} from './channels/sidebar_left';
|
import {ChannelsSidebarLeft} from './channels/sidebar_left';
|
||||||
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
import {ChannelsSidebarRight} from './channels/sidebar_right';
|
||||||
|
import {DeletePostModal} from './channels/delete_post_modal';
|
||||||
import {FindChannelsModal} from './channels/find_channels_modal';
|
import {FindChannelsModal} from './channels/find_channels_modal';
|
||||||
import {Footer} from './footer';
|
import {Footer} from './footer';
|
||||||
import {GlobalHeader} from './global_header';
|
import {GlobalHeader} from './global_header';
|
||||||
import {MainHeader} from './main_header';
|
import {MainHeader} from './main_header';
|
||||||
import {PostDotMenu} from './channels/post_dot_menu';
|
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 {PostMenu} from './channels/post_menu';
|
||||||
import {ThreadFooter} from './channels/thread_footer';
|
import {ThreadFooter} from './channels/thread_footer';
|
||||||
|
|
||||||
@ -27,12 +28,13 @@ const components = {
|
|||||||
ChannelsPost,
|
ChannelsPost,
|
||||||
ChannelsSidebarLeft,
|
ChannelsSidebarLeft,
|
||||||
ChannelsSidebarRight,
|
ChannelsSidebarRight,
|
||||||
|
DeletePostModal,
|
||||||
FindChannelsModal,
|
FindChannelsModal,
|
||||||
Footer,
|
Footer,
|
||||||
GlobalHeader,
|
GlobalHeader,
|
||||||
MainHeader,
|
MainHeader,
|
||||||
PostDotMenu,
|
PostDotMenu,
|
||||||
DeletePostModal,
|
PostReminderMenu,
|
||||||
PostMenu,
|
PostMenu,
|
||||||
ThreadFooter,
|
ThreadFooter,
|
||||||
};
|
};
|
||||||
|
@ -19,6 +19,7 @@ export default class ChannelsPage {
|
|||||||
readonly sidebarLeft;
|
readonly sidebarLeft;
|
||||||
readonly sidebarRight;
|
readonly sidebarRight;
|
||||||
readonly postDotMenu;
|
readonly postDotMenu;
|
||||||
|
readonly postReminderMenu;
|
||||||
readonly deletePostModal;
|
readonly deletePostModal;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
@ -32,6 +33,7 @@ export default class ChannelsPage {
|
|||||||
this.sidebarLeft = new components.ChannelsSidebarLeft(page.locator('#SidebarContainer'));
|
this.sidebarLeft = new components.ChannelsSidebarLeft(page.locator('#SidebarContainer'));
|
||||||
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
|
this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right'));
|
||||||
this.postDotMenu = new components.PostDotMenu(page.getByRole('menu', {name: 'Post extra options'}));
|
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'));
|
this.deletePostModal = new components.DeletePostModal(page.locator('#deletePostModal'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +57,13 @@ export default class ChannelsPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async postMessage(message: string) {
|
async postMessage(message: string) {
|
||||||
|
await this.writeMessage(message);
|
||||||
|
await this.sendMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeMessage(message: string) {
|
||||||
await this.postCreate.input.waitFor();
|
await this.postCreate.input.waitFor();
|
||||||
await this.postCreate.postMessage(message);
|
await this.postCreate.writeMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage() {
|
async sendMessage() {
|
||||||
|
@ -3,19 +3,18 @@
|
|||||||
|
|
||||||
import {expect, test} from '@e2e-support/test_fixture';
|
import {expect, test} from '@e2e-support/test_fixture';
|
||||||
|
|
||||||
test('Intro to channel', async ({pw, pages, axe}) => {
|
test('Base channel accessibility', async ({pw, pages, axe}) => {
|
||||||
// Create and sign in a new user
|
// # Create and sign in a new user
|
||||||
const {user} = await pw.initSetup();
|
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);
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
// Visit a default channel page
|
// # Visit a default channel page
|
||||||
const channelsPage = new pages.ChannelsPage(page);
|
const channelsPage = new pages.ChannelsPage(page);
|
||||||
await channelsPage.goto();
|
await channelsPage.goto();
|
||||||
await channelsPage.toBeVisible();
|
await channelsPage.toBeVisible();
|
||||||
await channelsPage.postMessage('hello');
|
await channelsPage.postMessage('hello');
|
||||||
await channelsPage.sendMessage();
|
|
||||||
|
|
||||||
// # Analyze the page
|
// # Analyze the page
|
||||||
// Disable 'color-contrast' to be addressed by MM-53814
|
// 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
|
// * Should have no violation
|
||||||
expect(accessibilityScanResults.violations).toHaveLength(0);
|
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();
|
||||||
|
});
|
||||||
|
@ -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.toBeVisible();
|
||||||
await lastPostByAdmin.postMenu.reply();
|
await lastPostByAdmin.postMenu.reply();
|
||||||
|
|
||||||
// # Write a message as a user
|
// # Post a message as a user
|
||||||
const sidebarRight = channelPage.sidebarRight;
|
const sidebarRight = channelPage.sidebarRight;
|
||||||
await sidebarRight.toBeVisible();
|
await sidebarRight.toBeVisible();
|
||||||
await sidebarRight.postMessage('Replying to a thread');
|
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
|
// # 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';
|
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
|
// # Close the RHS for draft to be saved
|
||||||
await sidebarRight.close();
|
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
|
// # Post a message in the channel
|
||||||
await channelPage.postMessage('Message which will be deleted');
|
await channelPage.postMessage('Message which will be deleted');
|
||||||
await channelPage.sendMessage();
|
|
||||||
|
|
||||||
// # Start a thread by clicking on reply menuitem from post options menu
|
// # Start a thread by clicking on reply menuitem from post options menu
|
||||||
const post = await channelPage.getLastPost();
|
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;
|
const sidebarRight = channelPage.sidebarRight;
|
||||||
await sidebarRight.toBeVisible();
|
await sidebarRight.toBeVisible();
|
||||||
|
|
||||||
// # Write a message in the thread
|
// # Post a message in the thread
|
||||||
await sidebarRight.postMessage('Replying to a thread');
|
await sidebarRight.postMessage('Replying to a thread');
|
||||||
await sidebarRight.sendMessage();
|
|
||||||
|
|
||||||
// # Write a message in the reply thread but don't send it
|
// # 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
|
// # Close the RHS for draft to be saved
|
||||||
await sidebarRight.close();
|
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.toBeVisible();
|
||||||
await post.postMenu.openDotMenu();
|
await post.postMenu.openDotMenu();
|
||||||
await channelPage.postDotMenu.toBeVisible();
|
await channelPage.postDotMenu.toBeVisible();
|
||||||
await channelPage.postDotMenu.delete();
|
await channelPage.postDotMenu.deleteMenuItem.click();
|
||||||
|
|
||||||
// # Confirm the delete from the modal
|
// # Confirm the delete from the modal
|
||||||
await channelPage.deletePostModal.toBeVisible();
|
await channelPage.deletePostModal.toBeVisible();
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {expect, test} from '@e2e-support/test_fixture';
|
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) => {
|
test('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => {
|
||||||
// Create and sign in a new user
|
// 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();
|
await channelsPage.toBeVisible();
|
||||||
|
|
||||||
// Wait for Boards' bot image to be loaded
|
// Wait for Boards' bot image to be loaded
|
||||||
const boardsWelcomePost = await channelsPage.getFirstPost();
|
// await pw.shouldHaveFeatureFlag('OnboardingAutoShowLinkedBoard', true);
|
||||||
await expect(await boardsWelcomePost.getProfileImage('boards')).toBeVisible();
|
// const boardsWelcomePost = await channelsPage.getFirstPost();
|
||||||
await wait(duration.one_sec);
|
// 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
|
// Wait for Playbooks icon to be loaded in App bar, except in iphone
|
||||||
if (!pw.isSmallScreen()) {
|
if (!pw.isSmallScreen()) {
|
||||||
|
@ -184,15 +184,6 @@ exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Connect(ChannelPermissionGate)
|
|
||||||
channelId=""
|
|
||||||
permissions={
|
|
||||||
Array [
|
|
||||||
"add_reaction",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
teamId="team_id_1"
|
|
||||||
/>
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
data-testid="follow_post_thread_post_id_1"
|
data-testid="follow_post_thread_post_id_1"
|
||||||
id="follow_post_thread_post_id_1"
|
id="follow_post_thread_post_id_1"
|
||||||
|
@ -508,12 +508,12 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
|||||||
onClick={this.handleForwardMenuItemActivated}
|
onClick={this.handleForwardMenuItemActivated}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<ChannelPermissionGate
|
{Boolean(isMobile && !isSystemMessage && !this.props.isReadOnly && this.props.enableEmojiPicker) &&
|
||||||
channelId={this.props.post.channel_id}
|
<ChannelPermissionGate
|
||||||
teamId={this.props.teamId}
|
channelId={this.props.post.channel_id}
|
||||||
permissions={[Permissions.ADD_REACTION]}
|
teamId={this.props.teamId}
|
||||||
>
|
permissions={[Permissions.ADD_REACTION]}
|
||||||
{Boolean(isMobile && !isSystemMessage && !this.props.isReadOnly && this.props.enableEmojiPicker) &&
|
>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
id={`post_reaction_${this.props.post.id}`}
|
id={`post_reaction_${this.props.post.id}`}
|
||||||
data-testid={`post_reaction_${this.props.post.id}`}
|
data-testid={`post_reaction_${this.props.post.id}`}
|
||||||
@ -526,8 +526,8 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
|
|||||||
leadingElement={<EmoticonPlusOutlineIcon size={18}/>}
|
leadingElement={<EmoticonPlusOutlineIcon size={18}/>}
|
||||||
onClick={this.handleAddReactionMenuItemActivated}
|
onClick={this.handleAddReactionMenuItemActivated}
|
||||||
/>
|
/>
|
||||||
}
|
</ChannelPermissionGate>
|
||||||
</ChannelPermissionGate>
|
}
|
||||||
{Boolean(
|
{Boolean(
|
||||||
!isSystemMessage &&
|
!isSystemMessage &&
|
||||||
this.props.isCollapsedThreadsEnabled &&
|
this.props.isCollapsedThreadsEnabled &&
|
||||||
|
@ -144,6 +144,10 @@ function PostReminderSubmenu(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<Menu.SubMenu
|
<Menu.SubMenu
|
||||||
id={`remind_post_${props.post.id}`}
|
id={`remind_post_${props.post.id}`}
|
||||||
|
menuAriaLabel={formatMessage({
|
||||||
|
id: 'post_info.post_reminder.sub_menu.header',
|
||||||
|
defaultMessage: 'Set a reminder for:',
|
||||||
|
})}
|
||||||
labels={
|
labels={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='post_info.post_reminder.menu'
|
id='post_info.post_reminder.menu'
|
||||||
|
@ -226,32 +226,32 @@ export function Menu(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<CompassDesignProvider theme={theme}>
|
<CompassDesignProvider theme={theme}>
|
||||||
{renderMenuButton()}
|
{renderMenuButton()}
|
||||||
<MuiMenuStyled
|
<MenuContext.Provider value={providerValue}>
|
||||||
anchorEl={anchorElement}
|
<MuiMenuStyled
|
||||||
open={isMenuOpen}
|
anchorEl={anchorElement}
|
||||||
onClose={handleMenuClose}
|
open={isMenuOpen}
|
||||||
onClick={handleMenuClick}
|
onClose={handleMenuClose}
|
||||||
onKeyDown={handleMenuKeyDown}
|
onClick={handleMenuClick}
|
||||||
className={A11yClassNames.POPUP}
|
onKeyDown={handleMenuKeyDown}
|
||||||
width={props.menu.width}
|
className={A11yClassNames.POPUP}
|
||||||
disableAutoFocusItem={disableAutoFocusItem} // This is not anti-pattern, see handleMenuButtonMouseDown
|
width={props.menu.width}
|
||||||
MenuListProps={{
|
disableAutoFocusItem={disableAutoFocusItem} // This is not anti-pattern, see handleMenuButtonMouseDown
|
||||||
id: props.menu.id,
|
MenuListProps={{
|
||||||
'aria-label': props.menu?.['aria-label'] ?? '',
|
id: props.menu.id,
|
||||||
}}
|
'aria-label': props.menu?.['aria-label'] ?? '',
|
||||||
TransitionProps={{
|
}}
|
||||||
mountOnEnter: true,
|
TransitionProps={{
|
||||||
unmountOnExit: true,
|
mountOnEnter: true,
|
||||||
timeout: {
|
unmountOnExit: true,
|
||||||
enter: MENU_OPEN_ANIMATION_DURATION,
|
timeout: {
|
||||||
exit: MENU_CLOSE_ANIMATION_DURATION,
|
enter: MENU_OPEN_ANIMATION_DURATION,
|
||||||
},
|
exit: MENU_CLOSE_ANIMATION_DURATION,
|
||||||
}}
|
},
|
||||||
>
|
}}
|
||||||
<MenuContext.Provider value={providerValue}>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</MenuContext.Provider>
|
</MuiMenuStyled>
|
||||||
</MuiMenuStyled>
|
</MenuContext.Provider>
|
||||||
</CompassDesignProvider>
|
</CompassDesignProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,19 @@ export interface Props extends MuiMenuItemProps {
|
|||||||
* To be used as a child of Menu component.
|
* To be used as a child of Menu component.
|
||||||
* Checkout Compass's Menu Item(compass.mattermost.com) for terminology, styling and usage guidelines.
|
* Checkout Compass's Menu Item(compass.mattermost.com) for terminology, styling and usage guidelines.
|
||||||
*
|
*
|
||||||
* @example
|
* @example <caption>Using a menu in a component</caption>
|
||||||
* <Menu.Container>
|
* <Menu.Container>
|
||||||
* <Menu.Item/>
|
* <Menu.Item/>
|
||||||
* </Menu.Container>
|
* </Menu.Container>
|
||||||
|
* @example <caption>Wrapping a menu item in another component</caption>
|
||||||
|
* // Remember to pass all unused props into the Menu.Item to ensure MUI props for a11y are passed properly
|
||||||
|
* const ConsoleLogItem = ({message, ...otherProps}) => ({
|
||||||
|
* <Menu.Item
|
||||||
|
* onClick={() => console.log(message)}
|
||||||
|
* {...otherProps}
|
||||||
|
* />
|
||||||
|
* });
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
export function MenuItem(props: Props) {
|
export function MenuItem(props: Props) {
|
||||||
const {
|
const {
|
||||||
@ -107,7 +116,7 @@ export function MenuItem(props: Props) {
|
|||||||
isLabelsRowLayout,
|
isLabelsRowLayout,
|
||||||
children,
|
children,
|
||||||
onClick,
|
onClick,
|
||||||
...restProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const menuContext = useContext(MenuContext);
|
const menuContext = useContext(MenuContext);
|
||||||
@ -181,7 +190,7 @@ export function MenuItem(props: Props) {
|
|||||||
isLabelsRowLayout={isLabelsRowLayout}
|
isLabelsRowLayout={isLabelsRowLayout}
|
||||||
onKeyDown={handleClick}
|
onKeyDown={handleClick}
|
||||||
onMouseDown={handleClick}
|
onMouseDown={handleClick}
|
||||||
{...restProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
{leadingElement && <div className='leading-element'>{leadingElement}</div>}
|
{leadingElement && <div className='leading-element'>{leadingElement}</div>}
|
||||||
<div className='label-elements'>{labels}</div>
|
<div className='label-elements'>{labels}</div>
|
||||||
@ -240,7 +249,7 @@ const MenuItemStyled = styled(MuiMenuItem, {
|
|||||||
'&.Mui-focusVisible .label-elements>:last-child, &.Mui-focusVisible .label-elements>:first-child, &.Mui-focusVisible .label-elements>:only-child': {
|
'&.Mui-focusVisible .label-elements>:last-child, &.Mui-focusVisible .label-elements>:first-child, &.Mui-focusVisible .label-elements>:only-child': {
|
||||||
color: isDestructive && 'var(--button-color)',
|
color: isDestructive && 'var(--button-color)',
|
||||||
},
|
},
|
||||||
'&.Mui-focusVisible .leading-element': {
|
'&.Mui-focusVisible .leading-element, &.Mui-focusVisible .trailing-elements': {
|
||||||
color: isDestructive && 'var(--button-color)',
|
color: isDestructive && 'var(--button-color)',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ type Props = {
|
|||||||
|
|
||||||
const CreateNewCategoryMenuItem = ({
|
const CreateNewCategoryMenuItem = ({
|
||||||
id,
|
id,
|
||||||
|
...otherProps
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const handleCreateCategory = useCallback(() => {
|
const handleCreateCategory = useCallback(() => {
|
||||||
@ -41,6 +42,7 @@ const CreateNewCategoryMenuItem = ({
|
|||||||
defaultMessage='Create New Category'
|
defaultMessage='Create New Category'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -11,16 +11,17 @@ import {openModal} from 'actions/views/modals';
|
|||||||
import {ModalIdentifiers} from 'utils/constants';
|
import {ModalIdentifiers} from 'utils/constants';
|
||||||
import MarkAsReadConfirmModal from './mark_as_read_confirm_modal';
|
import MarkAsReadConfirmModal from './mark_as_read_confirm_modal';
|
||||||
|
|
||||||
type Props = ({
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
handleViewCategory: () => void;
|
handleViewCategory: () => void;
|
||||||
numChannels: number;
|
numChannels: number;
|
||||||
})
|
}
|
||||||
|
|
||||||
const MarkAsUnreadItem = ({
|
const MarkAsUnreadItem = ({
|
||||||
id,
|
id,
|
||||||
handleViewCategory,
|
handleViewCategory,
|
||||||
numChannels,
|
numChannels,
|
||||||
|
...otherProps
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ const MarkAsUnreadItem = ({
|
|||||||
defaultMessage='Mark category as read'
|
defaultMessage='Mark category as read'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user