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

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

@@ -0,0 +1,182 @@
// 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 @integrations
import * as TIMEOUTS from '../../../../fixtures/timeouts';
import {getRandomId} from '../../../../utils';
import {verifyEphemeralMessage} from './helper';
describe('Integrations', () => {
let testUser;
let otherUser;
let offTopicUrl;
let channelUrl;
before(() => {
cy.apiInitSetup().then((out) => {
testUser = out.user;
offTopicUrl = out.offTopicUrl;
channelUrl = out.channelUrl;
cy.apiCreateUser({prefix: 'other'}).then(({user}) => {
otherUser = user;
cy.apiAddUserToTeam(out.team.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(out.channel.id, otherUser.id);
});
});
cy.apiLogin(testUser);
});
});
beforeEach(() => {
cy.visit(channelUrl);
cy.postMessage('hello');
});
it('MM-T573 / autocomplete list can scroll', () => {
// # Clear post textbox
cy.uiGetPostTextBox().clear().type('/');
// * Suggestion list should be visible
// # Scroll to bottom and verify that the last command "/shrug" is visible
cy.get('#suggestionList', {timeout: TIMEOUTS.FIVE_SEC}).should('be.visible').scrollTo('bottom').then((container) => {
cy.contains('/away', {container}).should('not.be.visible');
cy.contains('/shrug [message]', {container}).should('be.visible');
});
// # Scroll to top and verify that the first command "/away" is visible
cy.get('#suggestionList').scrollTo('top').then((container) => {
cy.contains('/away', {container}).should('be.visible');
cy.contains('/shrug [message]', {container}).should('not.be.visible');
});
});
it('MM-T678 /code', () => {
const message = '1. Not a list item, **not bolded**, http://notalink.com, ~off-topic is not a link to the channel.';
// # Use "/code"
cy.postMessage(`/code ${message} `);
// * Verify that that markdown isn't rendered
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).find('.user-popover').should('have.text', testUser.username);
cy.get(`#postMessageText_${postId}`).get('code').should('contain', message);
});
// # Type "/code" with no text
cy.postMessage('/code ');
// * Verify that an error message is shown
verifyEphemeralMessage('A message must be provided with the /code command.');
});
it('MM-T679 /echo', () => {
const message = getRandomId();
// # Type "/echo message 3"
cy.uiGetPostTextBox().clear().type(`/echo ${message} 3{enter}`);
// * Verify that post is not shown after 1 second
cy.wait(TIMEOUTS.ONE_SEC);
cy.getLastPost().within(() => {
cy.findByText(message).should('not.exist');
});
// * Verify that message is posted after 3 seconds
cy.wait(TIMEOUTS.TWO_SEC);
cy.getLastPost().within(() => {
cy.findByText(testUser.username);
cy.findByText(message);
});
});
it('MM-T680 /help', () => {
// # Type "/help"
cy.postMessage('/help ');
// # get last posted message
cy.wait(TIMEOUTS.HALF_SEC).getLastPostId().then((botLastPostId) => {
cy.get(`#post_${botLastPostId}`).within(() => {
// * Check if Bot message only visible to you
cy.findByText('(Only visible to you)').should('exist');
// * Check if we got ephemeral message of our selection
cy.contains('Mattermost is an open source platform for secure communication').should('exist');
});
});
});
it('MM-T681 /invite_people error message with no text or text that is not an email address', () => {
// # Type "/invite_people 123"
cy.postMessage('/invite_people 123');
// * Verify the message is shown saying "Please specify one or more valid email addresses"
verifyEphemeralMessage('Please specify one or more valid email addresses');
});
it('MM-T682 /leave', () => {
// # Go to Off-Topic
cy.visit(offTopicUrl);
// # Type "/leave"
cy.postMessage('/leave ');
// * Verity Off-Topic is not shown in LHS
cy.get('#sidebar-left').should('be.visible').should('not.contain', 'Off-Topic');
// * Verify user is redirected to Town Square
cy.uiGetLhsSection('CHANNELS').find('.active').should('contain', 'Town Square');
cy.get('#channelHeaderTitle').should('be.visible').should('contain', 'Town Square');
});
it('MM-T574 /shrug test', () => {
// # Login as otherUser and post a message
cy.getCurrentChannelId().then((channelId) => {
cy.postMessageAs({sender: otherUser, message: 'hello from otherUser', channelId});
});
const message = getRandomId();
// # Post "/shrug test" as testUser
cy.postMessage(`/shrug ${message} `);
// * Verify that it posted message as expected from testUser
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).find('.user-popover').should('have.text', testUser.username);
cy.get(`#postMessageText_${postId}`).should('have.text', `${message} ¯\\_(ツ)_/¯`);
});
// * Login as otherUser and verify that it read the same message as expected from testUser
cy.apiLogin(otherUser);
cy.visit(channelUrl);
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).find('.user-popover').should('have.text', testUser.username);
cy.get(`#postMessageText_${postId}`).should('have.text', `${message} ¯\\_(ツ)_/¯`);
});
});
it('MM-T5100 /marketplace test', () => {
cy.apiAdminLogin();
cy.apiInitSetup().then(({team}) => {
// # Go to town square
cy.visit(`/${team.name}/channels/town-square`);
// # Post "/marketplace" as SystemAdmin
cy.postMessage('/marketplace ');
cy.get('#modal_marketplace').should('be.visible');
});
});
});

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

@@ -0,0 +1,150 @@
// 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 @integrations
import * as TIMEOUTS from '../../../../fixtures/timeouts';
import {getRandomId} from '../../../../utils';
describe('Integrations', () => {
let testUser;
let testChannel;
let otherChannel;
before(() => {
cy.apiInitSetup({userPrefix: 'testUser'}).then(({team, user, channel}) => {
testUser = user;
testChannel = channel;
cy.apiCreateChannel(team.id, 'other-channel', 'Other Channel').then((out) => {
otherChannel = out.channel;
});
cy.apiLogin(testUser);
cy.visit('/');
});
});
beforeEach(() => {
cy.get('#sidebarItem_off-topic').click();
cy.uiGetPostTextBox();
});
it('MM-T683 /join', () => {
// # Type "/join ~new-channel"
cy.postMessage(`/join ~${otherChannel.name} `);
// * Verify user is redirected to New Channel
cy.get('#channelHeaderTitle').should('be.visible').should('contain', otherChannel.display_name);
});
it('MM-T684 /me', () => {
// # Type "/me message"
const message = getRandomId();
cy.postMessage(`/me ${message}`);
// * Verify a message is posted
cy.uiWaitUntilMessagePostedIncludes(message);
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).find('.user-popover').should('have.text', testUser.username);
cy.get(`#postMessageText_${postId}`).should('have.text', message);
// * The message should match other system message formatting.
cy.get(`#post_${postId}`).should('have.class', 'post--system');
});
});
it('MM-T685 /me not case-sensitive', () => {
// # Type "/Me message"
const message = getRandomId();
cy.postMessage(`/Me ${message}`);
// * Verify a message is posted
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).find('.user-popover').should('have.text', testUser.username);
cy.get(`#postMessageText_${postId}`).should('have.text', message);
});
});
it('MM-T2345 /me on RHS', () => {
cy.get(`#sidebarItem_${testChannel.name}`).click();
cy.get('#channelHeaderTitle').should('be.visible').should('contain', testChannel.display_name);
const rootMessage = 'root message';
cy.postMessage(rootMessage);
// # Open RHS (reply thread)
cy.clickPostCommentIcon();
cy.getLastPostId().then((postId) => {
// * Verify the message, both in RHS and center, is from current user
// and formatted with full opacity
[`#rhsPost_${postId}`, `#post_${postId}`].forEach((selector) => {
cy.get(selector).should('have.class', 'current--user').within(() => {
cy.get('.post__header').findByText(testUser.username);
cy.get('.post-message__text').findByText(rootMessage).should('have.css', 'color', 'rgb(63, 67, 80)');
});
});
});
// # type /me message
const message = 'reply';
cy.postMessageReplyInRHS(`/me ${message} `);
cy.uiWaitUntilMessagePostedIncludes(message);
cy.getLastPostId().then((postId) => {
// * Verify the message reply, both in RHS and center, is from current user and formatted with lower opacity
[`#rhsPost_${postId}`, `#post_${postId}`].forEach((selector) => {
cy.get(selector).should('have.class', 'current--user').within(() => {
cy.get('.profile-icon').should('not.be.visible');
cy.get('.post-message__text').findByText(message).should('have.css', 'color', 'rgba(63, 67, 80, 0.6)');
});
});
});
});
it('MM-T710 /mute error message', () => {
const invalidChannel = `invalid-channel-${getRandomId()}`;
// # Type /mute with random characters
cy.postMessage(`/mute ${invalidChannel} `);
cy.uiWaitUntilMessagePostedIncludes('Please use the channel handle to identify channels');
cy.getLastPostId().then((postId) => {
// * Should return an error message
cy.get(`#postMessageText_${postId}`).
should('have.text', `Could not find the channel ${invalidChannel}. Please use the channel handle to identify channels.`).
// * Channel handle links to: https://docs.mattermost.com/messaging/managing-channels.html#naming-a-channel
contains('a', 'channel handle').then((link) => {
const href = link.prop('href');
cy.request(href).its('allRequestResponses').then((response) => {
cy.wrap(response[0]['Request URL']).should('equal', 'https://docs.mattermost.com/messaging/managing-channels.html#naming-a-channel');
});
});
});
});
it('MM-T2834 Slash command help stays visible for system slash command', () => {
// # Type the rename slash command in textbox
cy.uiGetPostTextBox().clear().type('/rename ');
// # Scan inside of suggestion list
cy.get('#suggestionList').should('exist').and('be.visible').within(() => {
// * Verify that renaming part of rename autosuggestion is still
// visible in the autocomplete, since [text] is same as description and title, we will check if title exists
cy.findAllByText('[text]').first().should('exist');
});
// # Append Hello to /rename and hit enter
cy.uiGetPostTextBox().type('Hello{enter}').wait(TIMEOUTS.HALF_SEC);
cy.uiGetPostTextBox().invoke('text').should('be.empty');
});
});

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

@@ -0,0 +1,32 @@
// 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 @integrations
import * as TIMEOUTS from '../../../../fixtures/timeouts';
describe('Integrations', () => {
before(() => {
cy.apiInitSetup({loginAfter: true}).then(() => {
cy.visit('/');
cy.postMessage('hello');
});
});
// This test was moved here since Cypress is behaving differently as compared to browser
// and kept redirecting into the landing page even if the corresponding localstorage is already set.
it('MM-T686 /logout', () => {
// # Type "/logout"
cy.uiGetPostTextBox().should('be.visible').clear().type('/logout {enter}').wait(TIMEOUTS.HALF_SEC);
// * Ensure that the user was redirected to the login page
cy.url().should('include', '/login');
});
});

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

@@ -0,0 +1,142 @@
// 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 @integrations
import {getRandomId} from '../../../../utils';
import {loginAndVisitChannel} from './helper';
describe('Integrations', () => {
let testUser;
const userGroup = [];
let offTopicUrl;
before(() => {
cy.apiInitSetup().then(({team, user, offTopicUrl: url}) => {
testUser = user;
offTopicUrl = url;
Cypress._.times(8, () => {
cy.apiCreateUser().then(({user: otherUser}) => {
cy.apiAddUserToTeam(team.id, otherUser.id);
userGroup.push(otherUser);
});
});
});
});
it('MM-T664 /groupmsg initial tests', () => {
function verifyPostedMessage(message, usernames) {
// * Verify that the channel header contains each group member
usernames.forEach((username) => {
cy.contains('.channel-header__top', username).should('be.visible');
});
// * Verify that the message is posted into the GM channel
cy.uiWaitUntilMessagePostedIncludes(message);
cy.getLastPostId().then((postId) => {
cy.get(`#postMessageText_${postId}`).should('have.text', message);
});
// # Go back to off-topic channel
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
}
loginAndVisitChannel(testUser, offTopicUrl);
const usernames1 = Cypress._.map(userGroup, 'username').slice(0, 4);
const usernames1Format = [
`@${usernames1[0]},@${usernames1[1]},@${usernames1[2]},@${usernames1[3]}`, // Regular usernames format
`${usernames1[0]}, @${usernames1[1]} , ${usernames1[2]} , @${usernames1[3]}`, // Irregular usernames format
];
usernames1Format.forEach((users) => {
const message = getRandomId();
// # Use /groupmsg command to send group message - "/groupmsg [usernames] [message]"
cy.postMessage(`/groupmsg ${users} ${message}`);
// * Verify it redirects into the GM channel with new message posted.
verifyPostedMessage(message, usernames1);
// # Use /groupmsg command to send message to existing GM - "group msg [usernames]" (note: no message)
cy.postMessage(`/groupmsg ${users} `);
// * Verify it redirects into the GM channel without new message posted.
verifyPostedMessage(message, usernames1);
});
const usernames2 = Cypress._.map(userGroup, 'username').slice(1, 5);
const usernames2Format = [
`@${usernames2[0]}, @${usernames2[1]}, @${usernames2[2]}, @${usernames2[3]}`, // Regular usernames format
`${usernames2[0]}, @${usernames2[1]} , ${usernames2[2]} , @${usernames2[3]}`, // Irregular usernames format
];
usernames2Format.forEach((users) => {
// # Use /groupmsg command to create GM - "group msg [usernames]" (note: no message)
cy.postMessage(`/groupmsg ${users} `);
// * Verify that the channel header contains each group member
usernames2.forEach((username) => {
cy.contains('.channel-header__top', username).should('be.visible');
});
});
});
it('MM-T665 /groupmsg with users only and without message', () => {
loginAndVisitChannel(testUser, offTopicUrl);
// # Use /groupmsg command to open group message - "/groupmsg [usernames]"
const usernames = Cypress._.map(userGroup, 'username').slice(0, 3);
const message = '/groupmsg @' + usernames.join(', @') + ' ';
cy.postMessage(message);
// * Verify that the channel header contains each group member
usernames.forEach((username) => {
cy.contains('.channel-header__top', username).should('be.visible');
});
});
it('MM-T666 /groupmsg error if messaging more than 7 users', () => {
loginAndVisitChannel(testUser, offTopicUrl);
// # Include more than 7 valid users in the command
const usernames = Cypress._.map(userGroup, 'username');
const message = '/groupmsg @' + usernames.join(', @') + ' hello';
cy.postMessage(message);
// * If adding more than 7 users (excluding current user), system message saying "Group messages are limited to a maximum of 7 users."
cy.uiWaitUntilMessagePostedIncludes('Group messages are limited to a maximum of 7 users');
cy.getLastPostId().then((postId) => {
cy.get(`#postMessageText_${postId}`).should('have.text', 'Group messages are limited to a maximum of 7 users.');
});
// # Include one invalid user in the command
const message2 = '/groupmsg @' + usernames.slice(0, 2).join(', @') + ', @hello again';
cy.postMessage(message2);
// * If users cannot be found, returns error that user could not be found
cy.uiWaitUntilMessagePostedIncludes('Unable to find the user: @hello');
cy.getLastPostId().then((postId) => {
cy.get(`#postMessageText_${postId}`).should('have.text', 'Unable to find the user: @hello');
});
// # Include more than one invalid user in the command
const message3 = '/groupmsg @' + usernames.slice(0, 2).join(', @') + ', @hello, @world again';
cy.postMessage(message3);
// * If users cannot be found, returns error that user could not be found
cy.uiWaitUntilMessagePostedIncludes('Unable to find the users: @hello, @world');
cy.getLastPostId().then((postId) => {
cy.get(`#postMessageText_${postId}`).should('have.text', 'Unable to find the users: @hello, @world');
});
});
});

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

@@ -0,0 +1,25 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as TIMEOUTS from '../../../../fixtures/timeouts';
export function loginAndVisitChannel(user, channelUrl) {
cy.apiLogin(user);
cy.visit(channelUrl);
cy.get('#postListContent', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
cy.uiGetPostTextBox();
}
export function verifyEphemeralMessage(message) {
// # Checking if we got the ephemeral message with the selection we made
cy.wait(TIMEOUTS.HALF_SEC).getLastPostId().then((botLastPostId) => {
cy.get(`#post_${botLastPostId}`).within(() => {
// * Check if Bot message only visible to you
cy.findByText('(Only visible to you)').should('exist');
// * Check if we got ephemeral message of our selection
cy.findByText(message).should('exist');
});
});
}

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

@@ -0,0 +1,147 @@
// 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 @integrations
import * as MESSAGES from '../../../../fixtures/messages';
describe('Invalid slash command', () => {
const incorrectCommand1 = 'notacommand-1';
const incorrectCommand2 = 'notacommand-2';
const incorrectCommand3 = 'notacommand-3';
before(() => {
// # Login as test user and visit off-topic
cy.apiInitSetup({loginAfter: true}).then(({offTopicUrl}) => {
cy.visit(offTopicUrl);
cy.postMessage('hello');
});
});
it('MM-T667 - Start message with slash and non-command', () => {
// # Type a incorrect slash command and press enter
cy.uiGetPostTextBox().type(`/${incorrectCommand1} {enter}`);
// * Check that error message of incorrect command is displayed
verifyNonCommandErrorMessageIsDisplayed(incorrectCommand1);
// * Check that focus is still the center textbox
cy.focused().should('have.id', 'post_textbox');
// # Backspace in the center textbox and verify error message disappeared
cy.uiGetPostTextBox().type('{backspace}');
verifyNonCommandErrorMessageIsNotDisplayed(incorrectCommand1);
// # Type another incorrect slash command
cy.uiGetPostTextBox().clear().type(`/${incorrectCommand2} {enter}`);
// * Check that error message of incorrect command is displayed again
verifyNonCommandErrorMessageIsDisplayed(incorrectCommand2);
// # Click on the link to post incorrect command as plain text
cy.findByText('Click here to send as a message.').click({force: true});
// * Verify the incorrect command is posted as plain text when we pressed 'click here to send as message' link
verifyLastPostedMessageContainsPlainTextOfCommand(incorrectCommand2);
// # Lets try to post incorrect message as plain text via twice enter press
cy.uiGetPostTextBox().clear().type(`/${incorrectCommand3} {enter}`);
// * Check that error message of incorrect command is displayed again
verifyNonCommandErrorMessageIsDisplayed(incorrectCommand3);
// # Lets press enter again in the textbox after error message is shown to submit command as plain text
cy.uiGetPostTextBox().type('{enter}');
// * Verify incorrect command got posted as plain text message via twice enter press
verifyLastPostedMessageContainsPlainTextOfCommand(incorrectCommand3);
});
it('MM-T668 Start reply with slash and non-command', () => {
// # Post a message in the center text plane
cy.postMessage(MESSAGES.SMALL);
// # To the last message post a reply in RHS
cy.getLastPostId().then((lastPostID) => {
cy.clickPostCommentIcon(lastPostID);
cy.postMessageReplyInRHS(MESSAGES.TINY);
});
// # Type a incorrect slash command and press enter in RHS
cy.uiGetReplyTextBox().type(`/${incorrectCommand1} {enter}`);
// # Move the text search for error inside the RHS container only, so we are certain it is rendered below RHS textbox
cy.get('#rhsContainer').within(() => {
// * Check that error message of incorrect command is displayed
verifyNonCommandErrorMessageIsDisplayed(incorrectCommand1);
});
// * Check that the focus is still the RHS textbox and not in the center textbox
cy.focused().
should('have.id', 'reply_textbox').
and('not.have.id', 'post_textbox');
// * Verify hitting backspace in the textbox removes the error message
cy.uiGetReplyTextBox().type('{backspace}');
cy.get('#rhsContainer').within(() => {
// * Verify error message is not displayed
verifyNonCommandErrorMessageIsNotDisplayed(incorrectCommand1);
});
// # Press enter once with incorrect to allow the error message to show
cy.uiGetReplyTextBox().clear().type(`/${incorrectCommand2} {enter}`);
// * Check that error message of incorrect command is displayed
cy.get('#rhsContainer').within(() => {
verifyNonCommandErrorMessageIsDisplayed(incorrectCommand2);
});
// # Lets press enter again to submit it as plain text after error message is shown
cy.uiGetReplyTextBox().type('{enter}');
// * Verify incorrect command got posted as plain text message via twice enter press
verifyLastPostedMessageContainsPlainTextOfCommand(incorrectCommand2);
// # Lets add another incorrect command and press enter
cy.uiGetReplyTextBox().clear().type(`/${incorrectCommand3} {enter}`);
// * Check that error message of incorrect command is displayed
cy.get('#rhsContainer').within(() => {
verifyNonCommandErrorMessageIsDisplayed(incorrectCommand3);
});
// # Click on the link to post incorrect command as plain text below textbox
cy.findByText('Click here to send as a message.').should('exist').click({force: true});
// * Verify incorrect command got posted as plain text message via clicking link
verifyLastPostedMessageContainsPlainTextOfCommand(incorrectCommand3);
// # Close RHS
cy.uiCloseRHS();
});
});
function verifyNonCommandErrorMessageIsDisplayed(nonCommand) {
cy.findByText(`Command with a trigger of '/${nonCommand}' not found.`);
cy.findByText('Click here to send as a message.');
}
function verifyNonCommandErrorMessageIsNotDisplayed(nonCommand) {
cy.findByText(`Command with a trigger of '/${nonCommand}' not found.`).should('not.exist');
cy.findByText('Click here to send as a message.').should('not.exist');
}
function verifyLastPostedMessageContainsPlainTextOfCommand(nonCommand) {
// # Get the last posted message
cy.getLastPost().within(() => {
// * Verify the incorrect command is posted as plain text
cy.findByText(`/${nonCommand}`);
});
}

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

@@ -0,0 +1,229 @@
// 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 @integrations
import * as TIMEOUTS from '../../../../fixtures/timeouts';
import {loginAndVisitChannel} from './helper';
describe('Integrations', () => {
let testUser;
let testTeam;
const userGroup = [];
let testChannel;
let testChannelUrl;
let offTopicUrl;
before(() => {
cy.apiInitSetup().then(({team, user, offTopicUrl: url}) => {
testUser = user;
testTeam = team;
offTopicUrl = url;
Cypress._.times(8, () => {
cy.apiCreateUser().then(({user: otherUser}) => {
cy.apiAddUserToTeam(team.id, otherUser.id);
userGroup.push(otherUser);
});
});
});
});
beforeEach(() => {
cy.apiAdminLogin();
cy.apiCreateChannel(testTeam.id, 'channel', 'channel').then(({channel}) => {
testChannel = channel;
testChannelUrl = `/${testTeam.name}/channels/${channel.name}`;
cy.apiAddUserToChannel(channel.id, testUser.id);
});
});
it('MM-T658 /invite - current channel', () => {
cy.apiCreateUser().then(({user}) => {
return cy.apiDeactivateUser(user.id).then(() => user);
}).then((deactivatedUser) => {
const userToInvite = userGroup[0];
loginAndVisitChannel(testUser, testChannelUrl);
// # Post `/invite @username` where username is a user who is not in the current channel
cy.postMessage(`/invite @${userToInvite.username} `);
// * User who added them sees system message "username added to the channel by you"
cy.uiWaitUntilMessagePostedIncludes(`@${userToInvite.username} added to the channel by you`);
// * Cannot invite deactivated users to a channel
cy.postMessage(`/invite @${deactivatedUser.username} `);
cy.uiWaitUntilMessagePostedIncludes(`We couldn't find the user ${deactivatedUser.username}. They may have been deactivated by the System Administrator.`);
cy.apiLogout();
loginAndVisitChannel(userToInvite, offTopicUrl);
// * Added user sees channel added to LHS, mention badge
cy.uiGetLhsSection('CHANNELS').
findByLabelText(`${testChannel.display_name.toLowerCase()} public channel 1 mention`).
should('be.visible').
click();
// * Added user sees system message "username added to the channel by username."
cy.uiWaitUntilMessagePostedIncludes(`You were added to the channel by @${testUser.username}`);
});
});
it('MM-T661 /invite extra white space before @ in DM or GM', () => {
const [member1, member2, userToInviteGM, userToInviteDM] = userGroup;
loginAndVisitChannel(testUser, testChannelUrl);
// # In a GM use the /invite command to invite a user to a channel you have permission to add them to but place extra white space before the username
cy.postMessage(`/groupmsg @${member1.username} @${member2.username} `);
cy.postMessage(`/invite @${userToInviteGM.username} ~${testChannel.name} `);
// * User added to channel as expected
cy.uiWaitUntilMessagePostedIncludes(`${userToInviteGM.username} added to ${testChannel.name} channel.`);
cy.uiAddDirectMessage().click();
cy.get('#selectItems input').typeWithForce(userToInviteDM.username).wait(TIMEOUTS.ONE_SEC);
cy.get('#multiSelectList').findByText(`@${userToInviteDM.username}`).click();
cy.findByText('Go').click();
cy.uiGetChannelHeaderButton().contains(userToInviteDM.username);
// # In a DM use the /invite command to invite a user to a channel you have permission to add them to but place extra white space before the username
cy.postMessage(`/invite @${userToInviteDM.username} ~${testChannel.name} `);
// * User added to channel as expected
cy.uiWaitUntilMessagePostedIncludes(`${userToInviteDM.username} added to ${testChannel.name} channel.`);
});
it('MM-T659 /invite - other channel', () => {
const userToInvite = userGroup[0];
loginAndVisitChannel(testUser, offTopicUrl);
// # Post `/invite @username ~channel` where channel name is a channel you have permission to add members to but not the current channel, and username is a user not in that other channel
cy.postMessage(`/invite @${userToInvite.username} ~${testChannel.name} `);
// * User who added them sees system message "username added to channel."
cy.uiWaitUntilMessagePostedIncludes(`${userToInvite.username} added to ${testChannel.name} channel.`);
cy.apiLogout();
loginAndVisitChannel(userToInvite, offTopicUrl);
// * Added user sees channel added to LHS, mention badge.
cy.uiGetLhsSection('CHANNELS').
findByLabelText(`${testChannel.display_name.toLowerCase()} public channel 1 mention`).
should('be.visible').
click();
// * Added user sees system message "username added to the channel by username."
cy.uiWaitUntilMessagePostedIncludes(`You were added to the channel by @${testUser.username}`);
});
it('MM-T660_1 /invite tests when used in DMs and GMs', () => {
const [member1, member2, userDM] = userGroup;
loginAndVisitChannel(testUser, testChannelUrl);
// # In a GM Use the /invite command to invite a channel to another channel (e.g., /invite @[channel name])
cy.postMessage(`/groupmsg @${member1.username} @${member2.username} `);
cy.postMessage(`/invite @${testChannel.name} `);
// * Error appears: "We couldn't find the user. They may have been deactivated by the System Administrator."
cy.uiWaitUntilMessagePostedIncludes(`We couldn't find the user ${testChannel.name}. They may have been deactivated by the System Administrator.`);
cy.uiAddDirectMessage().click();
cy.get('#selectItems input').typeWithForce(userDM.username).wait(TIMEOUTS.ONE_SEC);
cy.get('#multiSelectList').findByText(`@${userDM.username}`).click();
cy.findByText('Go').click();
cy.uiGetChannelHeaderButton().contains(userDM.username);
// # In a GM Use the /invite command to invite a channel to another channel (e.g., /invite @[channel name])
cy.postMessage(`/invite @${testChannel.name} `);
// * Error appears: "We couldn't find the user. They may have been deactivated by the System Administrator."
cy.uiWaitUntilMessagePostedIncludes(`We couldn't find the user ${testChannel.name}. They may have been deactivated by the System Administrator.`);
});
it('MM-T660_2 /invite tests when used in DMs and GMs', () => {
const [member1, member2, userDM, userToInvite] = userGroup;
cy.apiAddUserToChannel(testChannel.id, userToInvite.id);
loginAndVisitChannel(testUser, testChannelUrl);
// # In a GM use the /invite command to invite someone to a channel they're already a member of
cy.postMessage(`/groupmsg @${member1.username} @${member2.username} `);
cy.postMessage(`/invite @${userToInvite.username} ~${testChannel.name} `);
// * Error appears: "[username] is already in the channel"
cy.uiWaitUntilMessagePostedIncludes(`${userToInvite.username} is already in the channel.`);
cy.uiAddDirectMessage().click();
cy.get('#selectItems input').typeWithForce(userDM.username).wait(TIMEOUTS.ONE_SEC);
cy.get('#multiSelectList').findByText(`@${userDM.username}`).click();
cy.findByText('Go').click();
cy.uiGetChannelHeaderButton().contains(userDM.username);
// # In a DM use the /invite command to invite someone to a channel they're already a member of
cy.postMessage(`/invite @${userToInvite.username} ~${testChannel.name} `);
// * Error appears: "[username] is already in the channel"
cy.uiWaitUntilMessagePostedIncludes(`${userToInvite.username} is already in the channel.`);
});
it('MM-T660_3 /invite tests when used in DMs and GMs', () => {
const [userA, userB, userC, userDM, member1, member2] = userGroup;
// # As UserA create a new public channel
loginAndVisitChannel(testUser, offTopicUrl);
cy.uiCreateChannel({name: `${userA.username}-channel`});
cy.get('#postListContent').should('be.visible');
cy.apiLogout();
loginAndVisitChannel(userB, offTopicUrl);
cy.uiAddDirectMessage().click();
cy.get('#selectItems input').typeWithForce(userDM.username).wait(TIMEOUTS.ONE_SEC);
cy.get('#multiSelectList').findByText(`@${userDM.username}`).click();
cy.findByText('Go').click();
cy.uiGetChannelHeaderButton().contains(userDM.username);
// # As UserB use the /invite command in a DM to invite UserC to the public channel that UserB is not a member of
cy.postMessage(`/invite @${userC.username} ~${userA.username}-channel `);
// * Error appears: "You don't have enough permissions to add [username] in [public channel name]."
cy.uiWaitUntilMessagePostedIncludes(`You don't have enough permissions to add ${userC.username} in ${userA.username}-channel.`);
// # As UserB use the /invite command in a GM to invite UserC to the public channel that UserB is not a member of
cy.postMessage(`/groupmsg @${member1.username} @${member2.username} `);
cy.postMessage(`/invite @${userC.username} ~${userA.username}-channel `);
// * Error appears: "You don't have enough permissions to add [username] in [public channel name]."
cy.uiWaitUntilMessagePostedIncludes(`You don't have enough permissions to add ${userC.username} in ${userA.username}-channel.`);
});
it('MM-T660_4 /invite tests when used in DMs and GMs', () => {
const userToInvite = userGroup[0];
loginAndVisitChannel(testUser, offTopicUrl);
// # Use the /invite command to invite a user to a channel by typing the channel name out without the tilde (~).
cy.postMessage(`/invite @${userToInvite.username} ${testChannel.display_name} `);
// * Error appears: "Could not find the channel [channel name]. Please use the channel handle to identify channels."
cy.uiWaitUntilMessagePostedIncludes(`Could not find the channel ${testChannel.display_name.split(' ')[1]}. Please use the channel handle to identify channels.`);
// * "channel handle" is a live link to https://docs.mattermost.com/messaging/managing-channels.html#naming-a-channel
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).
contains('a', 'channel handle').should('have.attr', 'href', 'https://docs.mattermost.com/messaging/managing-channels.html#naming-a-channel');
});
});
});

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

@@ -0,0 +1,63 @@
// 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 @integrations
import {getJoinEmailTemplate, verifyEmailBody} from '../../../../utils';
import {loginAndVisitChannel} from './helper';
describe('Integrations', () => {
let testUser;
let testTeam;
const usersToInvite = [];
let siteName;
let testChannelUrl;
before(() => {
cy.apiGetConfig().then(({config}) => {
siteName = config.TeamSettings.SiteName;
});
cy.apiInitSetup().then(({team, user, channelUrl}) => {
testUser = user;
testTeam = team;
testChannelUrl = channelUrl;
Cypress._.times(2, () => {
cy.apiCreateUser().then(({user: otherUser}) => {
usersToInvite.push(otherUser);
});
});
});
});
it('MM-T575 /invite-people', () => {
loginAndVisitChannel(testUser, testChannelUrl);
// # Post `/invite email1 email2` where emails are of users not added to the team yet
cy.postMessage(`/invite_people ${usersToInvite.map((user) => user.email).join(' ')} `);
// * User who added them sees system message "Email invite(s) sent"
cy.uiWaitUntilMessagePostedIncludes('Email invite(s) sent');
usersToInvite.forEach((invitedUser) => {
cy.getRecentEmail({username: invitedUser.username, email: invitedUser.email}).then((data) => {
const {body: actualEmailBody, subject} = data;
// * Verify the subject
expect(subject).to.contain(`[${siteName}] ${testUser.username} invited you to join ${testTeam.display_name} Team`);
// * Verify email body
const expectedEmailBody = getJoinEmailTemplate(testUser.username, invitedUser.email, testTeam);
verifyEmailBody(expectedEmailBody, actualEmailBody);
});
});
});
});

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

@@ -0,0 +1,82 @@
// 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 @integrations
describe('Integrations', () => {
const testCases = [
{command: '/away', className: 'icon-clock', message: 'You are now away'},
{command: '/dnd', className: 'icon-minus-circle', message: 'Do Not Disturb is enabled. You will not receive desktop or mobile push notifications until Do Not Disturb is turned off.'},
{command: '/offline', className: 'icon-circle-outline', message: 'You are now offline'},
{command: '/online', className: 'icon-check-circle', message: 'You are now online'},
];
let offTopicUrl;
before(() => {
// # Login as test user
cy.apiInitSetup({loginAfter: true}).then(({offTopicUrl: url}) => {
offTopicUrl = url;
});
});
it('I18456 Built-in slash commands: change user status via post', () => {
cy.apiSaveMessageDisplayPreference('compact');
cy.visit(offTopicUrl);
testCases.forEach((testCase) => {
cy.postMessage(testCase.command + ' ');
verifyUserStatus(testCase, true);
});
});
it('I18456 Built-in slash commands: change user status via suggestion list', () => {
cy.apiSaveMessageDisplayPreference('clean');
cy.visit(offTopicUrl);
testCases.forEach((testCase) => {
// # Type "/" on textbox
cy.uiGetPostTextBox().clear().type('/');
// # Verify that the suggestion list is visible
cy.get('#suggestionList').should('be.visible').then((container) => {
// # Find command and click
cy.contains(new RegExp(testCase.command), {container}).click({force: true});
});
// # Hit enter and verify user status
cy.uiGetPostTextBox().type(' {enter}');
verifyUserStatus(testCase, false);
});
});
});
function verifyUserStatus(testCase, isCompactMode) {
// * Verify that the user status is as indicated
cy.uiGetProfileHeader().
find('i').
should('be.visible').
and('have.class', testCase.className);
cy.uiWaitUntilMessagePostedIncludes(testCase.message);
// * Verify that ephemeral message is posted as expected
cy.getLastPostId().then((postId) => {
cy.get(`#post_${postId}`).find('.user-popover').should('have.text', 'System');
if (isCompactMode) {
cy.get(`#postMessageText_${postId}`).should('have.text', testCase.message + ' (Only visible to you)');
} else {
cy.get(`#postMessageText_${postId}`).should('have.text', testCase.message);
cy.get('.post__visibility').last().should('be.visible').and('have.text', '(Only visible to you)');
}
});
}

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

@@ -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.
// ***************************************************************
// Stage: @prod
// Group: @channels @integrations
import * as TIMEOUTS from '../../../../fixtures/timeouts';
describe('Integrations', () => {
const away = {name: 'away', ariaLabel: 'Away Icon', message: 'You are now away', className: 'icon-clock'};
const offline = {name: 'offline', ariaLabel: 'Offline Icon', message: 'You are now offline', className: 'icon-circle-outline'};
const online = {name: 'online', ariaLabel: 'Online Icon', message: 'You are now online', className: 'icon-check', profileClassName: 'icon-check-circle'};
before(() => {
// # Login as test user and go to off-topic
cy.apiInitSetup({loginAfter: true}).then(({offTopicUrl}) => {
cy.visit(offTopicUrl);
});
});
it('MM-T670 /away', () => {
// # Set online status and verify it's changed as the initial status
setStatus(online.name, online.profileClassName);
verifyUserStatus(away);
});
it('MM-T672 /offline', () => {
// # Set online status and verify it's changed as the initial status
setStatus(online.name, online.profileClassName);
verifyUserStatus(offline);
// # Switch to off-topic channel
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
cy.findByLabelText('channel header region').findByText('Off-Topic').should('be.visible');
// # Then switch back to off-topic channel again
cy.uiGetLhsSection('CHANNELS').findByText('Off-Topic').click();
cy.findByLabelText('channel header region').findByText('Off-Topic').should('be.visible');
// * Should not appear "New Messages" line
cy.findByText('New Messages').should('not.exist');
// # Get the system message
cy.uiGetNthPost(-2).within(() => {
cy.findByText(offline.message);
// * Verify system message profile is visible and without status
cy.findByLabelText('Mattermost Logo').should('be.visible');
cy.get('.post__img').find('.status').should('not.exist');
});
});
it('MM-T674 /online', () => {
// # Set offline status and verify it's changed as the initial status
setStatus(offline.name, offline.className);
verifyUserStatus(online);
});
});
function setStatus(status, icon) {
cy.apiUpdateUserStatus(status);
cy.uiGetProfileHeader().
find('i').
and('have.class', icon);
}
function verifyUserStatus(testCase) {
// # Clear then type '/'
cy.uiGetPostTextBox().clear().type('/');
// * Verify that the suggestion list is visible
cy.get('#suggestionList').should('be.visible');
// # Post slash command to change user status
cy.uiGetPostTextBox().type(`${testCase.name}{enter}`).wait(TIMEOUTS.ONE_HUNDRED_MILLIS).type('{enter}');
// * Get last post and verify system message
cy.getLastPost().within(() => {
cy.findByText(testCase.message);
cy.findByText('(Only visible to you)');
});
// * Verify status shown at user profile in LHS
cy.uiGetProfileHeader().
find('i').
and('have.class', testCase.profileClassName || testCase.className);
// # Post a message
cy.postMessage(testCase.name);
// Verify that the profile in the posted message shows correct status
cy.get('.post__img').last().findByLabelText(testCase.ariaLabel);
}