Move /e2e -> /e2e-tests
Этот коммит содержится в:
@@ -0,0 +1,195 @@
|
||||
// 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 @bot_accounts @mfa
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
describe('Bot accounts ownership and API', () => {
|
||||
let newTeam;
|
||||
let newUser;
|
||||
let newChannel;
|
||||
let botId;
|
||||
let botName;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Set ServiceSettings to expected values
|
||||
const newSettings = {
|
||||
ServiceSettings: {
|
||||
EnforceMultifactorAuthentication: false,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
|
||||
cy.apiInitSetup().then(({team, user, channel, townSquareUrl}) => {
|
||||
newTeam = team;
|
||||
newUser = user;
|
||||
newChannel = channel;
|
||||
|
||||
cy.visit(townSquareUrl);
|
||||
cy.postMessage('hello');
|
||||
});
|
||||
|
||||
// # Create a test bot
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
({user_id: botId, display_name: botName} = bot);
|
||||
cy.apiPatchUserRoles(bot.user_id, ['system_admin', 'system_user']);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1862 Only system admin are able to create bots', () => {
|
||||
// # Open product switch menu and click "Integrations"
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
|
||||
// * Confirm integrations are visible
|
||||
cy.url().should('include', `/${newTeam.name}/integrations`);
|
||||
cy.get('.backstage-header').findByText('Integrations').should('be.visible');
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(newUser);
|
||||
|
||||
cy.visit(`/${newTeam.name}/channels/town-square`);
|
||||
|
||||
// # Click product switch button
|
||||
cy.uiOpenProductMenu();
|
||||
|
||||
// * Confirm "Integrations" is not visible
|
||||
cy.uiGetProductMenu().should('not.contain', 'Integrations');
|
||||
});
|
||||
|
||||
it('MM-T1863 Only System Admin are able to create bots (API)', () => {
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(newUser);
|
||||
|
||||
// # Try to create a new bot as a regular user
|
||||
const botName3 = 'stay-enabled-bot-' + Date.now();
|
||||
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/bots',
|
||||
method: 'POST',
|
||||
failOnStatusCode: false,
|
||||
body: {
|
||||
username: botName3,
|
||||
display_name: 'some text',
|
||||
description: 'some text',
|
||||
},
|
||||
}).then((response) => {
|
||||
// * Validate that request was denied
|
||||
expect(response.status).to.equal(403);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1864 Create bot (API)', () => {
|
||||
// * This call will fail if bot was not created
|
||||
cy.apiCreateBot();
|
||||
});
|
||||
|
||||
it('MM-T1865 Create post as bot', () => {
|
||||
// # Create token for the bot
|
||||
cy.apiCreateToken(botId).then(({token}) => {
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
cy.apiCreatePost(newChannel.id, msg1, '', {attachments: [{pretext: 'Look some text', text: 'This is text'}]}, token);
|
||||
|
||||
// # Re-login to validate post presence
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/${newTeam.name}/channels/` + newChannel.name);
|
||||
|
||||
// * Validate post was created
|
||||
cy.findByText(msg1).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1866 Create two posts in a row to the same channel', () => {
|
||||
// # Create token for the bot
|
||||
cy.apiCreateToken(botId).then(({token}) => {
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
const msg2 = 'this is a bot message2 ' + botName;
|
||||
cy.apiCreatePost(newChannel.id, msg1, '', {attachments: [{pretext: 'Look some text', text: 'This is text'}]}, token).then(({body: post1}) => {
|
||||
cy.apiCreatePost(newChannel.id, msg2, '', {attachments: [{pretext: 'Look some text', text: 'This is text'}]}, token).then(({body: post2}) => {
|
||||
// # Re-login to validate post presence
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/${newTeam.name}/channels/` + newChannel.name);
|
||||
|
||||
// * Validate posts were created
|
||||
cy.get(`#postMessageText_${post1.id}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg1);
|
||||
cy.get(`#postMessageText_${post2.id}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg2);
|
||||
|
||||
// * Validate first post has an image
|
||||
cy.get(`#post_${post1.id}`).find('.Avatar').should('be.visible');
|
||||
|
||||
// * Validate that the second one doesn't
|
||||
cy.get(`#post_${post2.id}`).should('have.class', 'same--user');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1867 Post as a bot and include an @ mention', () => {
|
||||
// # Create token for the bot
|
||||
cy.apiCreateToken(botId).then(({token}) => {
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
cy.apiCreatePost(newChannel.id, msg1 + ' to @sysadmin', '', {}, token);
|
||||
|
||||
// # Re-login to validate post presence
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/${newTeam.name}/channels/` + newChannel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg1);
|
||||
|
||||
// * Assert that the last message posted contains highlighted mention
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).find('.mention--highlight').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1868 BOT has a member role and is not in target channel and team', () => {
|
||||
// # Create a test bot (member)
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
// # Create token for the bot
|
||||
cy.apiCreateToken(bot.user_id).then(({token}) => {
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
|
||||
// # Try posting
|
||||
cy.apiCreatePost(newChannel.id, 'this is a bot message ' + bot.username, '', {}, token, false).then((response) => {
|
||||
// * Validate that posting was not allowed
|
||||
expect(response.status).to.equal(403);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1869 BOT has a system admin role and is not in target channel and team', () => {
|
||||
const botName3 = 'stay-enabled-bot-' + Date.now();
|
||||
|
||||
// # Create token for the bot
|
||||
cy.apiCreateToken(botId).then(({token}) => {
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
|
||||
// # Try posting
|
||||
cy.apiCreatePost(newChannel.id, 'this is a bot message ' + botName3, '', {}, token).then((response) => {
|
||||
// * Validate that posting was allowed
|
||||
expect(response.status).to.equal(201);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,310 @@
|
||||
// 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 @bot_accounts @mfa
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
describe('Bot accounts ownership and API', () => {
|
||||
let newTeam;
|
||||
let newUser;
|
||||
let newChannel;
|
||||
let botId;
|
||||
let botUsername;
|
||||
let botName;
|
||||
let adminUser;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin().then(({user}) => {
|
||||
adminUser = user;
|
||||
});
|
||||
|
||||
// # Set ServiceSettings to expected values
|
||||
const newSettings = {
|
||||
ServiceSettings: {
|
||||
EnforceMultifactorAuthentication: false,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
|
||||
cy.apiInitSetup().then(({team, user, channel, townSquareUrl}) => {
|
||||
newTeam = team;
|
||||
newUser = user;
|
||||
newChannel = channel;
|
||||
|
||||
cy.visit(townSquareUrl);
|
||||
cy.postMessage('hello');
|
||||
});
|
||||
|
||||
// # Create a test bot
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
({user_id: botId, username: botUsername, display_name: botName} = bot);
|
||||
cy.apiPatchUserRoles(bot.user_id, ['system_admin', 'system_user']);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1870 BOT has a system admin role and can also post to private channels they do not belong to', () => {
|
||||
const channelName = 'channel' + Date.now();
|
||||
|
||||
// # Create private channel that bot doesn't belong to
|
||||
cy.apiCreateChannel(newTeam.id, channelName, channelName, 'P').then(({channel}) => {
|
||||
// # Create token for the bot
|
||||
cy.apiCreateToken(botId).then(({token}) => {
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
|
||||
// # Create a post
|
||||
cy.apiCreatePost(channel.id, msg1 + ' to @sysadmin', '', {}, token);
|
||||
|
||||
// # Re-login to validate post presence
|
||||
cy.apiAdminLogin();
|
||||
cy.visit(`/${newTeam.name}/channels/` + channel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('MM-T1872 Bot can post to DM channel', () => {
|
||||
// # Create DM channel that bot doesn't belong to
|
||||
cy.apiCreateDirectChannel([newUser.id, adminUser.id]).then(({channel}) => {
|
||||
// # Create token for the bot
|
||||
cy.apiAccessToken(botId, 'some text').then(({token}) => {
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
|
||||
// # Post test message
|
||||
cy.postBotMessage({message: msg1, token, channelId: channel.id});
|
||||
|
||||
// # Validate post presence
|
||||
cy.visit(`/${newTeam.name}/channels/` + channel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1874 Bots can post when MFA is enforced', () => {
|
||||
// # Create token for the bot
|
||||
cy.apiAccessToken(botId, 'some text').then(({token}) => {
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
cy.postBotMessage({channelId: newChannel.id, message: msg1, props: {attachments: [{pretext: 'Look some text', text: 'This is text'}]}, token});
|
||||
|
||||
// # Visit test channel
|
||||
cy.visit(`/${newTeam.name}/channels/` + newChannel.name);
|
||||
|
||||
// * Validate post was created
|
||||
cy.findByText(msg1).should('be.visible');
|
||||
|
||||
const newSettings = {
|
||||
ServiceSettings: {
|
||||
EnforceMultifactorAuthentication: true,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
|
||||
const msg2 = 'this is a bot message2 ' + botName;
|
||||
cy.postBotMessage({channelId: newChannel.id, message: msg2, props: {attachments: [{pretext: 'Look some text', text: 'This is text'}]}, token});
|
||||
|
||||
cy.visit(`/${newTeam.name}/channels/` + newChannel.name);
|
||||
|
||||
// * Validate post was created
|
||||
cy.findByText(msg2).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1875 A bot cannot create another bot', () => {
|
||||
// # Create token for the bot
|
||||
cy.apiAccessToken(botId, 'some text').then(({token}) => {
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
|
||||
// # Try to create a new bot
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest', Authorization: `Bearer ${token}`},
|
||||
url: '/api/v4/bots',
|
||||
method: 'POST',
|
||||
failOnStatusCode: false,
|
||||
body: {
|
||||
username: botName + '333',
|
||||
display_name: 'some text',
|
||||
description: 'some text',
|
||||
},
|
||||
}).then((response) => {
|
||||
// * Validate that request was denied
|
||||
expect(response.status).to.equal(403);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1877 Reactivate a deactivated bot', () => {
|
||||
// # Create private channel that bot doesn't belong to
|
||||
cy.apiCreateDirectChannel([newUser.id, adminUser.id]).then(({channel}) => {
|
||||
// # Create token for the bot
|
||||
cy.apiAccessToken(botId, 'some text').then(({token}) => {
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
|
||||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg1, token});
|
||||
|
||||
cy.visit(`/${newTeam.name}/channels/` + channel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg1);
|
||||
});
|
||||
|
||||
// # Disable the bot
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
cy.findByText(`${botName} (@${botUsername})`).scrollIntoView().parent().findByText('Disable').click();
|
||||
|
||||
// # Try to post again
|
||||
const msg2 = 'this is a bot message2 ' + botName;
|
||||
|
||||
// # Logout to allow posting as bot
|
||||
cy.apiLogout();
|
||||
|
||||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token, failOnStatus: false}).then(({status}) => {
|
||||
// * Validate that posting failed
|
||||
expect(status, 403);
|
||||
});
|
||||
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Enable the bot again
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
cy.findByText(`${botName} (@${botUsername})`).scrollIntoView().parent().findByText('Enable').click();
|
||||
|
||||
// # Try to post again
|
||||
|
||||
// * Validate that posting works
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token});
|
||||
|
||||
// * Validate post presence
|
||||
cy.visit(`/${newTeam.name}/channels/` + channel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1878 Disable token can not be used to post', () => {
|
||||
// # Create DM channel that bot doesn't belong to
|
||||
cy.apiCreateDirectChannel([newUser.id, adminUser.id]).then(({channel}) => {
|
||||
// # Create token for the bot
|
||||
cy.apiAccessToken(botId, 'some text').then(({token, id}) => {
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
|
||||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg1, token});
|
||||
|
||||
// # Validate post presence
|
||||
cy.visit(`/${newTeam.name}/channels/` + channel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg1);
|
||||
});
|
||||
|
||||
// # Disable the bot token
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
cy.findByText(`${botName} (@${botUsername})`).then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
cy.get(`#${id}_deactivate`).click();
|
||||
});
|
||||
|
||||
// # Try to post again
|
||||
const msg2 = 'this is a bot message2 ' + botName;
|
||||
|
||||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token, failOnStatus: false}).then(({status}) => {
|
||||
// * Validate that posting failed
|
||||
expect(status, 403);
|
||||
});
|
||||
|
||||
// # Enable the bot token again
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
cy.findAllByText('Bot Accounts');
|
||||
|
||||
cy.findByText(`${botName} (@${botUsername})`).scrollIntoView().then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
cy.get(`#${id}_activate`).click().wait(TIMEOUTS.ONE_SEC);
|
||||
|
||||
// # Try to post again
|
||||
// * Validate that posting works
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token});
|
||||
|
||||
// # Validate post presence
|
||||
cy.visit(`/${newTeam.name}/channels/` + channel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1880 Deleted token can not be used to post', () => {
|
||||
// # Create private channel that bot doesn't belong to
|
||||
cy.apiCreateDirectChannel([newUser.id, adminUser.id]).then(({channel}) => {
|
||||
// # Create token for the bot
|
||||
cy.apiAccessToken(botId, 'some text').then(({token, id}) => {
|
||||
const msg1 = 'this is a bot message ' + botName;
|
||||
|
||||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg1, token});
|
||||
|
||||
// # Validate post presence
|
||||
cy.visit(`/${newTeam.name}/channels/` + channel.name);
|
||||
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// * Validate post was created
|
||||
cy.get(`#postMessageText_${postId}`, {timeout: TIMEOUTS.ONE_MIN}).should('contain', msg1);
|
||||
});
|
||||
|
||||
// # Disable the bot token
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
cy.findByText(`${botName} (@${botUsername})`).scrollIntoView().then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// # Delete token
|
||||
cy.get(`#${id}_delete`).click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
|
||||
// # Try to post again
|
||||
const msg2 = 'this is a bot message2 ' + botName;
|
||||
|
||||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token, failOnStatus: false}).then(({status}) => {
|
||||
// * Validate that posting failed
|
||||
expect(status, 403);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 @not_cloud @bot_accounts
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
describe('Bot accounts ownership and API', () => {
|
||||
let newTeam;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
cy.apiInitSetup({
|
||||
promoteNewUserAsAdmin: true,
|
||||
loginAfter: true,
|
||||
}).then(({team}) => {
|
||||
newTeam = team;
|
||||
});
|
||||
|
||||
// # Set ServiceSettings to expected values
|
||||
const newSettings = {
|
||||
ServiceSettings: {
|
||||
DisableBotsWhenOwnerIsDeactivated: true,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
});
|
||||
|
||||
it('MM-T1861 Bots do not re-enable if the owner is re-activated', () => {
|
||||
// # Create another admin account
|
||||
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
|
||||
// # Login as the new admin
|
||||
cy.apiLogin(sysadmin);
|
||||
|
||||
// # Create a new bot as the new admin
|
||||
cy.apiCreateBot({prefix: 'stay-enabled-bot'}).then(({bot}) => {
|
||||
// # Login again as main admin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Deactivate the newly created admin
|
||||
cy.apiDeactivateUser(sysadmin.id);
|
||||
|
||||
// # Get bot list
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// # Search for the other bot
|
||||
cy.get('#searchInput', {timeout: TIMEOUTS.ONE_MIN}).type(bot.username);
|
||||
|
||||
// * Validate that the plugin is disabled since its owner is deactivated
|
||||
cy.get('.bot-list__disabled').scrollIntoView().should('be.visible');
|
||||
|
||||
// # Re-activate the newly created admin
|
||||
cy.apiActivateUser(sysadmin.id);
|
||||
|
||||
// # Repeat the test to confirm it stays disabled
|
||||
|
||||
// # Get bot list
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// # Search for the other bot
|
||||
cy.get('#searchInput', {timeout: TIMEOUTS.ONE_MIN}).type(bot.username);
|
||||
|
||||
// * Validate that the plugin is disabled even though its owner is activated
|
||||
cy.get('.bot-list__disabled').scrollIntoView().should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 @bot_accounts
|
||||
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
|
||||
describe('Bot channel intro and avatar', () => {
|
||||
let team;
|
||||
let bot;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
team = out.team;
|
||||
});
|
||||
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Create bot
|
||||
bot = await client.createBot(createBotPatch());
|
||||
await client.addToTeam(team.id, bot.user_id);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1839 Bots have default profile image visible', () => {
|
||||
// # Open bot DM channel
|
||||
cy.visit(`/${team.name}/messages/@${bot.username}`);
|
||||
|
||||
// # Get channel intro and bot-post Avatars
|
||||
cy.get(`#channelIntro .profile-icon > img.Avatar, img.Avatar[alt="${bot.username} profile image"]`).
|
||||
should(($imgs) => {
|
||||
// * Verify imgs downloaded
|
||||
expect($imgs[0].naturalWidth).to.be.greaterThan(0);
|
||||
expect($imgs[1].naturalWidth).to.be.greaterThan(0);
|
||||
}).
|
||||
each(($img) => {
|
||||
// * Verify img visible and has src
|
||||
cy.wrap($img).
|
||||
should('be.visible').
|
||||
and('have.attr', 'src').
|
||||
then((url) => cy.request({url, encoding: 'binary'})).
|
||||
then(({body}) => {
|
||||
// * Verify matches expected default bot avatar
|
||||
cy.fixture('bot-default-avatar.png', 'binary').should('deep.equal', body);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Create bot', () => {
|
||||
it('MM-T1810 Create a Bot via the UI', () => {
|
||||
cy.apiUpdateConfig({
|
||||
ServiceSettings: {
|
||||
EnableUserAccessTokens: true,
|
||||
},
|
||||
});
|
||||
|
||||
createBot();
|
||||
});
|
||||
|
||||
it('MM-T1811 Create a Bot when personal access tokens are set to False', () => {
|
||||
cy.apiUpdateConfig({
|
||||
ServiceSettings: {
|
||||
EnableUserAccessTokens: false,
|
||||
},
|
||||
});
|
||||
|
||||
createBot();
|
||||
});
|
||||
});
|
||||
|
||||
function createBot() {
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
// # Go to town-square channel
|
||||
cy.visit(`/${team.name}/channels/town-square`);
|
||||
cy.postMessage('hello');
|
||||
|
||||
// # Go to bot integrations page
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('a.integration-option[href$="/bots"]').click();
|
||||
cy.get('#addBotAccount').click();
|
||||
|
||||
// # Fill and submit form
|
||||
cy.get('#username').type(`bot-${getRandomId()}`);
|
||||
cy.get('#displayName').type('Test Bot');
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
// * Verify confirmation page
|
||||
cy.url().
|
||||
should('include', `/${team.name}/integrations/confirm`).
|
||||
should('match', /token=[a-zA-Z0-9]{26}/);
|
||||
|
||||
// * Verify confirmation form/token
|
||||
cy.get('div.backstage-form').
|
||||
should('include.text', 'Setup Successful').
|
||||
should((confirmation) => {
|
||||
expect(confirmation.text()).to.match(/Token: [a-zA-Z0-9]{26}/);
|
||||
});
|
||||
cy.get('#doneButton').click();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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 @not_cloud @bot_accounts
|
||||
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
import {createBotInteractive} from './helpers';
|
||||
|
||||
describe('Bot accounts - CRUD Testing', () => {
|
||||
let newTeam;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.shouldHavePluginUploadEnabled();
|
||||
|
||||
// # Set ServiceSettings to expected values
|
||||
const newSettings = {
|
||||
EmailSettings: {
|
||||
SMTPServer: '',
|
||||
},
|
||||
PluginSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
|
||||
// # Create a test bot
|
||||
cy.apiCreateBot();
|
||||
|
||||
// # Create and visit new channel
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
newTeam = team;
|
||||
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1849 Create a Personal Access Token when email config is invalid', () => {
|
||||
// # Create a test bot and validate that token is created
|
||||
const botUsername = `bot-${getRandomId()}`;
|
||||
createBotInteractive(newTeam, botUsername);
|
||||
cy.get('#doneButton').click();
|
||||
|
||||
// # Add a new token to the bot
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(`Test Bot (@${botUsername})`).then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// # Click the 'Create token' button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Create New Token').should('be.visible').click();
|
||||
|
||||
// # Add description
|
||||
cy.wrap(el[0].parentElement.parentElement).find('input').click().type('description!');
|
||||
|
||||
// # Save
|
||||
cy.findByTestId('saveSetting').click();
|
||||
|
||||
// # Click Close button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Close').should('be.visible').click();
|
||||
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// * Check that token is visible
|
||||
cy.wrap(el[0].parentElement.parentElement).findAllByText(/Token ID:/).should('have.length', 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,198 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
import {createBotInteractive} from './helpers';
|
||||
|
||||
describe('Bot accounts - CRUD Testing', () => {
|
||||
let newTeam;
|
||||
let testBot;
|
||||
|
||||
before(() => {
|
||||
// # Create and visit new channel
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
newTeam = team;
|
||||
});
|
||||
cy.apiAdminLogin();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// # Create a test bot
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
testBot = bot;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1841 Long description text', () => {
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(testBot.fullDisplayName).then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// # Click the edit button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Edit').should('be.visible').click();
|
||||
|
||||
// * Validate redirect to edit screen
|
||||
cy.url().should('include', `/${newTeam.name}/integrations/bots/edit`);
|
||||
|
||||
// # type long string
|
||||
const longDescription = 'A'.repeat(1020); // 1024 is the limit
|
||||
cy.get('#description').clear().type(longDescription);
|
||||
|
||||
// * Validate that it's fully typed
|
||||
cy.get('#description').should('have.value', longDescription);
|
||||
|
||||
// # type some more characters
|
||||
cy.get('#description').type('{end}12345');
|
||||
|
||||
// * Validate that it's partially updated
|
||||
cy.get('#description').should('have.value', longDescription + '1234');
|
||||
|
||||
// # Update the bot
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
// * Validate that bot saved correctly
|
||||
cy.url().should('include', `/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Validate that the description exists
|
||||
cy.findAllByText(longDescription + '1234').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1842 Change BOT role', () => {
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(testBot.fullDisplayName).then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// # Click the edit button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Edit').should('be.visible').click();
|
||||
|
||||
// * Validate redirect to edit screen
|
||||
cy.url().should('include', `/${newTeam.name}/integrations/bots/edit`);
|
||||
|
||||
// # Select sysadmin
|
||||
cy.get('select').select('System Admin');
|
||||
|
||||
// * Validate that permissions are set and read only
|
||||
cy.get('#postChannels').should('be.checked').should('be.disabled');
|
||||
cy.get('#postAll').should('be.checked').should('be.disabled');
|
||||
|
||||
// # Update the bot
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
// * Validate that bot saved correctly
|
||||
cy.url().should('include', `/${newTeam.name}/integrations/bots`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1843 ID along with actual token is created', () => {
|
||||
// # Create the bot and validate token is visible
|
||||
createBotInteractive(newTeam);
|
||||
cy.get('#doneButton').click();
|
||||
});
|
||||
|
||||
it('MM-T1844 Token is hidden when you return to the page but ID is still visible', () => {
|
||||
// # Create the bot and validate token is visible
|
||||
|
||||
const botUsername = `bot-${getRandomId()}`;
|
||||
|
||||
createBotInteractive(newTeam, botUsername).then((text) => {
|
||||
// # Close the Add dialog
|
||||
cy.get('#doneButton').click();
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(`Test Bot (@${botUsername})`).then((el) => {
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// * Validate that token is NOT visible on the next page
|
||||
const token = text.substr(text.indexOf('Token: ') + 7, 26);
|
||||
cy.findByText(new RegExp(token)).should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1845 Create a new token via the UI', () => {
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(testBot.fullDisplayName).then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// # Click the 'Create token' button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Create New Token').should('be.visible').click();
|
||||
|
||||
// # Try saving without description
|
||||
cy.findByTestId('saveSetting').click();
|
||||
cy.wrap(el[0].parentElement.parentElement).find('input').scrollIntoView();
|
||||
|
||||
// * Check for error message
|
||||
cy.get('#clientError').should('be.visible');
|
||||
|
||||
// # Add description
|
||||
cy.wrap(el[0].parentElement.parentElement).find('input').click().type(testBot.username + 'description!');
|
||||
|
||||
// # Save and check that no error is visible
|
||||
cy.findByTestId('saveSetting').click();
|
||||
|
||||
cy.get('#clientError').should('not.exist');
|
||||
|
||||
cy.findAllByText(testBot.username + 'description!').should('exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1848 Delete Token', () => {
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(testBot.fullDisplayName).then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// # Click the 'Create token' button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Create New Token').should('be.visible').click();
|
||||
|
||||
// # Add description
|
||||
cy.wrap(el[0].parentElement.parentElement).find('input').click().type('description!');
|
||||
|
||||
// # Save
|
||||
cy.findByTestId('saveSetting').click();
|
||||
|
||||
// # Click Close button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Close').should('be.visible').click();
|
||||
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// * Check that token is visible
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText(/Token ID:/).should('be.visible');
|
||||
|
||||
// # Click Delete button
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText('Delete').should('be.visible').click();
|
||||
|
||||
// * Validate that confirmation dialog is visible and click the delete button
|
||||
cy.get('#confirmModalButton').should('be.visible').click();
|
||||
|
||||
// * Check that token is not visible
|
||||
cy.wrap(el[0].parentElement.parentElement).findByText(/Token ID:/).should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
describe('Bot display name', () => {
|
||||
let offTopicChannel;
|
||||
let otherSysadmin;
|
||||
|
||||
before(() => {
|
||||
cy.intercept('**/api/v4/**').as('resources');
|
||||
|
||||
// # Set ServiceSettings to expected values
|
||||
const newSettings = {
|
||||
ServiceSettings: {
|
||||
EnableUserAccessTokens: false,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
|
||||
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
|
||||
otherSysadmin = sysadmin;
|
||||
cy.apiLogin(otherSysadmin);
|
||||
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
cy.apiGetChannelByName(team.name, 'off-topic').then(({channel}) => {
|
||||
offTopicChannel = channel;
|
||||
});
|
||||
cy.visit(`/${team.name}/channels/off-topic`);
|
||||
cy.wait('@resources');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1813 Display name for bots stays current', () => {
|
||||
cy.makeClient({user: otherSysadmin}).then((client) => {
|
||||
// # Create a bot and get bot user id
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
const botUserId = bot.user_id;
|
||||
const firstMessage = 'This is the first message from a bot that will change its name';
|
||||
const secondMessage = 'This is the second message from a bot that has changed its name';
|
||||
|
||||
// # Get token from bot's id
|
||||
cy.apiAccessToken(botUserId, 'Create token').then(({token}) => {
|
||||
//# Add bot to team
|
||||
cy.apiAddUserToTeam(offTopicChannel.team_id, botUserId);
|
||||
|
||||
// # Post message as bot through api with auth token
|
||||
const props = {attachments: [{pretext: 'Some Pretext', text: 'Some Text'}]};
|
||||
cy.postBotMessage({token, message: firstMessage, props, channelId: offTopicChannel.id}).
|
||||
its('id').
|
||||
should('exist').
|
||||
as('botPost');
|
||||
cy.uiWaitUntilMessagePostedIncludes(firstMessage);
|
||||
|
||||
// # Go to the channel
|
||||
cy.get('#sidebarItem_off-topic').click({force: true});
|
||||
|
||||
// * Verify bot display name
|
||||
cy.get('@botPost').then((postIdA) => {
|
||||
cy.get(`#post_${postIdA} button.user-popover`).click();
|
||||
|
||||
cy.get('#user-profile-popover').
|
||||
should('be.visible');
|
||||
|
||||
cy.findByTestId(`popover-fullname-${bot.username}`).
|
||||
should('have.text', bot.display_name);
|
||||
}).then(() => {
|
||||
// # Change display name after prior verification
|
||||
cy.wrap(client.patchBot(bot.user_id, {display_name: `NEW ${bot.display_name}`})).then((newBot) => {
|
||||
cy.postBotMessage({token, message: secondMessage, props, channelId: offTopicChannel.id}).
|
||||
its('id').
|
||||
should('exist').
|
||||
as('newBotPost');
|
||||
cy.uiWaitUntilMessagePostedIncludes(secondMessage);
|
||||
|
||||
// * Verify changed display name
|
||||
cy.get('@newBotPost').then(() => {
|
||||
cy.get('#user-profile-popover').
|
||||
should('be.visible');
|
||||
|
||||
cy.findByTestId(`popover-fullname-${bot.username}`).
|
||||
should('have.text', newBot.display_name);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import * as MESSAGES from '../../../fixtures/messages';
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Edit bot', () => {
|
||||
let testTeam;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, townSquareUrl}) => {
|
||||
testTeam = team;
|
||||
|
||||
cy.visit(townSquareUrl);
|
||||
cy.postMessage('hello');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1840 Description allows for special character', () => {
|
||||
const userName = `bot-${getRandomId()}`;
|
||||
const description = MESSAGES.LARGE.concat('!@#$%&*');
|
||||
|
||||
// # Create bot
|
||||
createBot(userName, testTeam.name);
|
||||
|
||||
// * Set alias for bot entry in bot list, this also checks that the bot entry exists
|
||||
cy.get('.backstage-list__item').contains('.backstage-list__item', userName).as('botEntry');
|
||||
|
||||
cy.get('@botEntry').then((el) => {
|
||||
// # Find the edit link for the bot
|
||||
const editLink = el.find('.item-actions>a');
|
||||
|
||||
if (editLink.text() === 'Edit') {
|
||||
// # Click the edit link for the bot
|
||||
cy.wrap(editLink).click();
|
||||
|
||||
// * Check that user name is as expected
|
||||
cy.get('#username').should('have.value', userName);
|
||||
|
||||
// * Check that details are empty
|
||||
cy.get('#displayName').should('have.value', '');
|
||||
cy.get('#description').should('have.value', '');
|
||||
|
||||
// # Set long description
|
||||
cy.get('#description').clear().type(description);
|
||||
|
||||
// # Click update button
|
||||
cy.get('#saveBot').click();
|
||||
}
|
||||
});
|
||||
|
||||
// * Get bot entry in bot list by username
|
||||
cy.get('@botEntry').then((el) => {
|
||||
cy.wrap(el).scrollIntoView();
|
||||
|
||||
// * Confirm long description is as expected
|
||||
cy.wrap(el.find('.bot-details__description')).should('have.text', description);
|
||||
});
|
||||
});
|
||||
|
||||
function createBot(userName, teamName) {
|
||||
// # Go to bot integrations page
|
||||
cy.uiOpenProductMenu('Integrations');
|
||||
cy.get('a.integration-option[href$="/bots"]').click();
|
||||
cy.get('#addBotAccount').click();
|
||||
|
||||
// # Fill and submit form
|
||||
cy.get('#username').type(userName);
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
// * Verify confirmation page
|
||||
cy.url().
|
||||
should('include', `/${teamName}/integrations/confirm`).
|
||||
should('match', /token=[a-zA-Z0-9]{26}/);
|
||||
|
||||
// * Verify confirmation form/token
|
||||
cy.get('div.backstage-form').
|
||||
should('include.text', 'Setup Successful').
|
||||
should((confirmation) => {
|
||||
expect(confirmation.text()).to.match(/Token: [a-zA-Z0-9]{26}/);
|
||||
});
|
||||
cy.get('#doneButton').click();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,132 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Edit bot username', () => {
|
||||
let team;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
team = out.team;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2923 Edit bot username.', () => {
|
||||
// # Visit bot config
|
||||
cy.visit('/admin_console/integrations/bot_accounts');
|
||||
|
||||
// # Verify that the setting is enabled
|
||||
cy.findByTestId('ServiceSettings.EnableBotAccountCreationtrue', {timeout: TIMEOUTS.ONE_MIN}).should('be.checked');
|
||||
|
||||
// # Visit the integrations
|
||||
goToCreateBot();
|
||||
|
||||
const initialBotName = `bot-${getRandomId()}`;
|
||||
|
||||
// # Fill and submit form
|
||||
cy.get('#username').clear().type(initialBotName);
|
||||
cy.get('#displayName').clear().type('Test Bot');
|
||||
cy.get('#saveBot').click();
|
||||
cy.get('#doneButton').click();
|
||||
|
||||
// * Set alias for bot entry in bot list, this also checks that the bot entry exists
|
||||
cy.get('.backstage-list__item').contains('.backstage-list__item', initialBotName).as('botEntry');
|
||||
|
||||
cy.get('@botEntry').then((el) => {
|
||||
// # Find the edit link for the bot
|
||||
const editLink = el.find('.item-actions>a');
|
||||
|
||||
if (editLink.text() === 'Edit') {
|
||||
// # Click the edit link for the bot
|
||||
cy.wrap(editLink).click();
|
||||
|
||||
// * Check that user name is as expected
|
||||
cy.get('#username').should('have.value', initialBotName);
|
||||
|
||||
// * Check that the display name is correct
|
||||
cy.get('#displayName').should('have.value', 'Test Bot');
|
||||
|
||||
// * Check that description is empty
|
||||
cy.get('#description').should('have.value', '');
|
||||
|
||||
const newBotName = `bot-${getRandomId()}`;
|
||||
|
||||
// * Enter the new user name
|
||||
cy.get('#username').clear().type(newBotName);
|
||||
|
||||
// # Click update button
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
cy.wrap(newBotName);
|
||||
}
|
||||
}).then((newBotName) => {
|
||||
// * Set alias for bot entry in bot list, this also checks that the bot entry exists
|
||||
cy.get('.backstage-list__item').contains('.backstage-list__item', newBotName).as('newbotEntry');
|
||||
|
||||
// * Get bot entry in bot list by username
|
||||
cy.get('@newbotEntry').then((el) => {
|
||||
cy.wrap(el).scrollIntoView();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1838 Bot naming convention is enforced', () => {
|
||||
goToCreateBot();
|
||||
|
||||
// # Attempt invalid bot usernames
|
||||
tryUsername('be', NAMING_WARNING_STANDARD);
|
||||
tryUsername('@be', NAMING_WARNING_STANDARD);
|
||||
tryUsername('abe.', NAMING_WARNING_ENDING_PERIOD);
|
||||
|
||||
// # Attempt valid bot username
|
||||
const validBotName = `abe-the-bot-${getRandomId()}`;
|
||||
tryUsername(validBotName);
|
||||
});
|
||||
|
||||
const NAMING_WARNING_STANDARD = 'Usernames have to begin with a lowercase letter and be 3-22 characters long. You can use lowercase letters, numbers, periods, dashes, and underscores.';
|
||||
const NAMING_WARNING_ENDING_PERIOD = 'Bot usernames cannot have a period as the last character';
|
||||
|
||||
function tryUsername(name, warningMessage) {
|
||||
cy.get('#username').clear().type(name);
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
if (warningMessage) {
|
||||
// * Verify expected warning
|
||||
cy.get('.backstage-form__footer .has-error').should('have.text', warningMessage);
|
||||
} else {
|
||||
// * Verify confirmation page
|
||||
cy.url().
|
||||
should('include', `/${team.name}/integrations/confirm`).
|
||||
should('match', /token=[a-zA-Z0-9]{26}/);
|
||||
|
||||
// * Verify confirmation form/token
|
||||
cy.get('div.backstage-form').
|
||||
should('include.text', 'Setup Successful').
|
||||
and('include.text', name).
|
||||
and((confirmation) => {
|
||||
expect(confirmation.text()).to.match(/Token: [a-zA-Z0-9]{26}/);
|
||||
});
|
||||
|
||||
// # back to start
|
||||
goToCreateBot();
|
||||
}
|
||||
}
|
||||
|
||||
function goToCreateBot() {
|
||||
cy.visit(`/${team.name}/integrations/bots`);
|
||||
|
||||
// * Assert that adding bots possible
|
||||
cy.get('#addBotAccount', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').click();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getRandomId} from '../../../utils';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
export function createBotInteractive(team, username = `bot-${getRandomId()}`) {
|
||||
// # Visit the Integrations > Bot Accounts page
|
||||
cy.visit(`/${team.name}/integrations/bots`);
|
||||
|
||||
// # Click add bot
|
||||
cy.get('#addBotAccount').click();
|
||||
|
||||
// # Fill and submit form
|
||||
cy.get('#username').type(username);
|
||||
cy.get('#displayName').type('Test Bot');
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
// * Verify confirmation page
|
||||
cy.url({timeout: TIMEOUTS.ONE_MIN}).
|
||||
should('include', `/${team.name}/integrations/confirm`).
|
||||
should('match', /token=[a-zA-Z0-9]{26}/);
|
||||
|
||||
// * Verify confirmation form/token
|
||||
cy.get('div.backstage-form').
|
||||
should('include.text', 'Setup Successful').
|
||||
should((confirmation) => {
|
||||
expect(confirmation.text()).to.match(/Token: [a-zA-Z0-9]{26}/);
|
||||
});
|
||||
|
||||
return cy.get('div.backstage-form').invoke('text');
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import {generateRandomUser} from '../../../support/api/user';
|
||||
|
||||
describe('Bots in lists', () => {
|
||||
let team;
|
||||
let channel;
|
||||
let bots;
|
||||
let createdUsers;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
team = out.team;
|
||||
channel = out.channel;
|
||||
});
|
||||
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Create bots
|
||||
bots = await Promise.all([
|
||||
client.createBot(createBotPatch()),
|
||||
client.createBot(createBotPatch()),
|
||||
client.createBot(createBotPatch()),
|
||||
]);
|
||||
|
||||
// # Create users
|
||||
createdUsers = await Promise.all([
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser()),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
...bots,
|
||||
...createdUsers,
|
||||
].map(async (user) => {
|
||||
// * Verify username exists
|
||||
cy.wrap(user).its('username');
|
||||
|
||||
// # Add to team and channel
|
||||
await client.addToTeam(team.id, user.user_id ?? user.id);
|
||||
await client.addToChannel(user.user_id ?? user.id, channel.id);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1834 Bots are not listed on “Users” list in System Console > Users', () => {
|
||||
// # Go to system console > users
|
||||
cy.visit('/admin_console/user_management/users');
|
||||
|
||||
bots.forEach(({username}) => {
|
||||
// # Search for bot
|
||||
cy.get('#searchUsers').clear().type(`@${username}`);
|
||||
|
||||
// * Verify bot not in list
|
||||
cy.findByTestId('noUsersFound').should('have.text', 'No users found');
|
||||
|
||||
// * Verify pseudo checksum total of non bot users
|
||||
cy.get('#searchableUserListTotal').contains('0 users of').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import {generateRandomUser} from '../../../support/api/user';
|
||||
|
||||
describe('Bots in lists', () => {
|
||||
let team;
|
||||
let channel;
|
||||
let testUser;
|
||||
|
||||
const STATUS_PRIORITY = {
|
||||
online: 0,
|
||||
away: 1,
|
||||
dnd: 2,
|
||||
offline: 3,
|
||||
ooo: 3,
|
||||
};
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
team = out.team;
|
||||
channel = out.channel;
|
||||
testUser = out.user;
|
||||
});
|
||||
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Create bots
|
||||
const bots = await Promise.all([
|
||||
client.createBot(createBotPatch()),
|
||||
client.createBot(createBotPatch()),
|
||||
client.createBot(createBotPatch()),
|
||||
]);
|
||||
|
||||
// # Create users
|
||||
const createdUsers = await Promise.all([
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser()),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
...bots,
|
||||
...createdUsers,
|
||||
].map(async (user) => {
|
||||
// * Verify username exists
|
||||
cy.wrap(user).its('username');
|
||||
|
||||
// # Add to team and channel
|
||||
await client.addToTeam(team.id, user.user_id ?? user.id);
|
||||
await client.addToChannel(user.user_id ?? user.id, channel.id);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1835 Channel Members list for BOTs', () => {
|
||||
cy.makeClient({user: testUser}).then((client) => {
|
||||
// # Login as regular user and visit a channel
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel members
|
||||
cy.get('.channel-header__trigger').click();
|
||||
cy.findByText('Manage Members').click();
|
||||
|
||||
cy.get('.more-modal__row .more-modal__name').then(async ($query) => {
|
||||
// # Extract usernames from jQuery collection
|
||||
const usernames = $query.toArray().map(({innerText}) => innerText.split('\n')[0]);
|
||||
|
||||
// # Get users
|
||||
const profiles = await client.getProfilesByUsernames(usernames);
|
||||
const statuses = await client.getStatusesByIds(profiles.map((user) => user.id));
|
||||
const users = Cypress._.zip(profiles, statuses).map(([profile, status]) => ({...profile, ...status}));
|
||||
|
||||
// # Sort 'em
|
||||
const sortedUsers = Cypress._.sortBy(users, [
|
||||
({is_bot: isBot}) => (isBot ? 1 : 0), // users first
|
||||
({status}) => STATUS_PRIORITY[status],
|
||||
({username}) => username,
|
||||
]);
|
||||
|
||||
// * Verify order of member-dropdown users against API-sourced/data-sorted version
|
||||
cy.wrap(usernames).should('deep.equal', sortedUsers.map(({username}) => username));
|
||||
});
|
||||
|
||||
// * Verify no statuses on bots
|
||||
cy.get('.more-modal__row--bot .status-wrapper .status').should('not.exist');
|
||||
|
||||
// * Verify bot badges
|
||||
cy.get('.more-modal__row--bot .Tag').then(($tags) => {
|
||||
$tags.toArray().forEach((tagEl) => {
|
||||
cy.wrap(tagEl).then(() => tagEl.scrollIntoView());
|
||||
cy.wrap(tagEl).should('be.visible').and('have.text', 'BOT');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import {createChannelPatch} from '../../../support/api/channel';
|
||||
|
||||
describe('Managing bots in Teams and Channels', () => {
|
||||
let team;
|
||||
|
||||
before(() => {
|
||||
cy.apiUpdateConfig({
|
||||
TeamSettings: {
|
||||
RestrictCreationToDomains: 'sample.mattermost.com',
|
||||
},
|
||||
});
|
||||
cy.apiInitSetup({loginAfter: true}).then((out) => {
|
||||
team = out.team;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1815 Add a BOT to a team that has email restricted', () => {
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Go to channel
|
||||
const channel = await client.getChannelByName(team.id, 'town-square');
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Invite bot to team
|
||||
const bot = await client.createBot(createBotPatch());
|
||||
cy.uiInviteMemberToCurrentTeam(bot.username);
|
||||
|
||||
// * Verify system message in-channel
|
||||
cy.uiWaitUntilMessagePostedIncludes(`@${bot.username} added to the team by you.`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1816 Add a BOT to a channel', () => {
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Go to channel
|
||||
const channel = await client.createChannel(createChannelPatch(team.id, 'a-chan', 'A Channel'));
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Add bot to team
|
||||
const bot = await client.createBot(createBotPatch());
|
||||
await client.addToTeam(team.id, bot.user_id);
|
||||
|
||||
// # Add bot to channel in team
|
||||
cy.uiAddUsersToCurrentChannel([bot.username]);
|
||||
|
||||
// * Verify system message in-channel
|
||||
cy.uiWaitUntilMessagePostedIncludes(`@${bot.username} added to the channel by you.`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1817 Add a BOT to a channel that is not on the Team', () => {
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Go to channel
|
||||
const channel = await client.createChannel(createChannelPatch(team.id, 'a-chan', 'A Channel'));
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Invite bot to team
|
||||
const bot = await client.createBot(createBotPatch());
|
||||
cy.postMessage(`/invite @${bot.username} `);
|
||||
|
||||
// * Verify system message in-channel
|
||||
cy.uiWaitUntilMessagePostedIncludes(`@${bot.username} is not a member of the team.`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1818 No ephemeral post about Adding a bot to a channel When Bot is mentioned', () => {
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Go to channel
|
||||
const channel = await client.createChannel(createChannelPatch(team.id, 'a-chan', 'A Channel'));
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # And bot to team
|
||||
const bot = await client.createBot(createBotPatch());
|
||||
cy.apiAddUserToTeam(team.id, bot.user_id);
|
||||
|
||||
// # Mention bot
|
||||
const message = `hey @${bot.username}, tell me a rhyme..`;
|
||||
cy.postMessage(message);
|
||||
|
||||
// * Verify no ephemeral post is shown asking if you want to invite the bot to the server
|
||||
cy.uiGetNthPost(-1).should('contain.text', message);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,101 @@
|
||||
// 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 @bot_accounts @plugin @not_cloud
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
import {matterpollPlugin} from '../../../utils/plugins';
|
||||
|
||||
describe('Managing bot accounts', () => {
|
||||
let newTeam;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.shouldHavePluginUploadEnabled();
|
||||
|
||||
// # Create and visit new channel
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
newTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
});
|
||||
|
||||
it('MM-T1859 Bot is kept active when owner is disabled', () => {
|
||||
// # Visit bot config
|
||||
cy.visit('/admin_console/integrations/bot_accounts');
|
||||
|
||||
// # Click 'false' to disable
|
||||
cy.findByTestId('ServiceSettings.DisableBotsWhenOwnerIsDeactivatedfalse', {timeout: TIMEOUTS.ONE_MIN}).click();
|
||||
|
||||
// # Save
|
||||
cy.findByTestId('saveSetting').should('be.enabled').click();
|
||||
|
||||
// # Create another admin account
|
||||
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
|
||||
// # Login as the new admin
|
||||
cy.apiLogin(sysadmin);
|
||||
|
||||
// # Create a new bot as the new admin
|
||||
cy.apiCreateBot({prefix: 'stay-enabled-bot'}).then(({bot}) => {
|
||||
// # Login again as main admin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Deactivate the newly created admin
|
||||
cy.apiDeactivateUser(sysadmin.id);
|
||||
|
||||
// # Get bot list
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// # Search for the other bot
|
||||
cy.get('#searchInput', {timeout: TIMEOUTS.ONE_MIN}).type(bot.display_name);
|
||||
|
||||
// * Validate that the plugin is still active, even though its owner is disabled
|
||||
cy.get('.bot-list__disabled').should('not.exist');
|
||||
cy.findByText(bot.fullDisplayName).scrollIntoView().should('be.visible');
|
||||
|
||||
cy.visit(`/${newTeam.name}/messages/@sysadmin`);
|
||||
|
||||
// # Get last post message text
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).as('postMessageText');
|
||||
});
|
||||
|
||||
// * Verify entire message
|
||||
cy.get('@postMessageText').
|
||||
should('be.visible').
|
||||
and('contain.text', `${sysadmin.username} was deactivated. They managed the following bot accounts`).
|
||||
and('contain.text', bot.username);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1853 Bots managed plugins can be created when Enable Bot Account Creation is set to false', () => {
|
||||
// # Upload and enable "matterpoll" plugin
|
||||
cy.apiUploadAndEnablePlugin(matterpollPlugin);
|
||||
|
||||
// # Visit bot config
|
||||
cy.visit('/admin_console/integrations/bot_accounts');
|
||||
|
||||
// # Click 'false' to disable
|
||||
cy.findByTestId('ServiceSettings.EnableBotAccountCreationfalse', {timeout: TIMEOUTS.ONE_MIN}).click();
|
||||
|
||||
// # Save
|
||||
cy.findByTestId('saveSetting').should('be.enabled').click();
|
||||
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Validate that plugin installed ok
|
||||
cy.contains('Matterpoll (@matterpoll)', {timeout: TIMEOUTS.ONE_MIN});
|
||||
});
|
||||
});
|
||||
@@ -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 @bot_accounts
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Managing bot accounts', () => {
|
||||
let newTeam;
|
||||
|
||||
before(() => {
|
||||
// # Create and visit new channel
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
newTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
const newSettings = {
|
||||
ServiceSettings: {
|
||||
EnableBotAccountCreation: true,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
});
|
||||
|
||||
it('MM-T1851 No option to create BOT accounts when Enable Bot Account Creation is set to False.', () => {
|
||||
// # Visit bot config
|
||||
cy.visit('/admin_console/integrations/bot_accounts');
|
||||
|
||||
// # Click 'false' to disable
|
||||
cy.findByTestId('ServiceSettings.EnableBotAccountCreationfalse', {timeout: TIMEOUTS.ONE_MIN}).click();
|
||||
|
||||
// # Save
|
||||
cy.findByTestId('saveSetting').should('be.enabled').click();
|
||||
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Assert that adding bots is not possible
|
||||
cy.get('#addBotAccount', {timeout: TIMEOUTS.ONE_MIN}).should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T1852 Bot creation via API is not permitted when Enable Bot Account Creation is set to False', () => {
|
||||
// # Visit bot config
|
||||
cy.visit('/admin_console/integrations/bot_accounts');
|
||||
|
||||
// # Click 'false' to disable
|
||||
cy.findByTestId('ServiceSettings.EnableBotAccountCreationfalse', {timeout: TIMEOUTS.ONE_MIN}).click();
|
||||
|
||||
// # Save
|
||||
cy.findByTestId('saveSetting').should('be.enabled').click().wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// * Validate that creating bot fails
|
||||
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/bots',
|
||||
method: 'POST',
|
||||
failOnStatusCode: false,
|
||||
body: {
|
||||
username: `bot-${getRandomId()}`,
|
||||
display_name: 'test bot',
|
||||
description: 'test bot',
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(403);
|
||||
expect(response.body.message).to.equal('Bot creation has been disabled.');
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1854 Bots can be create when Enable Bot Account Creation is set to True.', () => {
|
||||
// # Visit bot config
|
||||
cy.visit('/admin_console/integrations/bot_accounts');
|
||||
|
||||
// * Check that creation is enabled
|
||||
cy.findByTestId('ServiceSettings.EnableBotAccountCreationtrue', {timeout: TIMEOUTS.ONE_MIN}).should('be.checked');
|
||||
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Assert that adding bots is possible
|
||||
cy.get('#addBotAccount', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T1856 Disable Bot', () => {
|
||||
cy.apiCreateBot({prefix: 'test-bot'}).then(({bot}) => {
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// # Filter bot
|
||||
cy.get('#searchInput', {timeout: TIMEOUTS.ONE_MIN}).type(bot.username);
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(bot.fullDisplayName, {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView().then((el) => {
|
||||
// # Click the disable button
|
||||
cy.wrap(el[0].parentElement.parentElement).find('button:nth-child(3)').should('be.visible').click();
|
||||
});
|
||||
|
||||
// * Check that the bot is in the 'disabled' section
|
||||
cy.get('.bot-list__disabled').scrollIntoView().findByText(bot.fullDisplayName).should('be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1857 Enable Bot', () => {
|
||||
cy.apiCreateBot({prefix: 'test-bot'}).then(({bot}) => {
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(bot.fullDisplayName, {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView().then((el) => {
|
||||
// # Click the disable button
|
||||
cy.wrap(el[0].parentElement.parentElement).find('button:nth-child(3)').should('be.visible').click();
|
||||
});
|
||||
|
||||
// # Filter bot
|
||||
cy.get('#searchInput', {timeout: TIMEOUTS.ONE_MIN}).type(bot.username);
|
||||
|
||||
// # Re-enable the bot
|
||||
cy.get('.bot-list__disabled').scrollIntoView().findByText(bot.fullDisplayName, {timeout: TIMEOUTS.ONE_MIN}).scrollIntoView().then((el) => {
|
||||
// # Click the enable button
|
||||
cy.wrap(el[0].parentElement.parentElement).find('button:nth-child(1)').should('be.visible').click();
|
||||
});
|
||||
|
||||
// * Check that the bot is in the 'enabled' section
|
||||
cy.findByText(bot.fullDisplayName).scrollIntoView().should('be.visible');
|
||||
cy.get('.bot-list__disabled').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1858 Search active and disabled Bot accounts', () => {
|
||||
cy.apiCreateBot({prefix: 'hello-bot'}).then(({bot}) => {
|
||||
// # Visit the integrations
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// * Check that the previously created bot is listed
|
||||
cy.findByText(bot.fullDisplayName, {timeout: TIMEOUTS.ONE_MIN}).then((el) => {
|
||||
// # Make sure it's on the screen
|
||||
cy.wrap(el[0].parentElement.parentElement).scrollIntoView();
|
||||
|
||||
// # Click the disable button
|
||||
cy.wrap(el[0].parentElement.parentElement).find('button:nth-child(3)').should('be.visible').click();
|
||||
});
|
||||
|
||||
// * Validate that disabled section appears
|
||||
cy.get('.bot-list__disabled').scrollIntoView().should('be.visible');
|
||||
|
||||
// # Search for the other bot
|
||||
cy.apiCreateBot({prefix: 'other-bot'}).then(({bot: otherBot}) => {
|
||||
cy.get('#searchInput').type(otherBot.username);
|
||||
|
||||
// * Validate that disabled section disappears
|
||||
cy.get('.bot-list__disabled').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1860 Bot is disabled when owner is deactivated', () => {
|
||||
// # Create another admin account
|
||||
cy.apiCreateCustomAdmin().then(({sysadmin}) => {
|
||||
// # Login as the new admin
|
||||
cy.apiLogin(sysadmin);
|
||||
|
||||
// # Create a new bot as the new admin
|
||||
cy.apiCreateBot({prefix: 'stay-enabled-bot'}).then(({bot}) => {
|
||||
// # Login again as main admin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Deactivate the newly created admin
|
||||
cy.apiDeactivateUser(sysadmin.id);
|
||||
|
||||
// # Get bot list
|
||||
cy.visit(`/${newTeam.name}/integrations/bots`);
|
||||
|
||||
// # Search for the other bot
|
||||
cy.get('#searchInput', {timeout: TIMEOUTS.ONE_MIN}).type(bot.display_name);
|
||||
|
||||
// * Validate that the plugin is disabled since it's owner is deactivate
|
||||
cy.get('.bot-list__disabled').scrollIntoView().findByText(bot.fullDisplayName).scrollIntoView().should('be.visible');
|
||||
|
||||
cy.visit(`/${newTeam.name}/messages/@sysadmin`);
|
||||
|
||||
// # Get last post message text
|
||||
cy.getLastPostId().then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).as('postMessageText');
|
||||
});
|
||||
|
||||
// * Verify entire message
|
||||
cy.get('@postMessageText').
|
||||
should('be.visible').
|
||||
and('contain.text', `${sysadmin.username} was deactivated. They managed the following bot accounts`).
|
||||
and('contain.text', bot.username);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
describe('Bot post message', () => {
|
||||
let offTopicChannel;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
cy.apiGetChannelByName(team.name, 'off-topic').then(({channel}) => {
|
||||
offTopicChannel = channel;
|
||||
});
|
||||
cy.visit(`/${team.name}/channels/off-topic`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1812 Post as a bot when personal access tokens are false', () => {
|
||||
// # Create a bot and get bot user id
|
||||
cy.apiCreateBot().then(({bot}) => {
|
||||
const botUserId = bot.user_id;
|
||||
const message = 'This is a message from a bot.';
|
||||
|
||||
// # Get token from bot's id
|
||||
cy.apiAccessToken(botUserId, 'Create token').then(({token}) => {
|
||||
//# Add bot to team
|
||||
cy.apiAddUserToTeam(offTopicChannel.team_id, botUserId);
|
||||
|
||||
// # Post message as bot through api with auth token
|
||||
const props = {attachments: [{pretext: 'Some Pretext', text: 'Some Text'}]};
|
||||
cy.postBotMessage({token, message, props, channelId: offTopicChannel.id}).
|
||||
its('id').
|
||||
should('exist').
|
||||
as('botPost');
|
||||
|
||||
// * Verify bot message
|
||||
cy.uiWaitUntilMessagePostedIncludes(message);
|
||||
cy.get('@botPost').then((postId) => {
|
||||
cy.get(`#postMessageText_${postId}`).
|
||||
should('be.visible').
|
||||
and('have.text', message);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
|
||||
describe('Managing bots in Teams and Channels', () => {
|
||||
let team;
|
||||
|
||||
before(() => {
|
||||
cy.apiUpdateConfig({
|
||||
TeamSettings: {
|
||||
RestrictCreationToDomains: 'sample.mattermost.com',
|
||||
},
|
||||
});
|
||||
cy.apiInitSetup({loginAfter: true}).then((out) => {
|
||||
team = out.team;
|
||||
});
|
||||
});
|
||||
it('MM-T1819 Promote a BOT to team admin', () => {
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Go to channel
|
||||
const channel = await client.getChannelByName(team.id, 'off-topic');
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Add bot to team
|
||||
const bot = await client.createBot(createBotPatch());
|
||||
await client.addToTeam(team.id, bot.user_id);
|
||||
|
||||
// # Open team menu and click 'Manage Members'
|
||||
cy.uiOpenTeamMenu('Manage Members');
|
||||
|
||||
// # Find bot
|
||||
cy.get('.more-modal__list').find('.more-modal__row').its('length').should('be.gt', 0);
|
||||
cy.get('#searchUsersInput').type(bot.username);
|
||||
|
||||
// # Wait for loading screen
|
||||
cy.get('#teamMembersModal .loading-screen').should('be.visible');
|
||||
|
||||
// # Find bot member dropdown
|
||||
cy.get(`#teamMembersDropdown_${bot.username}`).as('memberDropdown').should('contain.text', 'Member').click();
|
||||
|
||||
// # Promote bot to team admin
|
||||
cy.findByTestId('userListItemActions').find('button').contains('Make Team Admin').click();
|
||||
|
||||
// * Verify bot was promoted
|
||||
cy.get('@memberDropdown').should('contain.text', 'Team Admin');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
// 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 @bot_accounts @not_cloud
|
||||
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import {generateRandomUser} from '../../../support/api/user';
|
||||
|
||||
describe('Bot accounts', () => {
|
||||
let team;
|
||||
let channel;
|
||||
let testUser;
|
||||
let bots;
|
||||
let createdUsers;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
||||
cy.apiInitSetup().then((out) => {
|
||||
team = out.team;
|
||||
channel = out.channel;
|
||||
testUser = out.user;
|
||||
});
|
||||
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Create bots
|
||||
bots = await Promise.all([
|
||||
client.createBot(createBotPatch()),
|
||||
client.createBot(createBotPatch()),
|
||||
client.createBot(createBotPatch()),
|
||||
]);
|
||||
|
||||
// # Create users
|
||||
createdUsers = await Promise.all([
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser()),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
...bots,
|
||||
...createdUsers,
|
||||
].map(async (user) => {
|
||||
// * Verify username exists
|
||||
cy.wrap(user).its('username');
|
||||
|
||||
// # Add to team and channel
|
||||
await client.addToTeam(team.id, user.user_id ?? user.id);
|
||||
await client.addToChannel(user.user_id ?? user.id, channel.id);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
});
|
||||
|
||||
it('MM-T1836 Bot accounts display', () => {
|
||||
// # Login as regular user and visit a channel
|
||||
cy.apiLogin(testUser);
|
||||
cy.visit(`/${team.name}/messages/@${bots[0].username}`);
|
||||
|
||||
cy.get('.SidebarChannelGroup:contains(DIRECT MESSAGES) .SidebarChannel.active > .SidebarLink').then(($link) => {
|
||||
// * Verify DM label
|
||||
cy.wrap($link).find('.SidebarChannelLinkLabel').should('have.text', bots[0].username);
|
||||
|
||||
// * Verify bot icon exists
|
||||
cy.wrap($link).find('.Avatar').should('exist').
|
||||
and('have.attr', 'src').
|
||||
then((url) => cy.request({url, encoding: 'binary'})).
|
||||
then(({body}) => {
|
||||
// * Verify it matches default bot avatar
|
||||
cy.fixture('bot-default-avatar.png', 'binary').should('deep.equal', body);
|
||||
});
|
||||
});
|
||||
|
||||
cy.postMessage('Bump bot chat recency');
|
||||
|
||||
// # Open a new DM
|
||||
cy.visit(`/${team.name}/messages/@${createdUsers[0].username}`);
|
||||
cy.postMessage('Hello, regular user');
|
||||
|
||||
// * Verify Bots and Regular users as siblings in DMs
|
||||
cy.get('.SidebarChannelGroup:contains(DIRECT MESSAGES) .SidebarChannel.active').siblings('.SidebarChannel').then(($siblings) => {
|
||||
cy.wrap($siblings).contains('.SidebarChannelLinkLabel', bots[0].username);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
// 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 @bot_accounts
|
||||
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
|
||||
describe('Bot tags', () => {
|
||||
let me;
|
||||
let team;
|
||||
let channel;
|
||||
let postId;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
team = out.team;
|
||||
channel = out.channel;
|
||||
});
|
||||
|
||||
let meId;
|
||||
|
||||
cy.getCurrentUserId().then((id) => {
|
||||
meId = id;
|
||||
});
|
||||
|
||||
cy.makeClient().then(async (client) => {
|
||||
// # Setup state
|
||||
me = await client.getUser(meId);
|
||||
const bot = await client.createBot(createBotPatch());
|
||||
await client.addToTeam(team.id, bot.user_id);
|
||||
await client.addToChannel(bot.user_id, channel.id);
|
||||
|
||||
const {token} = await client.createUserAccessToken(bot.user_id, 'Create token');
|
||||
const message = `Message for @${me.username}. Signed, @${bot.username}.`;
|
||||
|
||||
// # Post message as bot through api with auth token
|
||||
const props = {attachments: [{pretext: 'Some Pretext', text: 'Some Text'}]};
|
||||
|
||||
cy.postBotMessage({token, message, props, channelId: channel.id}).then(async ({id}) => {
|
||||
postId = id;
|
||||
await client.pinPost(postId);
|
||||
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
cy.clickPostDotMenu(postId);
|
||||
cy.get(`#CENTER_flagIcon_${postId}`).click();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T1831 BOT tag is visible in search results', () => {
|
||||
// # Open search
|
||||
cy.uiSearchPosts(`Message for @${me.username}`);
|
||||
|
||||
// * Verify bot badge
|
||||
cy.get('.sidebar--right__title').should('contain.text', 'Search Results');
|
||||
rhsPostHasBotBadge(postId);
|
||||
});
|
||||
|
||||
it('MM-T1832 BOT tag is visible in Recent Mentions', () => {
|
||||
// # Open mentions
|
||||
cy.uiGetRecentMentionButton().click();
|
||||
|
||||
// * Verify bot badge
|
||||
cy.get('.sidebar--right__title').should('contain.text', 'Recent Mentions');
|
||||
rhsPostHasBotBadge(postId);
|
||||
});
|
||||
|
||||
it('MM-T1833 BOT tag is visible in Pinned Posts', () => {
|
||||
// # Open pinned posts
|
||||
cy.uiGetChannelPinButton().click();
|
||||
|
||||
// * Verify bot badge
|
||||
cy.get('.sidebar--right__title').should('contain.text', 'Pinned Posts');
|
||||
rhsPostHasBotBadge(postId);
|
||||
});
|
||||
|
||||
it('MM-T3659 BOT tag is visible in Saved Posts', () => {
|
||||
// # Open saved posts
|
||||
cy.uiGetSavedPostButton().click();
|
||||
|
||||
// * Verify bot badge
|
||||
cy.get('.sidebar--right__title').should('contain.text', 'Saved Posts');
|
||||
rhsPostHasBotBadge(postId);
|
||||
});
|
||||
});
|
||||
|
||||
function rhsPostHasBotBadge(postId) {
|
||||
cy.get(`.post#searchResult_${postId} .Tag`).should('be.visible').and('have.text', 'BOT');
|
||||
}
|
||||
Ссылка в новой задаче
Block a user