mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
MM-54404 : E2E tests for the Gif picker (#24486)
This commit is contained in:
parent
7e0d9110ed
commit
19b843cf24
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, Locator} from '@playwright/test';
|
||||||
|
|
||||||
|
export default class EmojiGifPicker {
|
||||||
|
readonly container: Locator;
|
||||||
|
|
||||||
|
readonly gifTab: Locator;
|
||||||
|
readonly gifSearchInput: Locator;
|
||||||
|
readonly gifPickerItems: Locator;
|
||||||
|
|
||||||
|
constructor(container: Locator) {
|
||||||
|
this.container = container;
|
||||||
|
|
||||||
|
this.gifTab = container.getByText('GIFs');
|
||||||
|
this.gifSearchInput = container.getByPlaceholder('Search GIPHY');
|
||||||
|
this.gifPickerItems = container.locator('.gif-picker__items')
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBeVisible() {
|
||||||
|
await expect(this.container).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async openGifTab() {
|
||||||
|
await expect(this.gifTab).toBeVisible();
|
||||||
|
|
||||||
|
await this.gifTab.click({force: true});
|
||||||
|
|
||||||
|
await expect(this.gifSearchInput).toBeVisible();
|
||||||
|
await expect(this.gifPickerItems).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async searchGif(name: string) {
|
||||||
|
await this.gifSearchInput.fill(name);
|
||||||
|
await expect(this.gifSearchInput).toHaveValue(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getNthGif(n: number) {
|
||||||
|
await expect(this.gifPickerItems).toBeVisible();
|
||||||
|
|
||||||
|
await this.gifPickerItems.locator('img').nth(n).waitFor();
|
||||||
|
const nthGif = this.gifPickerItems.locator('img').nth(n);
|
||||||
|
await expect(nthGif).toBeVisible()
|
||||||
|
|
||||||
|
const nthGifSrc = await nthGif.getAttribute('src');
|
||||||
|
const nthGifAlt = await nthGif.getAttribute('alt');
|
||||||
|
|
||||||
|
if (!nthGifSrc || !nthGifAlt) {
|
||||||
|
throw new Error('Gif src or alt is empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
src: nthGifSrc,
|
||||||
|
alt: nthGifAlt,
|
||||||
|
img: nthGif,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {EmojiGifPicker};
|
@ -19,6 +19,7 @@ import {PostDotMenu} from './channels/post_dot_menu';
|
|||||||
import {PostReminderMenu} from './channels/post_reminder_menu';
|
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';
|
||||||
|
import {EmojiGifPicker} from './channels/emoji_gif_picker';
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
BoardsSidebar,
|
BoardsSidebar,
|
||||||
@ -39,6 +40,7 @@ const components = {
|
|||||||
Footer,
|
Footer,
|
||||||
MainHeader,
|
MainHeader,
|
||||||
PostReminderMenu,
|
PostReminderMenu,
|
||||||
|
EmojiGifPicker,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -23,6 +23,8 @@ export default class ChannelsPage {
|
|||||||
readonly postDotMenu;
|
readonly postDotMenu;
|
||||||
readonly postReminderMenu;
|
readonly postReminderMenu;
|
||||||
|
|
||||||
|
readonly emojiGifPickerPopup;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
|
|
||||||
@ -40,6 +42,9 @@ export default class ChannelsPage {
|
|||||||
// Menus
|
// Menus
|
||||||
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.postReminderMenu = new components.PostReminderMenu(page.getByRole('menu', {name: 'Set a reminder for:'}));
|
||||||
|
|
||||||
|
// Popovers
|
||||||
|
this.emojiGifPickerPopup = new components.EmojiGifPicker(page.locator('#emojiGifPicker'));
|
||||||
}
|
}
|
||||||
|
|
||||||
async toBeVisible() {
|
async toBeVisible() {
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, test} from '@e2e-support/test_fixture';
|
||||||
|
|
||||||
|
test('MM-T5445 Should search, select and post correct Gif when Gif picker is opened from center textbox', async ({
|
||||||
|
pw,
|
||||||
|
pages,
|
||||||
|
}) => {
|
||||||
|
const {user} = await pw.initSetup();
|
||||||
|
|
||||||
|
// # Log in as a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit default channel page
|
||||||
|
const channelPage = new pages.ChannelsPage(page);
|
||||||
|
await channelPage.goto();
|
||||||
|
await channelPage.toBeVisible();
|
||||||
|
|
||||||
|
// # Open emoji/gif picker
|
||||||
|
await channelPage.centerView.postCreate.openEmojiPicker();
|
||||||
|
await channelPage.emojiGifPickerPopup.toBeVisible();
|
||||||
|
|
||||||
|
// # Open gif tab
|
||||||
|
await channelPage.emojiGifPickerPopup.openGifTab();
|
||||||
|
|
||||||
|
// # Search for gif
|
||||||
|
await channelPage.emojiGifPickerPopup.searchGif('hello');
|
||||||
|
|
||||||
|
// # Select the first gif
|
||||||
|
const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} = await channelPage.emojiGifPickerPopup.getNthGif(0);
|
||||||
|
await firstSearchGifResult.click();
|
||||||
|
|
||||||
|
// # Send the selected gif as a message
|
||||||
|
await channelPage.centerView.postCreate.sendMessage();
|
||||||
|
|
||||||
|
// * Verify that last message has the gif
|
||||||
|
const lastPost = await channelPage.centerView.getLastPost();
|
||||||
|
await lastPost.toBeVisible();
|
||||||
|
await expect(lastPost.body.getByLabel('file thumbnail')).toHaveAttribute('alt', altOfFirstSearchGifResult);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('MM-T5446 Should search, select and post correct Gif when Gif picker is opened from RHS textbox', async ({
|
||||||
|
pw,
|
||||||
|
pages,
|
||||||
|
}) => {
|
||||||
|
const {user} = await pw.initSetup();
|
||||||
|
|
||||||
|
// # Log in as a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// # Visit default channel page
|
||||||
|
const channelPage = new pages.ChannelsPage(page);
|
||||||
|
await channelPage.goto();
|
||||||
|
await channelPage.toBeVisible();
|
||||||
|
|
||||||
|
// # Send a message
|
||||||
|
await channelPage.centerView.postCreate.postMessage('Message to open RHS');
|
||||||
|
|
||||||
|
// # Open the last post sent in RHS
|
||||||
|
const lastPost = await channelPage.centerView.getLastPost();
|
||||||
|
await lastPost.hover();
|
||||||
|
await lastPost.postMenu.toBeVisible();
|
||||||
|
await lastPost.postMenu.reply();
|
||||||
|
|
||||||
|
const sidebarRight = channelPage.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 channelPage.emojiGifPickerPopup.toBeVisible();
|
||||||
|
|
||||||
|
// # Open gif tab
|
||||||
|
await channelPage.emojiGifPickerPopup.openGifTab();
|
||||||
|
|
||||||
|
// # Search for gif
|
||||||
|
await channelPage.emojiGifPickerPopup.searchGif('hello');
|
||||||
|
|
||||||
|
// # Select the first gif
|
||||||
|
const {img: firstSearchGifResult, alt: altOfFirstSearchGifResult} = await channelPage.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);
|
||||||
|
});
|
@ -232,10 +232,6 @@ const AdvanceTextEditor = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
let emojiPicker = null;
|
let emojiPicker = null;
|
||||||
const emojiButtonAriaLabel = formatMessage({
|
|
||||||
id: 'emoji_picker.emojiPicker',
|
|
||||||
defaultMessage: 'Emoji Picker',
|
|
||||||
}).toLowerCase();
|
|
||||||
|
|
||||||
if (enableEmojiPicker && !readOnlyChannel) {
|
if (enableEmojiPicker && !readOnlyChannel) {
|
||||||
const emojiPickerTooltip = (
|
const emojiPickerTooltip = (
|
||||||
@ -269,7 +265,7 @@ const AdvanceTextEditor = ({
|
|||||||
ref={emojiPickerRef}
|
ref={emojiPickerRef}
|
||||||
onClick={toggleEmojiPicker}
|
onClick={toggleEmojiPicker}
|
||||||
type='button'
|
type='button'
|
||||||
aria-label={emojiButtonAriaLabel}
|
aria-label={formatMessage({id: 'emoji_picker.emojiPicker.button.ariaLabel', defaultMessage: 'select an emoji'})}
|
||||||
disabled={shouldShowPreview}
|
disabled={shouldShowPreview}
|
||||||
className={classNames({active: showEmojiPicker})}
|
className={classNames({active: showEmojiPicker})}
|
||||||
>
|
>
|
||||||
|
@ -446,10 +446,6 @@ const EditPost = ({editingPost, actions, canEditPost, config, channelId, draft,
|
|||||||
const getEmojiTargetRef = useCallback(() => emojiButtonRef.current, [emojiButtonRef]);
|
const getEmojiTargetRef = useCallback(() => emojiButtonRef.current, [emojiButtonRef]);
|
||||||
|
|
||||||
let emojiPicker = null;
|
let emojiPicker = null;
|
||||||
const emojiButtonAriaLabel = formatMessage({
|
|
||||||
id: 'emoji_picker.emojiPicker',
|
|
||||||
defaultMessage: 'Emoji Picker',
|
|
||||||
}).toLowerCase();
|
|
||||||
|
|
||||||
if (config.EnableEmojiPicker === 'true') {
|
if (config.EnableEmojiPicker === 'true') {
|
||||||
emojiPicker = (
|
emojiPicker = (
|
||||||
@ -466,7 +462,7 @@ const EditPost = ({editingPost, actions, canEditPost, config, channelId, draft,
|
|||||||
rightOffset={RIGHT_OFFSET}
|
rightOffset={RIGHT_OFFSET}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
aria-label={emojiButtonAriaLabel}
|
aria-label={formatMessage({id: 'emoji_picker.emojiPicker.button.ariaLabel', defaultMessage: 'select an emoji'})}
|
||||||
id='editPostEmoji'
|
id='editPostEmoji'
|
||||||
ref={emojiButtonRef}
|
ref={emojiButtonRef}
|
||||||
className='style--none post-action'
|
className='style--none post-action'
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
import type {CSSProperties, RefObject} from 'react';
|
import type {CSSProperties, RefObject} from 'react';
|
||||||
import React, {PureComponent, createRef} from 'react';
|
import React, {PureComponent, createRef} from 'react';
|
||||||
import {Tab, Tabs} from 'react-bootstrap';
|
import {Tab, Tabs} from 'react-bootstrap';
|
||||||
@ -90,17 +91,15 @@ export default class EmojiPickerTabs extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pickerClass = 'emoji-picker';
|
|
||||||
if (this.props.placement === 'bottom') {
|
|
||||||
pickerClass += ' bottom';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.enableGifPicker && typeof this.props.onGifClick != 'undefined') {
|
if (this.props.enableGifPicker && typeof this.props.onGifClick != 'undefined') {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
id='emojiGifPicker'
|
||||||
ref={this.rootPickerNodeRef}
|
ref={this.rootPickerNodeRef}
|
||||||
style={pickerStyle}
|
style={pickerStyle}
|
||||||
className={pickerClass}
|
className={classNames('a11y__popup', 'emoji-picker', {
|
||||||
|
bottom: this.props.placement === 'bottom',
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
id='emoji-picker-tabs'
|
id='emoji-picker-tabs'
|
||||||
@ -167,7 +166,9 @@ export default class EmojiPickerTabs extends PureComponent<Props, State> {
|
|||||||
<div
|
<div
|
||||||
id='emojiPicker'
|
id='emojiPicker'
|
||||||
style={pickerStyle}
|
style={pickerStyle}
|
||||||
className={`a11y__popup ${pickerClass} emoji-picker--single`}
|
className={classNames('a11y__popup', 'emoji-picker', 'emoji-picker--single', {
|
||||||
|
bottom: this.props.placement === 'bottom',
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<EmojiPickerHeader handleEmojiPickerClose={this.handleEmojiPickerClose}/>
|
<EmojiPickerHeader handleEmojiPickerClose={this.handleEmojiPickerClose}/>
|
||||||
<EmojiPicker
|
<EmojiPicker
|
||||||
|
@ -3384,7 +3384,7 @@
|
|||||||
"emoji_picker.close": "Close",
|
"emoji_picker.close": "Close",
|
||||||
"emoji_picker.custom": "Custom",
|
"emoji_picker.custom": "Custom",
|
||||||
"emoji_picker.custom_emoji": "Custom Emoji",
|
"emoji_picker.custom_emoji": "Custom Emoji",
|
||||||
"emoji_picker.emojiPicker": "Select an Emoji",
|
"emoji_picker.emojiPicker.button.ariaLabel": "select an emoji",
|
||||||
"emoji_picker.emojiPicker.previewPlaceholder": "Select an Emoji",
|
"emoji_picker.emojiPicker.previewPlaceholder": "Select an Emoji",
|
||||||
"emoji_picker.flags": "Flags",
|
"emoji_picker.flags": "Flags",
|
||||||
"emoji_picker.food-drink": "Food & Drink",
|
"emoji_picker.food-drink": "Food & Drink",
|
||||||
|
Loading…
Reference in New Issue
Block a user