Skip to content

Commit

Permalink
test: add sidepanel tests (#34028)
Browse files Browse the repository at this point in the history
  • Loading branch information
juliajforesti authored Dec 11, 2024
1 parent 6799f09 commit e39db8d
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 11 deletions.
166 changes: 162 additions & 4 deletions apps/meteor/tests/e2e/feature-preview.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { faker } from '@faker-js/faker';

import { Users } from './fixtures/userStates';
import { AccountProfile, HomeChannel } from './page-objects';
import { createTargetChannel, setSettingValueById } from './utils';
import { createTargetChannel, createTargetTeam, deleteChannel, deleteTeam, setSettingValueById } from './utils';
import { setUserPreferences } from './utils/setUserPreferences';
import { test, expect } from './utils/test';

Expand All @@ -10,15 +12,17 @@ test.describe.serial('feature preview', () => {
let poHomeChannel: HomeChannel;
let poAccountProfile: AccountProfile;
let targetChannel: string;
let sidepanelTeam: string;
const targetChannelNameInTeam = `channel-from-team-${faker.number.int()}`;

test.beforeAll(async ({ api }) => {
await setSettingValueById(api, 'Accounts_AllowFeaturePreview', true);
targetChannel = await createTargetChannel(api);
targetChannel = await createTargetChannel(api, { members: ['user1'] });
});

test.afterAll(async ({ api }) => {
await setSettingValueById(api, 'Accounts_AllowFeaturePreview', false);
await api.post('/channels.delete', { roomName: targetChannel });
await deleteChannel(api, targetChannel);
});

test.beforeEach(async ({ page }) => {
Expand Down Expand Up @@ -155,8 +159,162 @@ test.describe.serial('feature preview', () => {

const collapser = poHomeChannel.sidebar.getCollapseGroupByName('Channels');
await collapser.click();

await expect(poHomeChannel.sidebar.getItemUnreadBadge(collapser)).toBeVisible();
});
});

test.describe('Sidepanel', () => {
test.beforeEach(async ({ api }) => {
sidepanelTeam = await createTargetTeam(api, { sidepanel: { items: ['channels', 'discussions'] } });

await setUserPreferences(api, {
sidebarViewMode: 'Medium',
featuresPreview: [
{
name: 'newNavigation',
value: true,
},
{
name: 'sidepanelNavigation',
value: true,
},
],
});
});

test.afterEach(async ({ api }) => {
await deleteTeam(api, sidepanelTeam);

await setUserPreferences(api, {
sidebarViewMode: 'Medium',
featuresPreview: [
{
name: 'newNavigation',
value: false,
},
{
name: 'sidepanelNavigation',
value: false,
},
],
});
});
test('should be able to toggle "Sidepanel" feature', async ({ page }) => {
await page.goto('/account/feature-preview');

await poAccountProfile.getAccordionItemByName('Navigation').click();
const sidepanelCheckbox = poAccountProfile.getCheckboxByLabelText('Secondary navigation for teams');
await expect(sidepanelCheckbox).toBeChecked();
await sidepanelCheckbox.click();
await expect(sidepanelCheckbox).not.toBeChecked();

await poAccountProfile.btnSaveChanges.click();

await expect(poAccountProfile.btnSaveChanges).not.toBeVisible();
await expect(sidepanelCheckbox).not.toBeChecked();
});

test('should display sidepanel on a team and hide it on edit', async ({ page }) => {
await page.goto(`/group/${sidepanelTeam}`);
await poHomeChannel.content.waitForChannel();
await expect(poHomeChannel.sidepanel.sidepanelList).toBeVisible();

await poHomeChannel.tabs.btnRoomInfo.click();
await poHomeChannel.tabs.room.btnEdit.click();
await poHomeChannel.tabs.room.advancedSettingsAccordion.click();
await poHomeChannel.tabs.room.toggleSidepanelItems();
await poHomeChannel.tabs.room.btnSave.click();

await expect(poHomeChannel.sidepanel.sidepanelList).not.toBeVisible();
});

test('should display new channel from team on the sidepanel', async ({ page, api }) => {
await page.goto(`/group/${sidepanelTeam}`);
await poHomeChannel.content.waitForChannel();

await poHomeChannel.tabs.btnChannels.click();
await poHomeChannel.tabs.channels.btnCreateNew.click();
await poHomeChannel.sidenav.inputChannelName.fill(targetChannelNameInTeam);
await poHomeChannel.sidenav.checkboxPrivateChannel.click();
await poHomeChannel.sidenav.btnCreate.click();

await expect(poHomeChannel.sidepanel.sidepanelList).toBeVisible();
await expect(poHomeChannel.sidepanel.getItemByName(targetChannelNameInTeam)).toBeVisible();

await deleteChannel(api, targetChannelNameInTeam);
});

test('should display sidepanel item with the same display preference as the sidebar', async ({ page }) => {
await page.goto('/home');
const message = 'hello world';

await poHomeChannel.sidebar.setDisplayMode('Extended');
await poHomeChannel.sidebar.openChat(sidepanelTeam);
await poHomeChannel.content.sendMessage(message);
await expect(poHomeChannel.sidepanel.getExtendedItem(sidepanelTeam, message)).toBeVisible();
});

// remove .fail after fix
test.fail('should escape special characters on item subtitle', async ({ page }) => {
await page.goto('/home');
const message = 'hello > world';
const parsedWrong = 'hello > world';

await poHomeChannel.sidebar.setDisplayMode('Extended');
await poHomeChannel.sidebar.openChat(sidepanelTeam);
await poHomeChannel.content.sendMessage(message);

await expect(poHomeChannel.sidepanel.getExtendedItem(sidepanelTeam, message)).toBeVisible();
await expect(poHomeChannel.sidepanel.getExtendedItem(sidepanelTeam, message)).not.toHaveText(parsedWrong);
});

test('should show channel in sidepanel after adding existing one', async ({ page }) => {
await page.goto(`/group/${sidepanelTeam}`);

await poHomeChannel.tabs.btnChannels.click();
await poHomeChannel.tabs.channels.btnAddExisting.click();
await poHomeChannel.tabs.channels.inputChannels.fill(targetChannel);
await page.getByRole('listbox').getByRole('option', { name: targetChannel }).click();
await poHomeChannel.tabs.channels.btnAdd.click();
await poHomeChannel.content.waitForChannel();

await expect(poHomeChannel.sidepanel.getItemByName(targetChannel)).toBeVisible();
});

// remove .fail after fix
test.fail('should sort by last message even if unread message is inside thread', async ({ page, browser }) => {
const user1Page = await browser.newPage({ storageState: Users.user1.state });
const user1Channel = new HomeChannel(user1Page);

await page.goto(`/group/${sidepanelTeam}`);

await poHomeChannel.tabs.btnChannels.click();
await poHomeChannel.tabs.channels.btnAddExisting.click();
await poHomeChannel.tabs.channels.inputChannels.fill(targetChannel);
await page.getByRole('listbox').getByRole('option', { name: targetChannel }).click();
await poHomeChannel.tabs.channels.btnAdd.click();

const sidepanelTeamItem = poHomeChannel.sidepanel.getItemByName(sidepanelTeam);
const targetChannelItem = poHomeChannel.sidepanel.getItemByName(targetChannel);

await targetChannelItem.click();
expect(page.url()).toContain(`/channel/${targetChannel}`);
await poHomeChannel.content.sendMessage('hello channel');
await sidepanelTeamItem.focus();
await sidepanelTeamItem.click();
expect(page.url()).toContain(`/group/${sidepanelTeam}`);
await poHomeChannel.content.sendMessage('hello team');

await user1Page.goto(`/channel/${targetChannel}`);
await user1Channel.content.waitForChannel();
await user1Channel.content.openReplyInThread();
await user1Channel.content.toggleAlsoSendThreadToChannel(false);
await user1Channel.content.sendMessageInThread('hello thread');

const item = poHomeChannel.sidepanel.getItemByName(targetChannel);
await expect(item.locator('..')).toHaveAttribute('data-item-index', '0');

await user1Page.close();
});
});
});
4 changes: 4 additions & 0 deletions apps/meteor/tests/e2e/page-objects/account-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,8 @@ export class AccountProfile {
getCheckboxByLabelText(name: string): Locator {
return this.page.locator('label', { has: this.page.getByRole('checkbox', { name }) });
}

get btnSaveChanges(): Locator {
return this.page.getByRole('button', { name: 'Save changes', exact: true });
}
}
20 changes: 18 additions & 2 deletions apps/meteor/tests/e2e/page-objects/fragments/home-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,10 @@ export class HomeContent {
}

async toggleAlsoSendThreadToChannel(isChecked: boolean): Promise<void> {
await this.page.getByRole('dialog').locator('[name="alsoSendThreadToChannel"]').setChecked(isChecked);
await this.page
.getByRole('dialog')
.locator('label', { has: this.page.getByRole('checkbox', { name: 'Also send to channel' }) })
.setChecked(isChecked);
}

get lastSystemMessageBody(): Locator {
Expand Down Expand Up @@ -398,7 +401,20 @@ export class HomeContent {
async waitForChannel(): Promise<void> {
await this.page.locator('role=main').waitFor();
await this.page.locator('role=main >> role=heading[level=1]').waitFor();
const messageList = this.page.getByRole('main').getByRole('list', { name: 'Message list', exact: true });
await messageList.waitFor();

await expect(this.page.locator('role=main >> role=list')).not.toHaveAttribute('aria-busy', 'true');
await expect(messageList).not.toHaveAttribute('aria-busy', 'true');
}

async openReplyInThread(): Promise<void> {
await this.page.locator('[data-qa-type="message"]').last().hover();
await this.page.locator('[data-qa-type="message"]').last().locator('role=button[name="Reply in thread"]').waitFor();
await this.page.locator('[data-qa-type="message"]').last().locator('role=button[name="Reply in thread"]').click();
}

async sendMessageInThread(text: string): Promise<void> {
await this.page.getByRole('dialog').getByRole('textbox', { name: 'Message' }).fill(text);
await this.page.getByRole('dialog').getByRole('button', { name: 'Send', exact: true }).click();
}
}
13 changes: 13 additions & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/home-flextab-room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,17 @@ export class HomeFlextabRoom {
get checkboxIgnoreThreads(): Locator {
return this.page.getByRole('dialog').locator('label', { has: this.page.getByRole('checkbox', { name: 'Do not prune Threads' }) });
}

get checkboxChannels(): Locator {
return this.page.getByRole('dialog').locator('label', { has: this.page.getByRole('checkbox', { name: 'Channels' }) });
}

get checkboxDiscussions(): Locator {
return this.page.getByRole('dialog').locator('label', { has: this.page.getByRole('checkbox', { name: 'Discussions' }) });
}

async toggleSidepanelItems() {
await this.checkboxChannels.click();
await this.checkboxDiscussions.click();
}
}
1 change: 1 addition & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './omnichannel-sidenav';
export * from './omnichannel-close-chat-modal';
export * from './navbar';
export * from './sidebar';
export * from './sidepanel';
11 changes: 9 additions & 2 deletions apps/meteor/tests/e2e/page-objects/fragments/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,23 @@ export class Sidebar {
return this.sidebarSearchSection.getByRole('searchbox');
}

async setDisplayMode(mode: 'Extended' | 'Medium' | 'Condensed'): Promise<void> {
await this.sidebarSearchSection.getByRole('button', { name: 'Display', exact: true }).click();
await this.sidebarSearchSection.getByRole('menuitemcheckbox', { name: mode }).click();
await this.sidebarSearchSection.click();
}

async escSearch(): Promise<void> {
await this.page.keyboard.press('Escape');
}

async waitForChannel(): Promise<void> {
await this.page.locator('role=main').waitFor();
await this.page.locator('role=main >> role=heading[level=1]').waitFor();
await this.page.locator('role=main >> role=list').waitFor();
const messageList = this.page.getByRole('main').getByRole('list', { name: 'Message list', exact: true });
await messageList.waitFor();

await expect(this.page.locator('role=main >> role=list')).not.toHaveAttribute('aria-busy', 'true');
await expect(messageList).not.toHaveAttribute('aria-busy', 'true');
}

async typeSearch(name: string): Promise<void> {
Expand Down
30 changes: 30 additions & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/sidepanel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Locator, Page } from '@playwright/test';

export class Sidepanel {
private readonly page: Page;

constructor(page: Page) {
this.page = page;
}

get sidepanelList(): Locator {
return this.page.getByRole('main').getByRole('list', { name: 'Channels' });
}

get firstChannelFromList(): Locator {
return this.sidepanelList.getByRole('listitem').first();
}

getItemByName(name: string): Locator {
return this.sidepanelList.getByRole('link').filter({ hasText: name });
}

getExtendedItem(name: string, subtitle?: string): Locator {
const regex = new RegExp(`${name}.*${subtitle}`);
return this.sidepanelList.getByRole('link', { name: regex });
}

getItemUnreadBadge(item: Locator): Locator {
return item.getByRole('status', { name: 'unread' });
}
}
5 changes: 4 additions & 1 deletion apps/meteor/tests/e2e/page-objects/home-channel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Locator, Page } from '@playwright/test';

import { HomeContent, HomeSidenav, HomeFlextab, Navbar, Sidebar } from './fragments';
import { HomeContent, HomeSidenav, HomeFlextab, Navbar, Sidebar, Sidepanel } from './fragments';

export class HomeChannel {
public readonly page: Page;
Expand All @@ -11,6 +11,8 @@ export class HomeChannel {

readonly sidebar: Sidebar;

readonly sidepanel: Sidepanel;

readonly navbar: Navbar;

readonly tabs: HomeFlextab;
Expand All @@ -20,6 +22,7 @@ export class HomeChannel {
this.content = new HomeContent(page);
this.sidenav = new HomeSidenav(page);
this.sidebar = new Sidebar(page);
this.sidepanel = new Sidepanel(page);
this.navbar = new Navbar(page);
this.tabs = new HomeFlextab(page);
}
Expand Down
8 changes: 6 additions & 2 deletions apps/meteor/tests/e2e/utils/create-target-channel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { faker } from '@faker-js/faker';
import type { IRoom } from '@rocket.chat/core-typings';
import type { ChannelsCreateProps, GroupsCreateProps } from '@rocket.chat/rest-typings';

import type { BaseTest } from './test';
Expand All @@ -25,9 +26,12 @@ export async function createTargetPrivateChannel(api: BaseTest['api'], options?:
return name;
}

export async function createTargetTeam(api: BaseTest['api']): Promise<string> {
export async function createTargetTeam(
api: BaseTest['api'],
options?: { sidepanel?: IRoom['sidepanel'] } & Omit<GroupsCreateProps, 'name'>,
): Promise<string> {
const name = faker.string.uuid();
await api.post('/teams.create', { name, type: 1, members: ['user2', 'user1'] });
await api.post('/teams.create', { name, type: 1, members: ['user2', 'user1'], ...options });

return name;
}
Expand Down

0 comments on commit e39db8d

Please sign in to comment.