From 8fdbbf3d5bd7a5cfcf41a9bffe7ae6d5b10ed17b Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Fri, 5 May 2023 06:20:23 +0800 Subject: [PATCH] E2E/Playwright: MM-T5424 Find channel limit to 50 results (#23248) * fix aria-label of Find Channels modal * add components * add test for MM-T5424 --------- Co-authored-by: Mattermost Build --- .../playwright/support/server/channel.ts | 39 +++++++----- e2e-tests/playwright/support/test_fixture.ts | 15 +++-- .../channels/find_channels_modal.ts | 23 +++++++ .../ui/components/channels/header_mobile.ts | 22 +++++++ .../ui/components/channels/sidebar_left.ts | 21 +++++++ .../playwright/support/ui/components/index.ts | 9 +++ .../playwright/support/ui/pages/channels.ts | 6 ++ .../channels/search/find_channels.spec.ts | 61 +++++++++++++++++++ .../visual/channels/intro_channel.spec.ts | 3 +- .../quick_switch_modal.test.tsx.snap | 10 +-- .../quick_switch_modal/quick_switch_modal.tsx | 8 +-- 11 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 e2e-tests/playwright/support/ui/components/channels/find_channels_modal.ts create mode 100644 e2e-tests/playwright/support/ui/components/channels/header_mobile.ts create mode 100644 e2e-tests/playwright/support/ui/components/channels/sidebar_left.ts create mode 100644 e2e-tests/playwright/tests/functional/channels/search/find_channels.spec.ts diff --git a/e2e-tests/playwright/support/server/channel.ts b/e2e-tests/playwright/support/server/channel.ts index a217f8f1fe6..44293f341fc 100644 --- a/e2e-tests/playwright/support/server/channel.ts +++ b/e2e-tests/playwright/support/server/channel.ts @@ -4,25 +4,32 @@ import {getRandomId} from '@e2e-support/util'; import {Channel, ChannelType} from '@mattermost/types/channels'; -export function createRandomChannel( - teamId: string, - name: string, - displayName: string, - type: ChannelType = 'O', - purpose = '', - header = '', - unique = true -): Channel { - const randomSuffix = getRandomId(); +type ChannelInput = { + teamId: string; + name: string; + displayName: string; + type?: ChannelType; + purpose?: string; + header?: string; + unique?: boolean; +}; +export function createRandomChannel(channelInput: ChannelInput): Channel { const channel = { - team_id: teamId, - name: unique ? `${name}-${randomSuffix}` : name, - display_name: unique ? `${displayName} ${randomSuffix}` : displayName, - type, - purpose, - header, + team_id: channelInput.teamId, + name: channelInput.name, + display_name: channelInput.displayName, + type: channelInput.type || 'O', + purpose: channelInput.type || '', + header: channelInput.type || '', }; + if (channelInput.unique) { + const randomSuffix = getRandomId(); + + channel.name = `${channelInput.name}-${randomSuffix}`; + channel.display_name = `${channelInput.displayName} ${randomSuffix}`; + } + return channel as Channel; } diff --git a/e2e-tests/playwright/support/test_fixture.ts b/e2e-tests/playwright/support/test_fixture.ts index 1614f5a3cce..428d75c0818 100644 --- a/e2e-tests/playwright/support/test_fixture.ts +++ b/e2e-tests/playwright/support/test_fixture.ts @@ -1,8 +1,9 @@ -import {test as base, Browser} from '@playwright/test'; +import {test as base, Browser, ViewportSize} from '@playwright/test'; import {TestBrowser} from './browser_context'; import {shouldHaveCallsEnabled, shouldHaveFeatureFlag, shouldSkipInSmallScreen, shouldRunInLinux} from './flag'; import {initSetup, getAdminClient} from './server'; +import {isSmallScreen} from './util'; import {hideDynamicChannelsContent, waitForAnimationEnd, waitUntil} from './test_action'; import {pages} from './ui/pages'; import {matchSnapshot} from './visual'; @@ -15,8 +16,8 @@ type ExtendedFixtures = { }; export const test = base.extend({ - pw: async ({browser}, use) => { - const pw = new PlaywrightExtended(browser); + pw: async ({browser, viewport}, use) => { + const pw = new PlaywrightExtended(browser, viewport); await use(pw); await pw.testBrowser.close(); }, @@ -48,10 +49,13 @@ class PlaywrightExtended { // ./ui/pages readonly pages; + // ./util + readonly isSmallScreen; + // ./visual readonly matchSnapshot; - constructor(browser: Browser) { + constructor(browser: Browser, viewport: ViewportSize | null) { // ./browser_context this.testBrowser = new TestBrowser(browser); @@ -73,6 +77,9 @@ class PlaywrightExtended { // ./ui/pages this.pages = pages; + // ./util + this.isSmallScreen = () => isSmallScreen(viewport); + // ./visual this.matchSnapshot = matchSnapshot; } diff --git a/e2e-tests/playwright/support/ui/components/channels/find_channels_modal.ts b/e2e-tests/playwright/support/ui/components/channels/find_channels_modal.ts new file mode 100644 index 00000000000..cab7d6d810a --- /dev/null +++ b/e2e-tests/playwright/support/ui/components/channels/find_channels_modal.ts @@ -0,0 +1,23 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {expect, Locator} from '@playwright/test'; + +export default class FindChannelsModal { + readonly container: Locator; + readonly input; + readonly searchList; + + constructor(container: Locator) { + this.container = container; + + this.input = container.getByRole('textbox', {name: 'quick switch input'}); + this.searchList = container.locator('.suggestion-list__item'); + } + + async toBeVisible() { + await expect(this.container).toBeVisible(); + } +} + +export {FindChannelsModal}; diff --git a/e2e-tests/playwright/support/ui/components/channels/header_mobile.ts b/e2e-tests/playwright/support/ui/components/channels/header_mobile.ts new file mode 100644 index 00000000000..a687220abf4 --- /dev/null +++ b/e2e-tests/playwright/support/ui/components/channels/header_mobile.ts @@ -0,0 +1,22 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {expect, Locator} from '@playwright/test'; + +export default class ChannelsHeaderMobile { + readonly container: Locator; + + constructor(container: Locator) { + this.container = container; + } + + async toggleSidebar() { + await this.container.getByRole('button', {name: 'Toggle sidebar Menu Icon'}).click(); + } + + async toBeVisible() { + await expect(this.container).toBeVisible(); + } +} + +export {ChannelsHeaderMobile}; diff --git a/e2e-tests/playwright/support/ui/components/channels/sidebar_left.ts b/e2e-tests/playwright/support/ui/components/channels/sidebar_left.ts new file mode 100644 index 00000000000..ba75fa009d8 --- /dev/null +++ b/e2e-tests/playwright/support/ui/components/channels/sidebar_left.ts @@ -0,0 +1,21 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {expect, Locator} from '@playwright/test'; + +export default class ChannelsSidebarLeft { + readonly container: Locator; + readonly findChannelButton; + + constructor(container: Locator) { + this.container = container; + + this.findChannelButton = container.getByRole('button', {name: 'Find Channels'}); + } + + async toBeVisible() { + await expect(this.container).toBeVisible(); + } +} + +export {ChannelsSidebarLeft}; diff --git a/e2e-tests/playwright/support/ui/components/index.ts b/e2e-tests/playwright/support/ui/components/index.ts index 019e4be3259..4aba6c2cd92 100644 --- a/e2e-tests/playwright/support/ui/components/index.ts +++ b/e2e-tests/playwright/support/ui/components/index.ts @@ -3,19 +3,25 @@ import {BoardsSidebar} from './boards/sidebar'; import {ChannelsHeader} from './channels/header'; +import {ChannelsHeaderMobile} from './channels/header_mobile'; import {ChannelsAppBar} from './channels/app_bar'; import {ChannelsPostCreate} from './channels/post_create'; import {ChannelsPost} from './channels/post'; +import {ChannelsSidebarLeft} from './channels/sidebar_left'; import {ChannelsSidebarRight} from './channels/sidebar_right'; +import {FindChannelsModal} from './channels/find_channels_modal'; import {GlobalHeader} from './global_header'; const components = { BoardsSidebar, ChannelsAppBar, ChannelsHeader, + ChannelsHeaderMobile, ChannelsPostCreate, ChannelsPost, + ChannelsSidebarLeft, ChannelsSidebarRight, + FindChannelsModal, GlobalHeader, }; @@ -24,8 +30,11 @@ export { BoardsSidebar, ChannelsAppBar, ChannelsHeader, + ChannelsHeaderMobile, ChannelsPostCreate, ChannelsPost, + ChannelsSidebarLeft, ChannelsSidebarRight, + FindChannelsModal, GlobalHeader, }; diff --git a/e2e-tests/playwright/support/ui/pages/channels.ts b/e2e-tests/playwright/support/ui/pages/channels.ts index b9c76ffc4ce..542f9a822d8 100644 --- a/e2e-tests/playwright/support/ui/pages/channels.ts +++ b/e2e-tests/playwright/support/ui/pages/channels.ts @@ -11,17 +11,23 @@ export default class ChannelsPage { readonly channels = 'Channels'; readonly page: Page; readonly postCreate; + readonly findChannelsModal; readonly globalHeader; readonly header; + readonly headerMobile; readonly appBar; + readonly sidebarLeft; readonly sidebarRight; constructor(page: Page) { this.page = page; this.postCreate = new components.ChannelsPostCreate(page.locator('#post-create')); + this.findChannelsModal = new components.FindChannelsModal(page.getByRole('dialog', {name: 'Find Channels'})); this.globalHeader = new components.GlobalHeader(page.locator('#global-header')); this.header = new components.ChannelsHeader(page.locator('.channel-header')); + this.headerMobile = new components.ChannelsHeaderMobile(page.locator('.navbar')); this.appBar = new components.ChannelsAppBar(page.locator('.app-bar')); + this.sidebarLeft = new components.ChannelsSidebarLeft(page.locator('#SidebarContainer')); this.sidebarRight = new components.ChannelsSidebarRight(page.locator('#sidebar-right')); } diff --git a/e2e-tests/playwright/tests/functional/channels/search/find_channels.spec.ts b/e2e-tests/playwright/tests/functional/channels/search/find_channels.spec.ts new file mode 100644 index 00000000000..542b4578920 --- /dev/null +++ b/e2e-tests/playwright/tests/functional/channels/search/find_channels.spec.ts @@ -0,0 +1,61 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {expect, test} from '@e2e-support/test_fixture'; +import {createRandomChannel} from '@e2e-support/server'; + +test('MM-T5424 Find channel search returns only 50 results when there are more than 50 channels with similar names', async ({ + pw, + pages, +}) => { + 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 = createRandomChannel({ + 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 {page} = await pw.testBrowser.login(user); + + // # Visit a default channel page + const channelsPage = new pages.ChannelsPage(page); + await channelsPage.goto(); + await channelsPage.toBeVisible(); + + // # Click on "Find channel" and type "test_channel" + if (pw.isSmallScreen()) { + await channelsPage.headerMobile.toggleSidebar(); + } + 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(); + } +}); 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 53c1b74e115..86fd10ef54f 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 {isSmallScreen} from '@e2e-support/util'; test('Intro to channel as regular user', async ({pw, pages, browserName, viewport}, testInfo) => { // Create and sign in a new user @@ -23,7 +22,7 @@ test('Intro to channel as regular user', async ({pw, pages, browserName, viewpor // await wait(duration.one_sec); // Wait for Playbooks icon to be loaded in App bar, except in iphone - if (!isSmallScreen(viewport)) { + if (!pw.isSmallScreen()) { await expect(channelsPage.appBar.playbooksIcon).toBeVisible(); } diff --git a/webapp/channels/src/components/quick_switch_modal/__snapshots__/quick_switch_modal.test.tsx.snap b/webapp/channels/src/components/quick_switch_modal/__snapshots__/quick_switch_modal.test.tsx.snap index 72bccc658c3..8f54f90b71d 100644 --- a/webapp/channels/src/components/quick_switch_modal/__snapshots__/quick_switch_modal.test.tsx.snap +++ b/webapp/channels/src/components/quick_switch_modal/__snapshots__/quick_switch_modal.test.tsx.snap @@ -3,8 +3,8 @@ exports[`components/QuickSwitchModal should match snapshot 1`] = `
-

+

const providers: SwitchChannelProvider[] = this.channelProviders; const header = ( -

+

enforceFocus={false} restoreFocus={false} role='dialog' - aria-labelledby='quickSwitchModalLabel' - aria-describedby='quickSwitchHeader' + aria-labelledby='quickSwitchHeader' + aria-describedby='quickSwitchHeaderWithHint' animation={false} >
{header}