Этот коммит содержится в:
Mario Vitale
2023-03-27 16:28:42 +02:00
родитель da7a6825ce
Коммит ba6b97fb62
1142 изменённых файлов: 44 добавлений и 44 удалений

Просмотреть файл

@@ -0,0 +1,130 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Keyboard Shortcuts', () => {
let sysadmin;
let dmWithSysadmin;
let townSquare;
let offTopic;
let testTeam;
let publicChannel;
let privateChannel;
const insights = 'Insights';
const insightsSidebar = {name: insights};
before(() => {
cy.apiGetMe().then(({user: adminUser}) => {
sysadmin = adminUser;
// # Create and login as new user
// # Create a test team and channel, then visit
cy.apiInitSetup({loginAfter: true}).then(({team, channel, user}) => {
testTeam = team;
publicChannel = channel;
cy.apiCreateChannel(testTeam.id, 'private-a', 'Private B', 'P').then((out) => {
privateChannel = out.channel;
});
cy.apiCreateDirectChannel([sysadmin.id, user.id]).then((out) => {
dmWithSysadmin = out.channel;
dmWithSysadmin.name = sysadmin.username;
dmWithSysadmin.display_name = sysadmin.username;
});
cy.apiGetChannelByName(testTeam.name, 'town-square').then((out) => {
townSquare = out.channel;
});
cy.apiGetChannelByName(testTeam.name, 'off-topic').then((out) => {
offTopic = out.channel;
});
});
});
});
it('MM-T1229 Alt/Option + Up', () => {
cy.visit(`/${testTeam.name}/messages/@${sysadmin.username}`);
// * Verify that the channel is loaded
cy.get('#channelHeaderTitle').should('contain', sysadmin.username).wait(TIMEOUTS.ONE_SEC);
// * Switch to channels by Alt+Up/Down keypress and verify
verifyChannelSwitch(testTeam.name, townSquare, dmWithSysadmin, '{uparrow}');
verifyChannelSwitch(testTeam.name, privateChannel, townSquare, '{uparrow}');
verifyChannelSwitch(testTeam.name, offTopic, privateChannel, '{uparrow}');
verifyChannelSwitch(testTeam.name, publicChannel, offTopic, '{uparrow}');
// * Should switch to Insights
verifyChannelSwitch(testTeam.name, insightsSidebar, publicChannel, '{uparrow}');
// * Should switch to bottom of channel list when current channel is at the very top
verifyChannelSwitch(testTeam.name, dmWithSysadmin, insightsSidebar, '{uparrow}');
});
it('MM-T1230 Alt/Option + Down', () => {
cy.visit(`/${testTeam.name}/channels/${publicChannel.name}`);
// * Verify that the channel is loaded
cy.get('#channelHeaderTitle').should('contain', publicChannel.display_name).wait(TIMEOUTS.ONE_SEC);
// # Switch to channels by Alt+Up/Down keypress and verify
verifyChannelSwitch(testTeam.name, offTopic, publicChannel, '{downarrow}');
verifyChannelSwitch(testTeam.name, privateChannel, offTopic, '{downarrow}');
verifyChannelSwitch(testTeam.name, townSquare, privateChannel, '{downarrow}');
verifyChannelSwitch(testTeam.name, dmWithSysadmin, townSquare, '{downarrow}');
// * Should switch to top (Insights) when current channel is at the very bottom
verifyChannelSwitch(testTeam.name, insightsSidebar, dmWithSysadmin, '{downarrow}');
verifyChannelSwitch(testTeam.name, publicChannel, insightsSidebar, '{downarrow}');
});
function verifyChannelSwitch(teamName, toChannel, fromChannel, arrowKey) {
// # Type Alt+Up/Down
cy.get('body').type(`{alt}${arrowKey}`);
// * Verify that it redirects into expected URL
if (toChannel.type === 'D') {
cy.url().should('include', `/${teamName}/messages/@${toChannel.name}`);
} else if (toChannel.name === insights) {
cy.url().should('include', `/${teamName}/activity-and-insights`);
} else {
cy.url().should('include', `/${teamName}/channels/${toChannel.name}`);
}
cy.get('#SidebarContainer').should('be.visible').within(() => {
// * Verify that the toChannel is active in LHS
verifyClass(toChannel, 'have.class');
// * Verify that the fromChannel is not active in LHS
verifyClass(fromChannel, 'not.have.class');
});
function verifyClass(channel, assertion) {
if (channel.type) {
let label;
if (channel.type === 'O') {
label = channel.display_name.toLowerCase() + ' public channel';
} else if (channel.type === 'P') {
label = channel.display_name.toLowerCase() + ' private channel';
} else if (channel.type === 'D') {
label = channel.display_name.toLowerCase();
}
cy.findByLabelText(label).parent().should(assertion, 'active');
} else {
// For Insights
cy.findByText(channel.name).parent().parent().parent().should(assertion, 'active');
}
}
}
});

Просмотреть файл

@@ -0,0 +1,56 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
let testUser;
let testTeam;
let publicChannel;
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({team, channel, user}) => {
// # Visit a test channel
testTeam = team;
publicChannel = channel;
testUser = user;
cy.visit(`/${team.name}/channels/${channel.name}`);
});
});
it('MM-T3421 - Pressing the backspace key without an input focused should not send the browser back in history', () => {
// # Navigate to a couple of pages
cy.visit(`/${testTeam.name}/channels/town-square`);
cy.visit(`/${testTeam.name}/channels/off-topic`);
cy.visit(`/${testTeam.name}/channels/${publicChannel.name}`);
cy.visit(`/${testTeam.name}/channels/off-topic`);
// # Visit a DM URL
cy.visit(`/${testTeam.name}/messages/@${testUser.username}`);
cy.url().should('include', `/${testTeam.name}/messages/@${testUser.username}`);
// # Type/edit some text and remove focus from the input field
cy.uiGetPostTextBox().clear().type('This is a normal sentence.').type('{backspace}{backspace}').blur();
// * Verify that the backspace key presses modified the input correctly
cy.uiGetPostTextBox().should('have.value', 'This is a normal sentenc');
// # Select the body to remove focus from the input field
cy.get('body').type('{backspace}');
cy.get('body').type('{backspace}');
// * Verify that the additional backspace key presses on blur doesn't affect the input
cy.uiGetPostTextBox().should('have.value', 'This is a normal sentenc');
// * Verify that the URL doesn't change from the last URL
cy.url().should('include', `/${testTeam.name}/messages/@${testUser.username}`);
});
});

Просмотреть файл

@@ -0,0 +1,44 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
let url;
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
url = channelUrl;
});
});
it('MM-T4775 CTRL/CMD+ALT+I - Toggle Channel Info RHS', () => {
// # Visit a test channel
cy.visit(url);
// # Wait for the page to load
cy.get('.channel-intro').should('be.visible');
// ensure the RHS is not visible
cy.contains('#rhsContainer', 'Info').should('not.exist');
// # Press CTRL/CMD+ALT+I
cy.get('body').cmdOrCtrlShortcut('{alt}I');
// * Ensure RHS is now present
cy.contains('#rhsContainer', 'Info').should('be.visible');
// # Press CTRL/CMD+ALT+I
cy.get('body').cmdOrCtrlShortcut('{alt}I');
// * Ensure RHS is now closed
cy.contains('#rhsContainer', 'Info').should('not.exist');
});
});

Просмотреть файл

@@ -0,0 +1,44 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
let testTeam;
let testUser;
let otherUser;
before(() => {
cy.apiInitSetup().then(({team, user, offTopicUrl}) => {
testTeam = team;
testUser = user;
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiAddUserToTeam(testTeam.id, otherUser.id);
cy.apiLogin(testUser);
cy.visit(offTopicUrl);
});
});
});
it('MM-T1246 CTRL/CMD+K - @ at beginning of username', () => {
// # Type CTRL/CMD+K
cy.uiGetPostTextBox().cmdOrCtrlShortcut('k');
// # Enter @ followed by the first 2 characters of username of the other user
cy.get('#quickSwitchInput').type('@' + otherUser.username.slice(0, 3));
// # Click on the username in the suggestion list
cy.findByTestId(otherUser.username).click();
// * The direct message channel for the user opens
cy.url().should('include', `/${testTeam.name}/messages/@${otherUser.username}`);
});
});

Просмотреть файл

@@ -0,0 +1,37 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @keyboard_shortcuts¨
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup().then(({channelUrl}) => {
cy.visit(channelUrl);
});
});
it('MM-T1242 - CTRL/CMD+K - Typed characters are not lost after switching channels', () => {
const message = 'Hello World!';
// # Type CTRL/CMD+K to open 'Switch Channels'
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K');
// * Verify that the suggestion list is visible
cy.get('#suggestionList').should('be.visible');
// # Type ENTER to switch to new channel
cy.get('#quickSwitchInput').type('{enter}');
// # Typing message
cy.get('body').type(message);
// * Textbox should have text equal to message
cy.uiGetPostTextBox().should('have.text', message);
});
});

Просмотреть файл

@@ -0,0 +1,47 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
// # Visit a test channel
cy.visit(channelUrl);
});
});
it('MM-T1243 CTRL/CMD+K - Open public channel using arrow keys and Enter, click out of current channel message box first', () => {
// # To remove focus from message text box
cy.get('#postListContent').click();
cy.uiGetPostTextBox().should('not.be.focused');
// # Press CTRL/CMD+K
cy.get('body').cmdOrCtrlShortcut('K');
cy.get('#quickSwitchInput').type('T');
// # Press down arrow
cy.wait(TIMEOUTS.HALF_SEC);
cy.get('body').type('{downarrow}');
cy.get('body').type('{downarrow}');
// * Confirm the offtopic channel is selected in the suggestion list
cy.get('#suggestionList').findByTestId('off-topic').should('be.visible').and('have.class', 'suggestion--selected');
// # Press ENTER
cy.get('body').type('{enter}');
// * Confirm that channel is open, and post text box has focus
cy.contains('#channelHeaderTitle', 'Off-Topic');
cy.uiGetPostTextBox().should('be.focused');
});
});

Просмотреть файл

@@ -0,0 +1,127 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @keyboard_shortcuts
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Keyboard Shortcuts', () => {
let testTeam;
let testUser;
let otherUser;
let testChannel;
before(() => {
cy.apiUpdateConfig({
ServiceSettings: {
ThreadAutoFollow: true,
CollapsedThreads: 'default_off',
},
});
cy.apiInitSetup({loginAfter: true, promoteNewUserAsAdmin: true}).then(({team, channel, user}) => {
testTeam = team;
testUser = user;
testChannel = channel;
cy.apiSaveCRTPreference(testUser.id, 'on');
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiAddUserToTeam(testTeam.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
});
});
});
});
beforeEach(() => {
// # Visit channel
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
});
it('MM-T4648 CTRL/CMD+K - Create thread, Open global threads and then from find channels switch channel using arrow keys and Enter', () => {
// # Post first message as other user
cy.postMessageAs({
sender: otherUser,
message: 'First post',
channelId: testChannel.id,
}).then(({id: rootId}) => {
// # Click on post to open RHS
cy.get(`#post_${rootId}`).click();
// # Post a reply as current user
cy.postMessageReplyInRHS('Reply!');
// # Close RHS
cy.uiCloseRHS();
});
// # Post second message as other user
cy.postMessageAs({
sender: otherUser,
message: 'Second post',
channelId: testChannel.id,
}).then(({id: rootId}) => {
// # Click on post to open RHS
cy.get(`#post_${rootId}`).click();
// # Post a reply as current user
cy.postMessageReplyInRHS('Reply!');
// # Visit global threads
cy.uiClickSidebarItem('threads');
// * There should be a thread there
cy.get('article.ThreadItem').should('have.have.lengthOf', 2);
});
// # Press CTRL/CMD+K
cy.get('body').cmdOrCtrlShortcut('K');
cy.get('#quickSwitchInput').type('T');
// # Press down arrow
cy.wait(TIMEOUTS.HALF_SEC);
cy.get('body').type('{downarrow}');
cy.get('body').type('{downarrow}');
cy.get('body').type('{downarrow}');
// * should not select thread and switch thread in background
cy.url().should('equal', `${Cypress.config('baseUrl')}/${testTeam.name}/threads`);
// * Confirm the offtopic channel is selected in the suggestion list
cy.get('#suggestionList').findByTestId('off-topic').should('be.visible').and('have.class', 'suggestion--selected');
// # Press up arrow
cy.wait(TIMEOUTS.HALF_SEC);
cy.get('body').type('{uparrow}');
// * should not select thread and switch thread in background
cy.url().should('equal', `${Cypress.config('baseUrl')}/${testTeam.name}/threads`);
// * Confirm the townsquare channel is selected in the suggestion list
cy.get('#suggestionList').findByTestId('town-square').should('be.visible').and('have.class', 'suggestion--selected');
// # Press down arrow
cy.wait(TIMEOUTS.HALF_SEC);
cy.get('body').type('{downarrow}');
// * should not select thread and switch thread in background
cy.url().should('equal', `${Cypress.config('baseUrl')}/${testTeam.name}/threads`);
// * Confirm the offtopic channel is selected in the suggestion list
cy.get('#suggestionList').findByTestId('off-topic').should('be.visible').and('have.class', 'suggestion--selected');
// # Press ENTER
cy.get('body').type('{enter}');
// * Confirm that channel is open
cy.contains('#channelHeaderTitle', 'Off-Topic');
cy.url().should('include', '/channels/off-topic');
});
});

Просмотреть файл

@@ -0,0 +1,54 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// [#] indicates a test step (e.g. # Go to a page)
// [*] indicates an assertion (e.g. * Check the title)
// Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @messaging
describe('Keyboard Shortcuts', () => {
let testTeam;
let firstUser;
let secondUser;
let thirdUser;
before(() => {
// # Login as test user
cy.apiInitSetup().then(({offTopicUrl, team, user: user1}) => {
firstUser = user1;
testTeam = team;
// # Create two more users
cy.apiCreateUser().then(({user: user2}) => {
secondUser = user2;
cy.apiAddUserToTeam(testTeam.id, secondUser.id);
});
cy.apiCreateUser().then(({user: user3}) => {
thirdUser = user3;
cy.apiAddUserToTeam(testTeam.id, thirdUser.id);
});
cy.apiLogin(firstUser);
cy.visit(offTopicUrl);
});
});
it('MM-T1245 CTRL/CMD+K - Open GM using mouse', () => {
// # Create a GM channel
cy.apiCreateGroupChannel([firstUser.id, secondUser.id, thirdUser.id]).then(() => {
// # Press Cmd/Ctrl-K to open "Switch Channels" modal
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K');
// # Click on the GM link to go to channel
cy.get('.status--group').click();
// * Check if channel intro message with usernames is visible
cy.findByText(/This is the start/).should('be.visible').contains(secondUser.username).contains(thirdUser.username);
});
});
});

Просмотреть файл

@@ -0,0 +1,157 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Keyboard Shortcuts', () => {
let testUser;
let otherUser;
const count = 3;
const teamAndChannels = [];
before(() => {
cy.apiInitSetup().then(({team, channel, user}) => {
testUser = user;
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(channel.id, otherUser.id);
cy.apiLogin(testUser);
Cypress._.times(2, (i) => {
cy.apiCreateTeam(`team${i}`, `Team${i}`).then(({team: testTeam}) => {
teamAndChannels.push({team: testTeam, channels: []});
const channelName = `channel${i}`;
const channelDisplayName = `Channel${i}`;
Cypress._.times(count, (j) => {
cy.apiCreateChannel(testTeam.id, channelName + j, channelDisplayName + j).then(({channel: testChannel}) => {
teamAndChannels[i].channels.push(testChannel);
cy.apiAddUserToTeam(testTeam.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
});
});
});
});
});
});
});
});
});
beforeEach(() => {
cy.apiLogin(testUser);
});
it('MM-T1241 - CTRL/CMD+K: Unreads', () => {
const otherUserMention = `@${otherUser.username}`;
// # Post messages as testUser to first and second team's channels
Cypress._.forEach(teamAndChannels, (teamAndChannel, i) => {
cy.visit(`/${teamAndChannel.team.name}/channels/off-topic`);
Cypress._.forEach(teamAndChannel.channels, (channel, j) => {
cy.get('#sidebarItem_' + channel.name).scrollIntoView().click();
const message = i === j ? 'without mention' : `mention ${otherUserMention} `;
cy.postMessage(message);
cy.uiWaitUntilMessagePostedIncludes(message);
});
});
// # Login as otherUser
cy.apiLogout();
cy.apiLogin(otherUser);
const baseCount = 1;
const withMention = 1;
const team2 = teamAndChannels[1].team;
const team2Channels = teamAndChannels[1].channels;
// # switch to team 2
cy.visit(`/${team2.name}/channels/off-topic`);
// # Type CTRL/CMD+K
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K');
// # Verify that the mentions in the channels of this team are displayed, channel will come based on recency of post
cy.wait(TIMEOUTS.HALF_SEC);
cy.get('#suggestionList').
findByTestId(team2Channels[2].name).should('be.visible').and('have.class', 'suggestion--selected').
find('.badge').should('be.visible').and('have.text', baseCount + withMention);
cy.findByRole('textbox', {name: 'quick switch input'}).type('{downarrow}');
cy.get('#suggestionList').
findByTestId(team2Channels[1].name).should('be.visible').and('have.class', 'suggestion--selected').
find('.badge').should('be.visible').and('have.text', baseCount);
cy.findByRole('textbox', {name: 'quick switch input'}).type('{downarrow}');
cy.get('#suggestionList').
findByTestId(team2Channels[0].name).should('be.visible').and('have.class', 'suggestion--selected').
find('.badge').should('be.visible').and('have.text', baseCount + withMention);
cy.findByRole('textbox', {name: 'quick switch input'}).type('{downarrow}');
cy.findByRole('textbox', {name: 'quick switch input'}).type(team2Channels[1].display_name).wait(TIMEOUTS.HALF_SEC);
// # Verify that the channels of this team are displayed
cy.get('#suggestionList').should('be.visible').children().within((el) => {
cy.wrap(el).should('contain', team2Channels[1].display_name);
});
});
it('MM-T3002 CTRL/CMD+K - Unread Channels and input field focus', () => {
const team1 = teamAndChannels[0].team;
// # Visit town square channel by teamUser
cy.visit(`/${team1.name}/channels/off-topic`);
// # Post message in other channels by otherUser
cy.postMessageAs({
sender: otherUser,
message: `Message on the ${teamAndChannels[0].channels[0].display_name}`,
channelId: teamAndChannels[0].channels[0].id,
}).then(() => {
cy.postMessageAs({
sender: otherUser,
message: `Message on the ${teamAndChannels[0].channels[1].display_name}`,
channelId: teamAndChannels[0].channels[1].id,
}).then(() => {
cy.postMessageAs({
sender: otherUser,
message: `Message on the ${teamAndChannels[0].channels[2].display_name}`,
channelId: teamAndChannels[0].channels[2].id,
}).then(() => {
// # Press keyboard shortcut for channel switcher
cy.uiGetPostTextBox().cmdOrCtrlShortcut('k');
// * Verify channel switcher shows up
cy.get('.a11y__modal.channel-switcher').should('exist').and('be.visible').as('channelSwitcherDialog');
// * Verify the focus is on switchers input field
cy.focused().should('have.id', 'quickSwitchInput');
// * Verify all unread channels names are showing up in the dialogs list
cy.get('@channelSwitcherDialog').within(() => {
// * Verify all unread channels names are showing up in the dialogs list
teamAndChannels[0].channels.forEach((channel) => {
cy.findByText(channel.display_name).should('be.visible');
});
});
});
});
});
});
});

Просмотреть файл

@@ -0,0 +1,115 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
beforeEach(() => {
cy.apiAdminLogin();
cy.apiInitSetup().
then(({user, team}) => cy.
wrap(user).as('mainUser').
wrap(team).as('mainTeam'),
);
cy.apiInitSetup().
then(({user, team}) => cy.
wrap(user).as('otherUser').
wrap(team).as('otherTeam'),
);
});
it('MM-T1228_1 CTRL/CMD+K - Open DM with user not on the current team / with ANY', function() {
cy.apiUpdateConfig({
TeamSettings: {
RestrictDirectMessage: 'any',
},
});
// # Log-in with created user
cy.apiLogin(this.mainUser);
// * User is found and DM channel with the user opens
verifyUserIsFoundAndDMOpensOnClick(this.otherUser);
});
it('MM-T1228_2 CTRL/CMD+K - Open DM with user not on the current team / with TEAM', function() {
cy.apiUpdateConfig({
TeamSettings: {
RestrictDirectMessage: 'team',
},
});
// # Log-in with created user
cy.apiLogin(this.mainUser);
cy.visit('/');
// # Select CTRL/CMD+K (or ⌘+K) to open the channel switcher
cy.typeCmdOrCtrl().type('K', {release: true});
// # Start typing the name of other user
cy.findByRole('textbox', {name: 'quick switch input'}).type(this.otherUser.username);
// # Select other user from the list
cy.findByTestId(this.otherUser.username).should('not.exist');
});
it('MM-T1228_3 CTRL/CMD+K - Open DM with user belonging to both teams / with ANY', function() {
cy.apiUpdateConfig({
TeamSettings: {
RestrictDirectMessage: 'any',
},
});
// # Add other user to the main team
cy.apiAddUserToTeam(this.mainTeam.id, this.otherUser.id);
// # Log-in with created user
cy.apiLogin(this.mainUser);
// * User is found and DM channel with the user opens
verifyUserIsFoundAndDMOpensOnClick(this.otherUser);
});
it('MM-T1228_4 CTRL/CMD+K - Open DM with user belonging to both teams / with TEAM', function() {
cy.apiUpdateConfig({
TeamSettings: {
RestrictDirectMessage: 'team',
},
});
// # Add other user to the main team
cy.apiAddUserToTeam(this.mainTeam.id, this.otherUser.id);
// # Log-in with created user
cy.apiLogin(this.mainUser);
// * User is found and DM channel with the user opens
verifyUserIsFoundAndDMOpensOnClick(this.otherUser);
});
});
function verifyUserIsFoundAndDMOpensOnClick(user) {
cy.visit('/');
// # Select CTRL/CMD+K (or ⌘+K) to open the channel switcher
cy.typeCmdOrCtrl().type('K', {release: true});
// # Start typing the name of other user
cy.findByRole('textbox', {name: 'quick switch input'}).type(user.username);
// # Select other user from the list
cy.findByTestId(user.username).should('be.visible');
cy.findByTestId(user.username).click();
// * Other user name is visible in header
cy.get('#channelHeaderTitle').should('contain', user.username);
}

Просмотреть файл

@@ -0,0 +1,56 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
// # Visit a test channel
cy.visit(channelUrl);
});
});
it('MM-T1249 CTRL/CMD+SHIFT+L - Set focus to center channel message box (with REPLY RHS open)', () => {
cy.postMessage('Hello World!');
cy.getLastPostId().then((postId) => {
// # Open RHS
cy.clickPostDotMenu(postId);
cy.findByText('Reply').click();
// * Confirm that reply text box has focus
cy.uiGetReplyTextBox().should('be.focused');
// * Confirm the RHS is shown
cy.get('#rhsCloseButton').should('exist');
// # Press CTRL/CMD+SHIFT+L
cy.get('body').cmdOrCtrlShortcut('{shift}L');
// * Confirm the message box has focus
cy.uiGetPostTextBox().should('be.focused');
});
});
it('MM-T1250 CTRL/CMD+SHIFT+L - Set focus to center channel message box (with SEARCH RHS open)', () => {
// # Search
cy.get('#searchBox').click().type('test{enter}');
// * Wait for the RHS to open and the search results to appear
cy.contains('.sidebar--right__header', 'Search Results').should('be.visible');
// # Press CTRL/CMD+SHIFT+L
cy.get('body').cmdOrCtrlShortcut('{shift}L');
// * Confirm the message box has focus
cy.uiGetPostTextBox().should('be.focused');
});
});

Просмотреть файл

@@ -0,0 +1,50 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup().then(({channelUrl}) => {
cy.visit(channelUrl);
});
});
it('MM-T4441_1 CTRL/CMD+SHIFT+A - Settings should open in desktop view', () => {
// # Type CTRL/CMD+SHIFT+A to open 'Settings'
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}A');
// * Ensure account settings modal is open
cy.get('#accountSettingsModal').should('be.visible');
cy.uiClose();
});
it('MM-T4441_2 CTRL/CMD+SHIFT+A - Settings should open in mobile view view', () => {
// # Resize the window to mobile view
cy.viewport('iphone-6');
// # Type CTRL/CMD+SHIFT+A to open 'Settings'
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}A');
// * Ensure Settings modal is open
cy.get('#accountSettingsModal').should('be.visible');
cy.uiClose();
});
it('CTRL+A - Should not open Settings', () => {
// # Type CTRL/CMD+A to select the text
cy.uiGetPostTextBox().cmdOrCtrlShortcut('A');
// * Ensure Settings modal is not open
cy.get('#accountSettingsModal').should('not.exist');
});
});

Просмотреть файл

@@ -0,0 +1,46 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
// # Visit a test channel
cy.visit(channelUrl);
});
});
it('MM-T1251 CTRL/CMD+SHIFT+L - When not to set focus to center channel message box', () => {
// # Open settings modal
cy.uiOpenSettingsModal();
// # Press ctrl/cmd+shift+l
cy.get('body').cmdOrCtrlShortcut('{shift+l}');
// * Verify channel message box is not focused
cy.uiGetPostTextBox().should('not.be.focused');
// # Close settings modal
cy.uiClose();
// # Open invite members full-page screen
cy.get('#introTextInvite').click();
// # Press ctrl/cmd+shift+l
cy.get('body').cmdOrCtrlShortcut('{shift+l}');
// * Verify channel message box is not focused
cy.uiGetPostTextBox().should('not.be.focused');
// # Close invite members full-page screen
cy.uiClose();
});
});

Просмотреть файл

@@ -0,0 +1,76 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
let testTeam;
let testChannel;
let testUser;
let otherUser;
before(() => {
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;
testUser = user;
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiAddUserToTeam(testTeam.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
});
});
});
});
it('MM-T1253 - CTRL/CMD+SHIFT+M', () => {
const message1 = ' from DM channel';
const message2 = ' from channel';
const message3 = ' using suggestion';
const messagePrefix = `mention @${testUser.username}`;
cy.apiLogin(testUser);
// # Create DM channel with the second user
cy.apiCreateDirectChannel([testUser.id, otherUser.id]).then(() => {
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testUser.id}__${otherUser.id}`);
// # Post in DM channel
cy.postMessage(messagePrefix + message1);
});
// # Post user name mention in this channel
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
cy.postMessage(messagePrefix + message2);
// # Type user name mention and post it to the channel
cy.uiGetPostTextBox().clear().type(messagePrefix + message3).type('{enter}{enter}');
// # Type "words that trigger mentions"
cy.postMessage('mention @here ');
cy.postMessage('mention @all ');
cy.postMessage('mention @channel ');
// # Type CTRL/CMD+SHIFT+M to open search
cy.get('body').cmdOrCtrlShortcut('{shift}M');
cy.get('.sidebar--right__title').should('contain', 'Recent Mentions');
// # Verify that the correct number of mentions are returned
cy.findAllByTestId('search-item-container').should('be.visible').should('have.length', 3);
cy.get('#search-items-container').within(() => {
// * Ensure that the mentions are visible in the RHS
cy.findAllByText(`@${testUser.username}`).should('be.visible');
});
});
});

Просмотреть файл

@@ -0,0 +1,46 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as TIMEOUTS from '../../../../fixtures/timeouts';
/**
* Fires off keyboard shortcut for "React to last message"
* @param {String} from CENTER, RHS or body if not provided.
*/
export function doReactToLastMessageShortcut(from) {
if (from === 'CENTER') {
cy.uiGetPostTextBox().
focus().
clear().
cmdOrCtrlShortcut('{shift}\\');
} else if (from === 'RHS') {
cy.uiGetReplyTextBox().
focus().
clear().
cmdOrCtrlShortcut('{shift}\\');
} else {
cy.get('body').cmdOrCtrlShortcut('{shift}\\');
}
cy.wait(TIMEOUTS.HALF_SEC);
}
/**
* Check if an emoji reaction was added to a post, defaults check for 'smile' emoji
* @param {String} postId Post ID of the message
* @param {String} emoji (Optional) Emoji name
*/
export function checkReactionFromPost(postId, emoji = 'smile') {
if (postId) {
cy.get(`#${postId}_message`).within(() => {
cy.findByLabelText('reactions').should('exist');
cy.findByLabelText(`remove reaction ${emoji}`).should('exist');
});
} else {
cy.findByLabelText('reactions').should('exist');
cy.findByLabelText(`remove reaction ${emoji}}`).should('exist');
}
}
export function pressEscapeKey() {
cy.get('body').type('{esc}');
}

Просмотреть файл

@@ -0,0 +1,237 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @emoji @keyboard_shortcuts
import * as MESSAGES from '../../../../fixtures/messages';
import {
doReactToLastMessageShortcut,
pressEscapeKey,
} from './helpers';
describe('Keyboard shortcut CTRL/CMD+Shift+\\ for adding reaction to last message', () => {
let testUser;
let testTeam;
let emptyChannel;
before(() => {
// # Enable Experimental View Archived Channels
cy.apiUpdateConfig({
TeamSettings: {
ExperimentalViewArchivedChannels: true,
},
});
cy.apiInitSetup().then(({team, channel, user}) => {
testUser = user;
testTeam = team;
emptyChannel = channel;
});
});
beforeEach(() => {
// # Login as test user and visit off-topic
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/off-topic`);
// # Post a message without reaction for each test
cy.postMessage('hello');
});
it('MM-T4059_1 Do not open if emoji picker is already opened for other message', () => {
// # Get post ID of the first post
cy.getLastPostId().then((firstPostId) => {
// # Post another message
cy.postMessage(MESSAGES.MEDIUM);
// # Click reaction button from the first message
cy.clickPostReactionIcon(firstPostId);
// # Do keyboard shortcut while emoji picker is opened
doReactToLastMessageShortcut();
// # Add reaction to first post
cy.clickEmojiInEmojiPicker('smile');
// * Verify no reaction is added to last post
cy.getLastPostId().then((lastPostId) => {
cy.get(`#${lastPostId}_message`).within(() => {
cy.findByLabelText('reactions').should('not.exist');
cy.findByLabelText('remove reaction smile').should('not.exist');
});
});
});
});
it('MM-T4059_2 Do not open emoji picker if last message is not visible in view', () => {
// # Get post ID of the first post
cy.getLastPostId().then((lastPostId) => {
cy.get(`#${lastPostId}_message`).as('firstPost');
});
// # Make several posts, enough to enable vertical scroll
Cypress._.times(5, () => {
cy.uiPostMessageQuickly(MESSAGES.HUGE);
});
cy.postMessage(MESSAGES.SMALL);
// # Get the post id of the last post
cy.getLastPostId().then((lastPostId) => {
cy.get(`#${lastPostId}_message`).as('lastPost');
});
// # Scroll to top post
cy.get('@firstPost').scrollIntoView();
// # Do keyboard shortcut
doReactToLastMessageShortcut();
// * Check that emoji picker is not open
cy.get('#emojiPicker').should('not.exist');
// * No reaction should be present on the last message
cy.get('@lastPost').within(() => {
cy.findByLabelText('reactions').should('not.exist');
});
});
it('MM-T4059_3 Do not open emoji picker if any modal is open', () => {
cy.uiOpenProductMenu('About Mattermost');
verifyEmojiPickerNotOpen();
cy.uiOpenTeamMenu('View Members');
verifyEmojiPickerNotOpen();
cy.uiOpenProfileModal();
verifyEmojiPickerNotOpen();
['Edit Channel Header', 'Rename Channel'].forEach((modal) => {
// # Open the modal and do keyboard shortcut
cy.uiOpenChannelMenu(modal);
doReactToLastMessageShortcut();
// * Verify emoji picker is not open
cy.get('#emojiPicker').should('not.exist');
// # Close the modal
pressEscapeKey();
});
});
it('MM-T4059_4 Do not open emoji picker if any dropdown is open', () => {
// # Open the channel menu dropdown and do keyboard shortcut
cy.uiOpenChannelMenu();
doReactToLastMessageShortcut();
// # Verify emoji picker is not open
cy.get('#emojiPicker').should('not.exist');
// * Open the main menu dropdown and do keyboard shortcut
cy.uiOpenTeamMenu();
doReactToLastMessageShortcut();
// * Verify emoji picker is not open
cy.get('#emojiPicker').should('not.exist');
});
it('MM-T4059_5 Do not open emoji picker if RHS is fully expanded for search results, recent mentions and saved posts', () => {
// # Open the saved message
cy.uiGetSavedPostButton().click();
// # Expand RHS
cy.findByLabelText('Expand Sidebar Icon').click();
// # Do keyboard shortcut
doReactToLastMessageShortcut();
// * Check if emoji picker is opened
cy.get('#emojiPicker').should('not.exist');
// # Close the expanded RHS
cy.findByLabelText('Collapse Sidebar Icon').click();
// # Open the pinned posts
cy.uiGetChannelPinButton().click();
// # Expand RHS
cy.findByLabelText('Expand Sidebar Icon').click();
// # Do keyboard shortcut
doReactToLastMessageShortcut();
// * Check if emoji picker is opened
cy.get('#emojiPicker').should('not.exist');
// # Close the expanded RHS
cy.findByLabelText('Collapse Sidebar Icon').click();
});
it('MM-T4059_6 Do not open emoji picker if last post is a system message', () => {
// # Login as admin
cy.apiAdminLogin();
// # Visit the new empty channel
cy.visit(`/${testTeam.name}/channels/${emptyChannel.name}`);
// * Check that there are no post except you joined message
cy.findAllByTestId('postView').should('have.length', 1);
// # Do keyboard shortcut
doReactToLastMessageShortcut();
// * Check that emoji picker is not opened for system joining message
cy.get('#emojiPicker').should('not.exist');
// # Delete the system message
cy.getLastPostId().then((lastPostId) => {
cy.clickPostDotMenu(lastPostId);
// # Click delete button.
cy.get(`#delete_post_${lastPostId}`).click();
// * Check that confirmation dialog is open.
cy.get('#deletePostModal').should('be.visible');
// # Confirm deletion.
cy.get('#deletePostModalButton').click();
// # Do keyboard shortcut
doReactToLastMessageShortcut('CENTER');
// * Check that emoji picker is not opened for new channel
cy.get('#emojiPicker').should('not.exist');
});
// # Post a message to channel
cy.postMessage(MESSAGES.TINY);
// # Archive the channel after posting a message
cy.apiDeleteChannel(emptyChannel.id);
// # Do keyboard shortcut
doReactToLastMessageShortcut();
// * Check that emoji picker is not opened
cy.get('#emojiPicker').should('not.exist');
});
});
function verifyEmojiPickerNotOpen() {
// # Click emoji button
doReactToLastMessageShortcut();
// * Verify emoji picker is not open
cy.get('#emojiPicker').should('not.exist');
// # Close the modal
pressEscapeKey();
}

Просмотреть файл

@@ -0,0 +1,246 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @emoji @keyboard_shortcuts
import * as TIMEOUTS from '../../../../fixtures/timeouts';
import * as MESSAGES from '../../../../fixtures/messages';
import {
checkReactionFromPost,
doReactToLastMessageShortcut,
} from './helpers';
describe('Keyboard shortcut CTRL/CMD+Shift+\\ for adding reaction to last message', () => {
let testUser;
let otherUser;
let testTeam;
let offTopicChannel;
before(() => {
// # Enable Experimental View Archived Channels
cy.apiUpdateConfig({
TeamSettings: {
ExperimentalViewArchivedChannels: true,
},
});
cy.apiInitSetup().then(({team, user}) => {
testUser = user;
testTeam = team;
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiGetChannelByName(testTeam.name, 'off-topic').then((out) => {
offTopicChannel = out.channel;
});
cy.apiAddUserToTeam(testTeam.id, otherUser.id);
});
});
});
beforeEach(() => {
// # Login as test user and visit off-topic
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/off-topic`);
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('contain', 'Off-Topic');
// # Post a message without reaction for each test
cy.postMessage('hello');
});
it('MM-T4060_1 Open emoji picker on center when focus is neither on center or comment textbox even if RHS is opened', () => {
// # Click post comment icon
cy.clickPostCommentIcon();
// * Check that RHS is open
cy.get('#rhsContainer').should('be.visible');
// # Post couple of comments in RHS.
cy.postMessageReplyInRHS(MESSAGES.SMALL);
cy.postMessageReplyInRHS(MESSAGES.TINY);
// # Save the post ID where reaction should not be added
cy.getLastPostId().as('prevLastPostId');
// # Have another user post a message
cy.postMessageAs({
sender: otherUser,
message: MESSAGES.MEDIUM,
channelId: offTopicChannel.id,
});
cy.wait(TIMEOUTS.TWO_SEC);
// # Click anywhere to take focus away from RHS text box
cy.get('body').click();
cy.wait(TIMEOUTS.TWO_SEC);
// # Do keyboard shortcut without focus on center
doReactToLastMessageShortcut();
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji reaction is shown in the last message in center
cy.getLastPostId().then((lastPostId) => {
cy.get(`#post_${lastPostId}`).findByLabelText('remove reaction smile').should('exist');
});
// * Check if no emoji reaction is shown from last comment both in RHS and center
cy.get('@prevLastPostId').then((lastPostId) => {
cy.get(`#rhsPost_${lastPostId}`).findByLabelText('remove reaction smile').should('not.exist');
cy.get(`#post_${lastPostId}`).findByLabelText('remove reaction smile').should('not.exist');
});
cy.uiCloseRHS();
});
it('MM-T4060_2 Open emoji picker on center when focus is on center text box even if RHS is opened', () => {
// # Click post comment icon
cy.clickPostCommentIcon();
// * Check that RHS is open
cy.get('#rhsContainer').should('be.visible');
// # Post couple of comments in RHS.
cy.postMessageReplyInRHS(MESSAGES.SMALL);
cy.postMessageReplyInRHS(MESSAGES.TINY);
// # Get the last post ID in RHS where reaction should not be added
cy.getLastPostId().then((lastPostId) => {
cy.get(`#${lastPostId}_message`).as('postInRHS');
});
// # Have another user post a message to a channel
cy.postMessageAs({
sender: otherUser,
message: MESSAGES.MEDIUM,
channelId: offTopicChannel.id,
});
cy.wait(TIMEOUTS.FIVE_SEC);
// # Click anywhere to take focus away from RHS text box
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
// # Do keyboard shortcut with focus on center
doReactToLastMessageShortcut('CENTER');
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// # This post is in Center, where reaction is to be added
cy.getLastPostId().then((lastPostId) => {
cy.get(`#${lastPostId}_message`).as('postInCenter');
});
// * Check if emoji is shown as reaction to the message in center
cy.getLastPostId().then((lastPostId) => {
checkReactionFromPost(lastPostId);
});
// * Check if no emoji reaction is shown in the last comment at RHS
cy.get('@postInRHS').within(() => {
cy.findByLabelText('reactions').should('not.exist');
cy.findByLabelText('remove reaction smile').should('not.exist');
});
cy.uiCloseRHS();
});
it('MM-T1804_1 Open emoji picker for last message when focus is on center textbox', () => {
// # Do keyboard shortcut with focus on center
doReactToLastMessageShortcut('CENTER');
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji is shown as reaction to last message
cy.getLastPostId().then((lastPostId) => {
checkReactionFromPost(lastPostId);
});
});
it('MM-T1804_2 Open emoji picker for last message even when focus is not on center textbox', () => {
// # Click anywhere to take focus away from center text box
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
// # Do keyboard shortcut without focus on center
doReactToLastMessageShortcut();
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji is shown as reaction to last message
cy.getLastPostId().then((lastPostId) => {
checkReactionFromPost(lastPostId);
});
});
it('MM-T1804_3 Should reopen emoji picker even if shortcut is hit repeatedly on center', () => {
// # Do keyboard shortcuts then escape multiple times, and
// * verify that emoji picker open up each time
Cypress._.times(3, () => {
doReactToLastMessageShortcut('CENTER');
cy.get('#emojiPicker').should('exist');
cy.get('body').click();
cy.get('#emojiPicker').should('not.exist');
});
// # Do keyboard shortcut with focus on center
doReactToLastMessageShortcut('CENTER');
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji is shown as reaction to last message
cy.getLastPostId().then((lastPostId) => {
checkReactionFromPost(lastPostId);
});
});
it('MM-T1804_4 Should add reaction to same post on which emoji picker was opened', () => {
// # Save the post id which user initially intended to add reaction to, for later use
cy.getLastPostId().then((lastPostId) => {
cy.wrap(lastPostId).as('postIdForAddingReaction');
});
// # Do keyboard shortcut without focus
doReactToLastMessageShortcut();
// * Check that emoji picker is open
cy.get('#emojiPicker').should('exist');
// # While open, have another user post a message to a channel
cy.postMessageAs({
sender: otherUser,
message: MESSAGES.TINY,
channelId: offTopicChannel.id,
});
cy.wait(TIMEOUTS.FIVE_SEC);
// * Check if emoji picker is still open and add a reaction
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji is shown as reaction to the message it initially intended
cy.get('@postIdForAddingReaction').then((postIdForAddingReaction) => {
checkReactionFromPost(postIdForAddingReaction);
});
// * Check if last message didn't get a reaction
cy.getLastPostId().then((lastPostId) => {
cy.get(`#${lastPostId}_message`).within(() => {
cy.findByLabelText('reactions').should('not.exist');
cy.findByLabelText('remove reaction smile').should('not.exist');
});
});
});
});

Просмотреть файл

@@ -0,0 +1,116 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @emoji @keyboard_shortcuts
import * as TIMEOUTS from '../../../../fixtures/timeouts';
import * as MESSAGES from '../../../../fixtures/messages';
import {
checkReactionFromPost,
doReactToLastMessageShortcut,
} from './helpers';
describe('Keyboard shortcut CTRL/CMD+Shift+\\ for adding reaction to last message', () => {
let testUser;
let testTeam;
before(() => {
// # Enable Experimental View Archived Channels
cy.apiUpdateConfig({
TeamSettings: {
ExperimentalViewArchivedChannels: true,
},
});
cy.apiInitSetup().then(({team, user}) => {
testUser = user;
testTeam = team;
});
});
beforeEach(() => {
// # Login as test user and visit town-square
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/off-topic`);
cy.get('#channelHeaderTitle', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('contain', 'Off-Topic');
// # Post a message without reaction for each test
cy.postMessage(MESSAGES.TINY);
});
it('MM-T4058_1 Open emoji picker for root post in RHS when focus is on comment textbox', () => {
// # Click post comment icon
cy.clickPostCommentIcon();
// * Check that the RHS is open
cy.get('#rhsContainer').should('be.visible');
// # Do keyboard shortcut with focus on RHS
doReactToLastMessageShortcut('RHS');
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji is shown as reaction to the last message (same in RHS)
cy.getLastPostId().then((lastPostId) => {
checkReactionFromPost(lastPostId);
});
cy.uiCloseRHS();
});
it('MM-T4058_2 Open emoji picker for last comment in RHS when focus is on comment textbox', () => {
// # Click post comment icon
cy.clickPostCommentIcon();
// * Check that the RHS is open
cy.get('#rhsContainer').should('be.visible');
// # Post few comments in RHS
cy.postMessageReplyInRHS(MESSAGES.SMALL);
cy.postMessageReplyInRHS(MESSAGES.TINY);
// # Do keyboard shortcut with focus on RHS
doReactToLastMessageShortcut('RHS');
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji is shown as reaction to the last message (same in RHS)
cy.getLastPostId().then((lastPostId) => {
checkReactionFromPost(lastPostId);
});
cy.uiCloseRHS();
});
it('MM-T4058_3 Open emoji picker for last comment in fully expanded RHS when focus is on comment textbox', () => {
// # Click post comment icon
cy.clickPostCommentIcon();
// * Check that the RHS is open
cy.get('#rhsContainer').should('be.visible');
// # Fully expand the RHS
cy.uiExpandRHS();
// # Do keyboard shortcut with focus on RHS
doReactToLastMessageShortcut('RHS');
// # Add reaction to a post
cy.clickEmojiInEmojiPicker('smile');
// * Check if emoji is shown as reaction to the last message (same in RHS)
cy.getLastPostId().then((lastPostId) => {
checkReactionFromPost(lastPostId);
});
});
});

Просмотреть файл

@@ -0,0 +1,84 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
// # Visit a test channel
cy.visit(channelUrl);
});
});
it('MM - T1257 CTRL / CMD + UP or DOWN in RHS', () => {
const firstMessage = 'Hello World!';
const messages = ['This', 'is', 'an', 'e2e test', '/shrug'];
// # Post a message in the central textbox
cy.postMessage(firstMessage);
cy.getLastPostId().then((postId) => {
// # Open RHS
cy.clickPostDotMenu(postId);
cy.findByText('Reply').click();
// * Confirm that reply text box has focus
cy.findByTestId('reply_textbox').should('be.focused');
// * Verify RHS is opened
cy.uiGetRHS().within(() => {
for (let idx = 0; idx < messages.length; idx++) {
// # Post each message as a reply
cy.findByTestId('reply_textbox').
type(messages[idx]).
type('{enter}').
clear();
}
// * Confirm that reply textbox has focus
cy.findByTestId('reply_textbox').should('be.focused');
cy.findByTestId('reply_textbox').clear();
// # Press CTRL/CMD + uparrow repeatedly
let previousMessageIndex = messages.length - 1;
for (let idx = 0; idx <= messages.length; idx++) {
if (idx === messages.length) {
// * Check if the last message is equal to the first message
cy.findByTestId('reply_textbox').cmdOrCtrlShortcut('{uparrow}');
cy.findByTestId('reply_textbox').should('have.text', firstMessage);
break;
}
if (messages[previousMessageIndex] === '/shrug') {
cy.findByTestId('reply_textbox').click();
}
cy.findByTestId('reply_textbox').cmdOrCtrlShortcut('{uparrow}');
// * Check if the message is equal to the last message
cy.findByTestId('reply_textbox').should('have.text', messages[previousMessageIndex]);
previousMessageIndex--;
}
// * Press CTRL/CMD + downarrow check if the current text is equal to the second message
cy.findByTestId('reply_textbox').cmdOrCtrlShortcut('{downarrow}').should('have.text', messages[0]);
// # Close the RHS
cy.uiCloseRHS();
});
// * Press CTRL/CMD + uparrow in central textbox check if the text is equal to the last message
cy.findByTestId('post_textbox').cmdOrCtrlShortcut('{uparrow}').should('have.text', messages[messages.length - 1]);
// * Press CTRL/CMD + downarrow in central textbox check if the text is equal to the last message / there is no change in text
cy.findByTestId('post_textbox').cmdOrCtrlShortcut('{downarrow}').should('have.text', messages[messages.length - 1]);
});
});
});

Просмотреть файл

@@ -0,0 +1,49 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
// # Visit test channel
cy.visit(channelUrl);
});
});
it('MM-T1255 CTRL/CMD+UP or DOWN no action on draft post', () => {
const message = 'Test message from User 1';
// # Type a message in the input box but do not post it
cy.uiGetPostTextBox().type(message).wait(TIMEOUTS.ONE_SEC);
// # Press CMD/CTRL+DOWN arrow
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{downarrow}');
// * Check the focus after pressing CTRL/CMD + DOWN then check match the text and the cursor position respectively
cy.uiGetPostTextBox().
should('be.focused').
and('have.text', message).
and('have.prop', 'selectionStart', message.length).
and('have.prop', 'selectionEnd', message.length);
// # Press CMD/CTRL+UP arrow
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{uparrow}');
// * Check the focus after pressing CTRL/CMD + UP then check match the text and the cursor position respectively
cy.uiGetPostTextBox().
should('be.focused').
and('have.text', message).
and('have.prop', 'selectionStart', 0).
and('have.prop', 'selectionEnd', 0);
});
});

Просмотреть файл

@@ -0,0 +1,115 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import {beUnread} from '../../../support/assertions';
import {stubClipboard} from '../../../utils';
describe('Keyboard Shortcuts', () => {
let testTeam;
let testChannel;
const postMessage = 'test for saved post';
const postEditMessage = ' POST EDITED';
before(() => {
// # Login as test user and visit off-topic channel
cy.apiInitSetup({loginAfter: true}).then(({team, channel}) => {
testTeam = team;
testChannel = channel;
cy.visit(`/${team.name}/channels/off-topic`);
});
cy.postMessage(postMessage);
});
it('MM-T4801 Dot menu keyboard shortcuts', () => {
cy.getLastPostId().then((postId) => {
stubClipboard().as('clipboard');
const permalink = `${Cypress.config('baseUrl')}/${testTeam.name}/pl/${postId}`;
// # Reply
cy.uiPostDropdownMenuShortcut(postId, 'Reply', 'R');
// * Verify reply text box is focused
cy.uiGetReplyTextBox().should('be.focused');
// # Mark as unread
cy.uiPostDropdownMenuShortcut(postId, 'Mark as Unread', 'U');
// * Verify the channel is unread in LHS
cy.get(`#sidebarItem_${testChannel.name}`).should(beUnread);
// # Pin Post
cy.uiPostDropdownMenuShortcut(postId, 'Pin to Channel', 'P');
// * Verify post is pinned
cy.get(`#post_${postId}`).find('.post-pre-header').should('be.visible').and('have.text', 'Pinned');
// # Unpin Post
cy.uiPostDropdownMenuShortcut(postId, 'Unpin from Channel', 'P');
// * Verify post is unpinned
cy.get(`#post_${postId}`).and('not.have.text', 'Pinned');
// # Copy Link
cy.uiPostDropdownMenuShortcut(postId, 'Copy Link', 'K');
// * Verify link is copied to the clipboard
cy.get('@clipboard').its('contents').should('eq', permalink);
// # Edit
cy.uiPostDropdownMenuShortcut(postId, 'Edit', 'E');
// # add test to the message
cy.get('body').type(postEditMessage);
cy.get('body').type('{enter}');
// * Verify edited message
cy.uiWaitUntilMessagePostedIncludes(postMessage + postEditMessage);
cy.get(`#postMessageText_${postId}`).
and('have.text', postMessage + postEditMessage + ' Edited');
// # Copy Text
cy.uiPostDropdownMenuShortcut(postId, 'Copy Text', 'C');
// * Verify message is copied to the clipboard
cy.get('@clipboard').its('contents').should('eq', postMessage + postEditMessage);
});
cy.postMessage('message to delete');
cy.getLastPostId().then((postId) => {
// # Delete
cy.uiPostDropdownMenuShortcut(postId, 'Delete', '{del}');
cy.findByText('Delete').click();
// * Verify message was deleted
cy.findByText('message to delete').should('not.exist');
});
cy.getLastPostId().then((postId) => {
// * verify Save not shown in webview
cy.findByText('Save').should('not.exist');
cy.viewport('iphone-6');
// # Save Post
cy.uiPostDropdownMenuShortcut(postId, 'Save', 'S', 'RHS_ROOT');
// * Verify post is Saved
cy.get(`#post_${postId}`).find('.post-pre-header').should('be.visible').and('have.text', 'Saved');
// # Unsave Post
cy.uiPostDropdownMenuShortcut(postId, 'Remove from Saved', 'S', 'RHS_ROOT');
// * Verify post is unsaved
cy.get(`#post_${postId}`).and('not.have.text', 'Saved');
});
});
});

Просмотреть файл

@@ -0,0 +1,44 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
let channelUrl;
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({offTopicUrl}) => {
channelUrl = offTopicUrl;
cy.visit(channelUrl);
});
});
it('MM-T1244 CTRL/CMD+K - Esc closes modal', () => {
const searchTerm = 'test' + Date.now();
// # Open Channel switcher modal by click on the button
cy.findByRole('button', {name: 'Find Channels'}).click();
// # Type in the quick switch input box
cy.get('#quickSwitchInput').typeWithForce(searchTerm);
// * Verify that the no search result test is displayed
cy.get('.no-results__title').should('be.visible').and('have.text', 'No results for "' + searchTerm + '"');
// # Press escape key
cy.get('#quickSwitchInput').typeWithForce('{esc}');
// * Verify that the modal is closed
cy.get('.modal-content').should('not.exist');
// * Verify that the user does not leave the off-topic channel
cy.url().should('contain', channelUrl);
});
});

Просмотреть файл

@@ -0,0 +1,469 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import * as messages from '../../../fixtures/messages';
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Keyboard Shortcuts', () => {
let testTeam;
let testChannel;
let testUser;
let otherUser;
before(() => {
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;
testUser = user;
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiAddUserToTeam(testTeam.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
});
});
});
});
beforeEach(() => {
// # Login as admin and visit town-square
cy.apiAdminLogin();
cy.visit(`/${testTeam.name}/channels/town-square`);
});
it('MM-T1227 - CTRL/CMD+K - Join public channel', () => {
// # Type CTRL/CMD+K
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K');
cy.apiCreateUser({prefix: 'temp-'}).then(({user: tempUser}) => {
// # Add user to team but not to test channel
cy.apiAddUserToTeam(testTeam.id, tempUser.id);
// # In the "Switch Channels" modal type the first chars of the test channel name
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.focused').type(testChannel.name.substring(0, 3)).wait(TIMEOUTS.HALF_SEC);
// # Verify that the list of users and channels suggestions is present
cy.get('#suggestionList').should('be.visible').within(() => {
// * The channel the current user is not a member of should be there in the search list; click it
cy.findByTestId(testChannel.name).scrollIntoView().should('exist').click().wait(TIMEOUTS.HALF_SEC);
});
// # Verify that we are in the test channel
cy.get('#channelIntro').contains('.channel-intro__title', `Beginning of ${testChannel.display_name}`).should('be.visible');
// # Verify that the right channel is displayed in LHS
cy.uiGetLhsSection('CHANNELS').findByText(testChannel.display_name).should('be.visible');
// # Verify that the current user(sysadmin) created the channel
cy.get('#channelIntro').contains('.channel-intro__content', `This is the start of the ${testChannel.display_name} channel, created by sysadmin`).should('be.visible');
});
});
it('MM-T1231 - ALT+SHIFT+UP', () => {
cy.apiLogout();
cy.apiLogin(testUser);
cy.apiCreateTeam('team1', 'Team1').then(({team}) => {
const privateChannels = [];
const publicChannels = [];
const dmChannels = [];
// # Create two public channels
for (let index = 0; index < 2; index++) {
const otherUserId = otherUser.id;
cy.apiCreateChannel(team.id, `a-public-${index}`, `A Public ${index}`).then(({channel}) => {
publicChannels.push(channel);
cy.apiAddUserToTeam(team.id, otherUserId).then(() => {
cy.apiAddUserToChannel(channel.id, otherUserId);
});
});
}
// # Create two private channels
for (let index = 0; index < 2; index++) {
const otherUserId = otherUser.id;
cy.apiCreateChannel(team.id, `b-private-${index}`, `B Private ${index}`, 'P').then(({channel}) => {
privateChannels.push(channel);
cy.apiAddUserToChannel(channel.id, otherUserId);
});
}
// # Set up DM channel
cy.apiCreateDirectChannel([testUser.id, otherUser.id]).wait(TIMEOUTS.ONE_SEC).then(({channel}) => {
dmChannels.push(channel);
cy.visit(`/${team.name}/channels/${testUser.id}__${otherUser.id}`);
cy.uiGetPostTextBox().clear().type(`message from ${testUser.username}`).type('{enter}');
});
// # Add posts by second user to the newly created channels in the first team
cy.apiLogout();
cy.apiLogin(otherUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
cy.get('#sidebarItem_' + publicChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to public channel').type('{enter}');
cy.get('#sidebarItem_' + privateChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to private channel').type('{enter}');
cy.get('#sidebarItem_' + dmChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type(`direct message from ${otherUser.username}`).type('{enter}');
});
cy.apiLogout();
cy.apiLogin(testUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
// # Verify that the channels are unread
cy.get(`#sidebarItem_${publicChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${privateChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${dmChannels[0].name}`).should('have.class', 'unread-title');
// # Navigate to the bottom of the list of channels
cy.get('#sidebarItem_' + dmChannels[0].name).scrollIntoView().click();
cy.get('.active').find('#sidebarItem_' + dmChannels[0].name).should('exist');
// # Press alt + shift + up
cy.get('body').type('{alt}{shift}', {release: false}).type('{uparrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + privateChannels[0].name).should('exist');
cy.get('body').type('{alt}{shift}', {release: false}).type('{uparrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + publicChannels[0].name).should('exist');
// # No navigation - stay in place
cy.get('body').type('{alt}{shift}', {release: false}).type('{uparrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + publicChannels[0].name).should('exist');
});
// # Handle favorite channels
const favPrivateChannels = [];
const favPublicChannels = [];
const favDMChannels = [];
// # Set up public favorite channel
cy.apiCreateChannel(team.id, 'public', 'public').then(({channel}) => {
favPublicChannels.push(channel);
cy.apiAddUserToChannel(channel.id, otherUser.id);
markAsFavorite(channel.name);
});
// # Set up private favorite channel
cy.apiCreateChannel(team.id, 'private', 'private', 'P').then(({channel}) => {
favPrivateChannels.push(channel);
cy.apiAddUserToChannel(channel.id, otherUser.id);
markAsFavorite(channel.name);
});
// # Set up DM favorite channel
cy.apiCreateDirectChannel([testUser.id, otherUser.id]).wait(TIMEOUTS.ONE_SEC).then(({channel}) => {
favDMChannels.push(channel);
cy.visit(`/${team.name}/channels/${testUser.id}__${otherUser.id}`);
cy.uiGetPostTextBox().clear().type(`message from ${testUser.username}`).type('{enter}');
markAsFavorite(channel.name);
});
// # Add posts by second user to the newly created channels in the first team
cy.apiLogout();
cy.apiLogin(otherUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
cy.get('#sidebarItem_' + favPublicChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to public channel').type('{enter}');
cy.get('#sidebarItem_' + favPrivateChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to private channel').type('{enter}');
cy.get('#sidebarItem_' + favDMChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type(`direct message from ${otherUser.username}`).type('{enter}');
});
cy.apiLogout();
cy.apiLogin(testUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
// # Verify that the channels are unread - in the Favorites tab the unread channels are ordered alphabetically
cy.get(`#sidebarItem_${favDMChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${favPrivateChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${favPublicChannels[0].name}`).should('have.class', 'unread-title');
// # Navigate to the middle of the list of unread favorite channels
cy.get('#sidebarItem_' + favPrivateChannels[0].name).scrollIntoView().click();
cy.get('.active').find('#sidebarItem_' + favPrivateChannels[0].name).should('exist');
// # Press alt + shift + up
cy.get('body').type('{alt}{shift}', {release: false}).type('{uparrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + favDMChannels[0].name).should('exist');
cy.get('body').type('{alt}{shift}', {release: false}).type('{uparrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + favPublicChannels[0].name).should('exist');
// # No navigation - stay in place
cy.get('body').type('{alt}{shift}', {release: false}).type('{uparrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + favPublicChannels[0].name).should('exist');
});
});
});
it('MM-T1232 - ALT+SHIFT+DOWN', () => {
cy.apiLogout();
cy.apiLogin(testUser);
cy.apiCreateTeam('team2', 'Team2').then(({team}) => {
const privateChannels = [];
const publicChannels = [];
const dmChannels = [];
// # Create two public channels
for (let index = 0; index < 2; index++) {
const otherUserId = otherUser.id;
cy.apiCreateChannel(team.id, `a-public-${index}`, `A Public ${index}`).then(({channel}) => {
publicChannels.push(channel);
cy.apiAddUserToTeam(team.id, otherUserId).then(() => {
cy.apiAddUserToChannel(channel.id, otherUserId);
});
});
}
// # Create two private channels
for (let index = 0; index < 2; index++) {
const otherUserId = otherUser.id;
cy.apiCreateChannel(team.id, `b-private-${index}`, `B Private ${index}`).then(({channel}) => {
privateChannels.push(channel);
cy.apiAddUserToChannel(channel.id, otherUserId);
});
}
// # Set up DM channel
cy.apiCreateDirectChannel([testUser.id, otherUser.id]).wait(TIMEOUTS.ONE_SEC).then(({channel}) => {
dmChannels.push(channel);
cy.visit(`/${team.name}/channels/${testUser.id}__${otherUser.id}`);
cy.uiGetPostTextBox().clear().type(`message from ${testUser.username}`).type('{enter}');
});
// # Add posts by second user to the newly created channels in the first team
cy.apiLogout();
cy.apiLogin(otherUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
cy.get('#sidebarItem_' + publicChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to public channel').type('{enter}');
cy.get('#sidebarItem_' + privateChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to private channel').type('{enter}');
cy.get('#sidebarItem_' + dmChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type(`direct message from ${otherUser.username}`).type('{enter}');
});
cy.apiLogout();
cy.apiLogin(testUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
// # Verify that the channels are unread
cy.get(`#sidebarItem_${publicChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${privateChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${dmChannels[0].name}`).should('have.class', 'unread-title');
// # Navigate to the top of the list of channels
cy.get('#sidebarItem_' + publicChannels[0].name).scrollIntoView().click();
cy.get('.active').find('#sidebarItem_' + publicChannels[0].name).should('exist');
// # Press alt + shift + down
cy.get('body').type('{alt}{shift}', {release: false}).type('{downarrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + privateChannels[0].name).should('exist');
cy.get('body').type('{alt}{shift}', {release: false}).type('{downarrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + dmChannels[0].name).should('exist');
// # No navigation - stay in place
cy.get('body').type('{alt}{shift}', {release: false}).type('{downarrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + dmChannels[0].name).should('exist');
});
// # Handle favorite channels
const favPrivateChannels = [];
const favPublicChannels = [];
const favDMChannels = [];
// # Set up public favorite channel
cy.apiCreateChannel(team.id, 'public', 'public').then(({channel}) => {
favPublicChannels.push(channel);
cy.apiAddUserToChannel(channel.id, otherUser.id);
markAsFavorite(channel.name);
});
// # Set up private favorite channel
cy.apiCreateChannel(team.id, 'private', 'private', 'P').then(({channel}) => {
favPrivateChannels.push(channel);
cy.apiAddUserToChannel(channel.id, otherUser.id);
markAsFavorite(channel.name);
});
// # Set up DM favorite channel
cy.apiCreateDirectChannel([testUser.id, otherUser.id]).wait(TIMEOUTS.ONE_SEC).then(({channel}) => {
favDMChannels.push(channel);
cy.visit(`/${team.name}/channels/${testUser.id}__${otherUser.id}`);
cy.uiGetPostTextBox().clear().type(`message from ${testUser.username}`).type('{enter}');
markAsFavorite(channel.name);
});
// # Add posts by second user to the newly created channels in the first team
cy.apiLogout();
cy.apiLogin(otherUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
cy.get('#sidebarItem_' + favPublicChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to public channel').type('{enter}');
cy.get('#sidebarItem_' + favPrivateChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type('message to private channel').type('{enter}');
cy.get('#sidebarItem_' + favDMChannels[0].name).scrollIntoView().click();
cy.uiGetPostTextBox().clear().type(`direct message from ${otherUser.username}`).type('{enter}');
});
cy.apiLogout();
cy.apiLogin(testUser).then(() => {
cy.visit(`/${team.name}/channels/off-topic`);
// # Verify that the channels are unread - in the Favorites tab the unread channels are ordered alphabetically
cy.get(`#sidebarItem_${favDMChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${favPrivateChannels[0].name}`).should('have.class', 'unread-title');
cy.get(`#sidebarItem_${favPublicChannels[0].name}`).should('have.class', 'unread-title');
// # Navigate to the middle of the list of unread favorite channels
cy.get('#sidebarItem_' + favPrivateChannels[0].name).scrollIntoView().click();
cy.get('.active').find('#sidebarItem_' + favPrivateChannels[0].name).should('exist');
// # Press alt + shift + down
cy.get('body').type('{alt}{shift}', {release: false}).type('{downarrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + favPublicChannels[0].name).should('exist');
cy.get('body').type('{alt}{shift}', {release: false}).type('{downarrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + favDMChannels[0].name).should('exist');
// # No navigation - stay in place
cy.get('body').type('{alt}{shift}', {release: false}).type('{downarrow}').type('{alt}{shift}', {release: true});
cy.get('.active').find('#sidebarItem_' + favDMChannels[0].name).should('exist');
});
});
});
it('MM-T1240 - CTRL/CMD+K: Open and close', () => {
// # Type CTRL/CMD+K to open 'Switch Channels' modal
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K').then(() => {
// * Channel switcher hint should be visible and focused on
cy.get('#quickSwitchHint').should('be.visible');
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.focused');
});
// # Type CTRL/CMD+K to close 'Switch Channels' modal
cy.get('body').cmdOrCtrlShortcut('K');
cy.get('#quickSwitchHint').should('not.exist');
});
it('MM-T1248 - CTRL/CMD+SHIFT+L - Set focus to center channel message box', () => {
// # Open search box to change focus
cy.get('#searchBox').click().should('be.focused').then(() => {
// # Type CTRL/CMD+SHIFT+L
cy.get('body').cmdOrCtrlShortcut('{shift}L');
cy.uiGetPostTextBox().should('be.focused');
});
// # Post a message and open RHS
const message = `hello${Date.now()}`;
cy.postMessage(message);
cy.getLastPostId().then((postId) => {
// # Mouseover the post and click post comment icon.
cy.clickPostCommentIcon(postId);
cy.uiGetReplyTextBox().focus().should('be.focused');
}).then(() => {
// # Type CTRL/CMD+SHIFT+L
cy.get('body').cmdOrCtrlShortcut('{shift}L');
cy.uiGetPostTextBox().should('be.focused');
});
});
it('MM-T1252 - CTRL/CMD+SHIFT+A', () => {
// # Type CTRL/CMD+SHIFT+A to open 'Profile' modal
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}A');
cy.uiGetSettingsModal().should('be.visible');
// # Type CTRL/CMD+SHIFT+A to close 'Profile' modal
cy.get('body').cmdOrCtrlShortcut('{shift}A');
cy.uiGetSettingsModal().should('not.exist');
});
it('MM-T1278 - CTRL/CMD+SHIFT+K', () => {
// # Type CTRL/CMD+SHIFT+K to open 'Direct Messages' modal
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}K');
cy.get('#moreDmModal').should('be.visible').contains('Direct Messages');
// # Type CTRL/CMD+SHIFT+K to close 'Direct Messages' modal
cy.get('body').cmdOrCtrlShortcut('{shift}K');
cy.get('#moreDmModal').should('not.exist');
});
it('MM-T4452 - CTRL/CMD+SHIFT+. Expand or collapse RHS when RHS is already open', () => {
// # Post a message in center
cy.postMessage(messages.TINY);
// # Mouseover the post and click post comment icon.
cy.clickPostCommentIcon();
// # Type CTRL/CMD+SHIFT+. to expand 'RHS'
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}.');
// * Verify RHS is now expanded
cy.uiGetRHS().isExpanded();
// # Type CTRL/CMD+SHIFT+. to collapse 'RHS'
cy.get('body').cmdOrCtrlShortcut('{shift}.');
// * Verify RHS is now in collapsed state
cy.get('#sidebar-right').should('be.visible').and('not.have.class', 'sidebar--right--expanded');
});
it('MM-T4452 - CTRL/CMD+SHIFT+. Expand or collapse RHS when RHS is in closed state', () => {
// # Type CTRL/CMD+SHIFT+. to open 'RHS'
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}.');
// * Verify RHS is now open and is in collapsed state
cy.get('#sidebar-right').should('be.visible').and('not.have.class', 'sidebar--right--expanded');
// # Type CTRL/CMD+SHIFT+. to expand 'RHS'
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}.');
// * Verify RHS is now fully expanded
cy.uiGetRHS().isExpanded();
// # Type CTRL/CMD+SHIFT+. to collapse 'RHS'
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{shift}.');
// * Verify RHS is now in collapsed state
cy.get('#sidebar-right').should('be.visible').and('not.have.class', 'sidebar--right--expanded');
});
function markAsFavorite(channelName) {
// # Visit the channel
cy.get(`#sidebarItem_${channelName}`).scrollIntoView().click();
cy.get('#postListContent').should('be.visible');
// # Remove from Favorites if already set
cy.get('#channelHeaderInfo').then((el) => {
if (el.find('#toggleFavorite.active').length) {
cy.get('#toggleFavorite').click();
}
});
// # Mark it as Favorite
cy.get('#toggleFavorite').click();
}
});

Просмотреть файл

@@ -0,0 +1,206 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import * as TIMEOUTS from '../../../fixtures/timeouts';
import {isMac} from '../../../utils';
describe('Keyboard Shortcuts', () => {
let testTeam;
let testUser;
let otherUser;
before(() => {
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testUser = user;
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiAddUserToTeam(testTeam.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(channel.id, otherUser.id);
});
});
});
});
beforeEach(() => {
// # Login as admin and visit town-square
cy.apiAdminLogin();
cy.visit(`/${testTeam.name}/channels/town-square`);
});
it('MM-T1239 - CTRL+/ and CMD+/ and /shortcuts', () => {
// # Type CTRL/CMD+/
cy.uiGetPostTextBox().cmdOrCtrlShortcut('/');
// # Verify that the 'Keyboard Shortcuts' modal is open
modalShouldOpen();
// # Verify that the 'Keyboard Shortcuts' modal displays the CTRL/CMD+U shortcut
cy.get('.section').eq(2).within(() => {
cy.findByText('Files').should('be.visible');
cy.get('.shortcut-line').should('be.visible').as('shortcutLine');
if (isMac()) {
cy.get('@shortcutLine').findByText('⌘').should('be.visible');
} else {
cy.get('@shortcutLine').findByText('Ctrl').should('be.visible');
}
cy.get('@shortcutLine').findByText('U').should('be.visible');
});
// # Type CTRL/CMD+/ to close the 'Keyboard Shortcuts' modal
cy.get('body').cmdOrCtrlShortcut('/');
cy.get('#shortcutsModalLabel').should('not.exist');
// # Type /shortcuts
cy.uiGetPostTextBox().clear().type('/shortcuts{enter}');
modalShouldOpen();
// # Close the 'Keyboard Shortcuts' modal using the x button
cy.get('.modal-header button.close').should('have.attr', 'aria-label', 'Close').click();
cy.get('#shortcutsModalLabel').should('not.exist');
// # Type /shortcuts
cy.uiGetPostTextBox().clear().type('/shortcuts{enter}');
// # Close the 'Keyboard Shortcuts' modal by pressing ESC key
cy.get('body').type('{esc}');
cy.get('#shortcutsModalLabel').should('not.exist');
});
it('MM-T1254 - CTRL/CMD+UP; CTRL/CMD+DOWN', () => {
const messagePrefix = 'hello from current user: ';
let message;
const count = 5;
// # Post messages to the center channel
for (let index = 0; index < count; index++) {
message = messagePrefix + index;
cy.postMessage(message);
}
for (let index = 0; index < count; index++) {
// # Type CTRL/CMD+UP
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{uparrow}');
// # Verify that the previous message is displayed
message = messagePrefix + (4 - index);
cy.uiGetPostTextBox().contains(message);
}
// # One extra CTRL/CMD+UP does not change the displayed message
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{uparrow}');
message = messagePrefix + '0';
cy.uiGetPostTextBox().contains(message);
for (let index = 1; index < count; index++) {
// # Type CTRL/CMD+DOWN
cy.uiGetPostTextBox().cmdOrCtrlShortcut('{downarrow}');
// # Verify that the next message is displayed
message = messagePrefix + index;
cy.uiGetPostTextBox().contains(message);
}
});
it('MM-T1260 - UP arrow', () => {
const message = 'Test';
const editMessage = 'Edit Test';
// # Post message text
cy.uiGetPostTextBox().clear().type(message).type('{enter}').wait(TIMEOUTS.HALF_SEC);
// # Edit previous post
cy.getLastPostId().then(() => {
cy.uiGetPostTextBox().type('{uparrow}');
// * Edit Post Input should appear
cy.get('#edit_textbox').should('be.visible');
// * Edit to the post message and type ENTER
cy.get('#edit_textbox').invoke('val', '').clear().type(editMessage).type('{enter}').wait(TIMEOUTS.HALF_SEC);
});
cy.getLastPostId().then((postId) => {
// * Post should have "Edited"
cy.get(`#postEdited_${postId}`).
should('be.visible').
should('contain', 'Edited');
});
});
it('MM-T1273 - @[character]+TAB', () => {
const userName = `${testUser.username}`;
// # Enter the first characters of a user name
cy.uiGetPostTextBox().clear().type('@' + userName.substring(0, 5)).wait(TIMEOUTS.HALF_SEC);
// # Select the focused on user from the list using TAB
cy.get('#suggestionList').should('be.visible').focused().tab();
// # Verify that the correct user name has been selected
cy.uiGetPostTextBox().should('contain', userName);
// # Clear the message box
cy.uiGetPostTextBox().clear();
});
it('MM-T1274 - :[character]+TAB', () => {
const emojiName = ':tomato';
// # Enter the first characters of an emoji name
cy.uiGetPostTextBox().clear().type(emojiName.substring(0, 3)).wait(TIMEOUTS.HALF_SEC);
// # Go down the list of emojis
cy.get('body').type('{downarrow}').wait(TIMEOUTS.HALF_SEC);
cy.get('body').type('{downarrow}').wait(TIMEOUTS.HALF_SEC);
cy.get('body').type('{downarrow}').wait(TIMEOUTS.HALF_SEC);
cy.get('body').type('{downarrow}').wait(TIMEOUTS.HALF_SEC);
// # Select the fourth emoji from the top using TAB
cy.get('#suggestionList').should('be.visible').focused().tab();
// # Verify that the correct selection has been made
cy.uiGetPostTextBox().should('contain', emojiName);
});
it('MM-T1275 - SHIFT+UP', () => {
const message = `hello${Date.now()}`;
// # Post message to center channel
cy.postMessage(message);
// # Press SHIFT+UP
cy.uiGetPostTextBox().type('{shift}{uparrow}');
// # Verify that the RHS reply box is focused
cy.uiGetReplyTextBox().should('be.focused');
// * Verify that the recently posted message is shown in the RHS
cy.getLastPostId().then((postId) => {
cy.get(`#rhsPostMessageText_${postId}`).should('exist');
});
});
it('MM-T1279 - Keyboard shortcuts menu item', () => {
// # Click "Keyboard shortcuts" at help menu
cy.uiOpenHelpMenu('Keyboard shortcuts');
modalShouldOpen();
});
});
function modalShouldOpen() {
const name = isMac() ? /Keyboard shortcuts ⌘ \// : /Keyboard shortcuts Ctrl \//;
cy.findByRole('dialog', {name}).should('be.visible');
}

Просмотреть файл

@@ -0,0 +1,102 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @keyboard_shortcuts
import {isMac} from '../../../utils';
describe('Keyboard Shortcuts', () => {
const count = 5;
const teams = [];
const channels = [];
before(() => {
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
cy.apiLogin(sysadmin);
const prefix = 't0';
cy.apiInitSetup({teamPrefix: {name: prefix, displayName: prefix}, channelPrefix: {name: prefix, displayName: prefix}}).then(({team, channel}) => {
teams.push(team);
channels.push(channel);
cy.visit(`/${team.name}/channels/${channel.name}`);
cy.postMessage('hello');
for (let index = 1; index < count; index++) {
const otherPrefix = `t${index}`;
cy.apiCreateTeam(otherPrefix, otherPrefix).then(({team: otherTeam}) => {
teams.push(otherTeam);
cy.apiCreateChannel(otherTeam.id, otherPrefix, otherPrefix).then(({channel: otherChannel}) => {
channels.push(otherChannel);
cy.visit(`/${otherTeam.name}/channels/${otherChannel.name}`);
cy.postMessage('hello');
});
});
}
});
});
});
it('MM-T1575 - Ability to Switch Teams', () => {
for (let index = 0; index < count; index++) {
// # Verify that we've switched to the correct team
cy.uiGetLHSHeader().findByText(teams[count - index - 1].display_name);
// # Verify that we've switched to the correct channel
cy.get('#channelHeaderTitle').should('be.visible').should('contain', channels[count - index - 1].display_name);
// # Press CTRL/CMD+SHIFT+UP
if (isMac()) {
cy.get('body').type('{cmd}{option}', {release: false}).type('{uparrow}').type('{cmd}{option}', {release: true});
} else {
cy.get('body').type('{ctrl}{shift}', {release: false}).type('{uparrow}').type('{ctrl}{shift}', {release: true});
}
}
for (let index = 0; index < count; index++) {
// # Press CTRL/CMD+SHIFT+DOWN
if (isMac()) {
cy.get('body').type('{cmd}{option}', {release: false}).type('{downarrow}').type('{cmd}{option}', {release: true});
} else {
cy.get('body').type('{ctrl}{shift}', {release: false}).type('{downarrow}').type('{ctrl}{shift}', {release: true});
}
// # Verify that we've switched to the correct team
cy.uiGetLHSHeader().findByText(teams[index].display_name);
// # Verify that we've switched to the correct channel
cy.get('#channelHeaderTitle').should('be.visible').should('contain', channels[index].display_name);
}
for (let index = 1; index <= count; index++) {
// # Press CTRL/CMD+SHIFT+index
if (isMac()) {
cy.get('body').type('{cmd}{option}', {release: false}).type(String(index)).type('{cmd}{option}', {release: true});
} else {
cy.get('body').type('{ctrl}{shift}', {release: false}).type(String(index)).type('{ctrl}{shift}', {release: true});
}
// # Verify that we've switched to the correct team
cy.uiGetLHSHeader().findByText(teams[index - 1].display_name);
// # Verify that we've switched to the correct channel
cy.get('#channelHeaderTitle').should('be.visible').should('contain', channels[index - 1].display_name);
}
// # Verify keyboard shortcuts in Keyboard Shortcuts modal
cy.uiOpenHelpMenu('Keyboard shortcuts');
const name = isMac() ? /Keyboard Shortcuts ⌘ \// : /Keyboard Shortcuts Ctrl \//;
cy.findByRole('dialog', {name}).within(() => {
cy.findByText('Navigation').should('be.visible');
cy.findByText('Previous team:').should('be.visible');
cy.findAllByText('Next team:').should('be.visible');
cy.findAllByText('Navigate to a specific team:').should('be.visible');
});
});
});

Просмотреть файл

@@ -0,0 +1,41 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({offTopicUrl}) => {
// # Visit a test channel
cy.visit(offTopicUrl);
cy.postMessage('Hello World');
});
});
it('MM-T1277 SHIFT+UP', () => {
// # Press shift+up to open the latest thread in the channel in the RHS
cy.uiGetPostTextBox().type('{shift}{uparrow}');
// * RHS Opens up
cy.get('.sidebar--right__header').should('be.visible');
// * RHS textbox should be focused
cy.uiGetReplyTextBox().should('be.focused');
// # Click into the post textbox in the center channel
cy.uiGetPostTextBox().click();
// # Press shift+up again
cy.uiGetPostTextBox().type('{shift}{uparrow}');
// * RHS textbox should be focused
cy.uiGetReplyTextBox().should('be.focused');
});
});

Просмотреть файл

@@ -0,0 +1,50 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({offTopicUrl}) => {
// # Visit off-topic channel
cy.visit(offTopicUrl);
});
});
it('MM-T1265 UP - System message does not open for edit; opens previous regular message', () => {
const message = 'Test message';
const newHeader = 'New Header';
// # Post message in the channel from User
cy.postMessage(message);
// # Open the edit the channel header modal
cy.findByRole('button', {name: 'Set a Header dialog'}).click();
// * Verify modal is open
cy.findByRole('dialog', {name: 'Edit Header for Off-Topic'}).within(() => {
// # Enter new header and save
cy.findByRole('textbox', {name: 'edit the channel header...'}).type(newHeader);
cy.uiSave();
});
// * Wait for the system message to be posted
cy.uiWaitUntilMessagePostedIncludes(newHeader);
// # Press UP arrow
cy.findByTestId('post_textbox').
type('{uparrow}');
// * Verify that the Edit Post Input is visible
cy.get('#edit_textbox').
should('be.visible').
should('have.text', message);
});
});

Просмотреть файл

@@ -0,0 +1,43 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
describe('Keyboard Shortcuts', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
// # Visit a test channel
cy.visit(channelUrl);
});
});
it('MM-T1261 UP arrow', () => {
cy.postMessage('Hello World');
cy.getLastPostId().then((postId) => {
// # Add a reply message, to have RHS container open
cy.clickPostDotMenu(postId);
cy.findByText('Reply').click();
const replyMessage = 'Well, hello there.';
cy.uiGetReplyTextBox().type(replyMessage);
cy.uiGetReplyTextBox().type('{enter}');
cy.uiWaitUntilMessagePostedIncludes(replyMessage);
// # Press up arrow key
cy.get('body').type('{uparrow}');
// * Verify that the Edit Post Input is visible
cy.get('#edit_textbox').should('be.visible');
// * Verify that edit box have value of edited message
cy.get('#edit_textbox').should('have.value', replyMessage);
});
});
});

Просмотреть файл

@@ -0,0 +1,319 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @keyboard_shortcuts
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Keyboard Shortcuts', () => {
let testTeam;
let testChannel;
let testUser;
let otherUser;
before(() => {
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;
testUser = user;
cy.apiCreateUser({prefix: 'other'}).then(({user: user1}) => {
otherUser = user1;
cy.apiAddUserToTeam(testTeam.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
});
});
});
});
it('MM-T1235 Arrow up key - no Edit modal open up if user has not posted any message yet', () => {
const message2 = 'Test message from User 2';
cy.apiLogin(otherUser);
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Post message in the channel from User 2
cy.postMessage(message2);
cy.apiLogout();
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Press UP arrow
cy.uiGetPostTextBox().type('{uparrow}');
// * Verify that Edit modal should not be visible
cy.get('#edit_textbox').should('not.exist');
});
it('MM-T1236 Arrow up key - Edit Input opens up for own message of a user', () => {
const message1 = 'Test message from User 1';
const message2 = 'Test message from User 2';
cy.apiLogin(testUser);
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Post message in the channel from User 1
cy.postMessage(message1);
cy.apiLogout();
cy.apiLogin(otherUser);
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Post message in the channel from User 2
cy.postMessage(message2);
cy.apiLogout();
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Press UP arrow
cy.uiGetPostTextBox().type('{uparrow}');
// * Verify that the Edit Post Input is visible
cy.get('#edit_textbox').should('be.visible');
// * Verify that the Edit textbox contains previously sent message by user 1
cy.get('#edit_textbox').should('have.text', message1);
});
it('MM-T1271_1 UP - Removing all text in edit deletes post if without attachment', () => {
const message = 'Message to be deleted';
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Post message
cy.postMessage(message);
cy.uiWaitUntilMessagePostedIncludes(message);
cy.getLastPostId().then((postID) => {
// * Verify that testuser sees post
cy.get(`#postMessageText_${postID}`).should('contain', message);
cy.uiGetPostTextBox().type('{uparrow}');
// * Validate that edit box contains just posted message
cy.get('#edit_textbox').should('have.text', message);
// # Clear all text, delete and confirm by pressing enter
cy.wait(TIMEOUTS.HALF_SEC);
cy.get('#edit_textbox').clear().type('{enter}');
// * Verify confirm modal is shown
cy.findByRole('dialog', {name: 'Confirm Post Delete'}).should('be.visible');
// # Press enter on confirm dialog
cy.uiGetButton('Delete').click();
// * Verify post is deleted
cy.get(`#postMessageText_${postID}`).should('not.exist');
});
// # Post message as other user
cy.postMessageAs({sender: otherUser, message, channelId: testChannel.id});
cy.uiWaitUntilMessagePostedIncludes(message);
cy.getLastPostId().then((postID) => {
cy.get(`#postMessageText_${postID}`).should('contain', message);
// # Delete message as test user
cy.externalRequest({user: otherUser, method: 'DELETE', path: `posts/${postID}`});
// * Verify that other user sees that message is deleted
cy.get(`#post_${postID} #${postID}_message`).should('have.text', '(message deleted)');
});
});
it('MM-T1271_2 UP - Removing all text in edit does not delete post if with attachment', () => {
const message = 'This is a message';
const filename = 'mattermost-icon.png';
cy.apiLogin(testUser);
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Post message with attachment
cy.get('#fileUploadInput').attachFile(filename);
cy.postMessage(message);
// * Verify that the message and file attachment is posted
cy.uiWaitUntilMessagePostedIncludes(message);
cy.uiGetFileThumbnail(filename).should('be.visible');
// # Press up arrow
cy.uiGetPostTextBox().type('{uparrow}');
cy.wait(TIMEOUTS.HALF_SEC);
// # Clear all text and confirm
cy.get('#edit_textbox').clear().type('{enter}');
// * Delete post confirm modal should not exist
cy.get('#deletePostModal').should('not.exist');
// * Verify that attachment is still visible
cy.uiGetFileThumbnail(filename).should('be.visible');
// * Post should contain edited tag
cy.getLastPostId().then((postId) => {
// * Post should have "Edited"
cy.get(`#postEdited_${postId}`).
should('be.visible').
should('contain', 'Edited');
});
// # Login with other user
cy.apiLogout();
cy.apiLogin(otherUser);
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// * Verify that attachment is still visible
cy.uiGetFileThumbnail(filename).should('be.visible');
// * Post should contain edited tag
cy.getLastPostId().then((postId) => {
// * Post should have "Edited"
cy.get(`#postEdited_${postId}`).
should('be.visible').
should('contain', 'Edited');
});
});
it('MM-T1272 Arrow up key - Removing all text in edit deletes reply', () => {
const message = 'Test message from User 1';
const reply = 'Reply from User 1';
cy.apiLogin(testUser);
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Post message in the channel from User 1
cy.postMessage(message);
// # Reply to message
cy.getLastPostId().then((postId) => {
cy.clickPostCommentIcon(postId);
cy.postMessageReplyInRHS(reply);
});
cy.getLastPostId().then((postID) => {
// # Press UP arrow
cy.uiGetPostTextBox().type('{uparrow}');
cy.wait(TIMEOUTS.HALF_SEC);
// # Clear message and type ENTER
cy.get('#edit_textbox').clear().type('{enter}');
// * Delete post confirmation modal should be visible
cy.get('#deletePostModal').should('be.visible');
// # Confirm delete
cy.get('#deletePostModalButton').click();
// * Assert post message disappears
cy.get(`#postMessageText_${postID}`).should('not.exist');
});
});
it('MM-T1269 Arrow up key - Edit code block', () => {
const messageWithCodeblock1 = '```{shift}{enter}codeblock1{shift}{enter}```{shift}{enter}';
const messageWithCodeblock2 = '```{shift}{enter}codeblock2{shift}{enter}```{shift}{enter}';
cy.apiLogin(testUser);
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Post code block message from User 1
cy.uiGetPostTextBox().type(messageWithCodeblock1).type('{enter}');
cy.uiWaitUntilMessagePostedIncludes('codeblock1');
// # Press UP arrow
cy.uiGetPostTextBox().type('{uparrow}');
// # Edit text
cy.get('#edit_textbox').clear().type(messageWithCodeblock2).type('{enter}');
// * Verify that the message was edited
cy.uiWaitUntilMessagePostedIncludes('codeblock2');
});
it('MM-T1264 Arrow up key - Ephemeral message does not open for edit; opens previous regular message', () => {
// # Type user message
const message = 'Hello World';
cy.postMessage(message);
// # Type "/code" with no text to receive ephemeral message
cy.postMessage('/code ');
// * Verify if an ephemeral message was received
cy.findByText('(Only visible to you)').should('exist');
cy.findByText('A message must be provided with the /code command.').should('exist');
// # Press up arrow key
cy.get('body').type('{uparrow}');
// * Verify that the Edit Post Input is visible
cy.get('#edit_textbox').should('be.visible');
// * Verify that edit box have value of previous regular message
cy.get('#edit_textbox').should('have.value', message);
});
it('MM-T1270 UP - Edit message with attachment but no text', () => {
cy.apiLogin(testUser);
// # Visit the channel using the channel name
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Upload file
cy.get('#fileUploadInput').attachFile('mattermost-icon.png');
// # Wait for file to upload
cy.wait(TIMEOUTS.TWO_SEC);
cy.uiGetPostTextBox().type('{enter}');
cy.getLastPost().within(() => {
// * Attachment should exist
cy.get('.file-view--single').should('exist');
// * Edited indicator should not exist
cy.get('.post-edited__indicator').should('not.exist');
});
// # Press UP arrow
cy.uiGetPostTextBox().type('{uparrow}');
// # Add some text to the previous message and save
cy.get('#edit_textbox').type('Test').type('{enter}');
cy.wait(TIMEOUTS.ONE_SEC);
cy.getLastPost().within(() => {
// * Posted message should be correct
cy.get('.post-message__text').should('contain.text', 'Test');
// * Attachment should exist
cy.get('.file-view--single').should('exist');
// * Edited indicator should exist
cy.get('.post-edited__indicator').should('exist');
});
});
});