mirror of
https://github.com/mattermost/mattermost.git
synced 2026-04-22 22:57:17 -04:00
MM-47287 Refactor/migrate bot accounts to typescript (#28347)
* refactor: convert bot_api_1_spec.js to typescript - convert file bot_accounts/bot_api_1_spec.js to typescript - update related data types in order to fix argument issues * refactor: convert bot_api_not_cloud_spec.js to ts - convert file bot_accounts/bot_api_not_cloud_spec.js to typescript - update related data types in order to fix argument issues * refactor: convert bot_channel_intro_spec.js to ts - convert file bot_accounts/bot_channel_intro_spec.js to typescript - convert support/api/bots.js to typescript - remove data type bot.d.ts and include docs and definitions in support/api/bots.ts * refactor: convert bot_accounts files to ts - convert files from js to typescript - move declaration files to ts - update js docs - fix lint and type errors Related to #21303 * fix: replace params undefined on client.createUser - replace undefined params with empty strings as suggested in review * fix: add types to variables on spec tags_spec.ts - add types to variables * fix: update args for apiCreateBot on api/bots.ts - update args so that lint issue is fixed * Apply suggestions from code review update assertion to 401 --------- Co-authored-by: Saturnino Abril <5334504+saturninoabril@users.noreply.github.com>
This commit is contained in:
parent
f4c85a875d
commit
a358bef3cd
41 changed files with 2197 additions and 2110 deletions
|
|
@ -10,14 +10,17 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts @mfa
|
||||
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
describe('Bot accounts ownership and API', () => {
|
||||
let newTeam;
|
||||
let newUser;
|
||||
let newChannel;
|
||||
let botId;
|
||||
let botName;
|
||||
let newTeam: Team;
|
||||
let newUser: UserProfile;
|
||||
let newChannel: Channel;
|
||||
let botId: string;
|
||||
let botName: string;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin();
|
||||
|
|
@ -10,16 +10,19 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts @mfa
|
||||
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
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;
|
||||
let newTeam: Team;
|
||||
let newUser: UserProfile;
|
||||
let newChannel: Channel;
|
||||
let botId: string;
|
||||
let botUsername: string;
|
||||
let botName: string;
|
||||
let adminUser: UserProfile;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.apiAdminLogin().then(({user}) => {
|
||||
|
|
@ -180,7 +183,7 @@ describe('Bot accounts ownership and API', () => {
|
|||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token, failOnStatus: false}).then(({status}) => {
|
||||
// * Validate that posting failed
|
||||
expect(status, 403);
|
||||
expect(status).to.equal(401);
|
||||
});
|
||||
|
||||
cy.apiAdminLogin();
|
||||
|
|
@ -238,7 +241,7 @@ describe('Bot accounts ownership and API', () => {
|
|||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token, failOnStatus: false}).then(({status}) => {
|
||||
// * Validate that posting failed
|
||||
expect(status, 403);
|
||||
expect(status).to.equal(401);
|
||||
});
|
||||
|
||||
// # Enable the bot token again
|
||||
|
|
@ -301,7 +304,7 @@ describe('Bot accounts ownership and API', () => {
|
|||
// # Create a post
|
||||
cy.postBotMessage({channelId: channel.id, message: msg2, token, failOnStatus: false}).then(({status}) => {
|
||||
// * Validate that posting failed
|
||||
expect(status, 403);
|
||||
expect(status).to.equal(401);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -10,10 +10,11 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @not_cloud @bot_accounts
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
describe('Bot accounts ownership and API', () => {
|
||||
let newTeam;
|
||||
let newTeam: Team;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
|
@ -10,11 +10,13 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Bot} from '@mattermost/types/bots';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
|
||||
describe('Bot channel intro and avatar', () => {
|
||||
let team;
|
||||
let bot;
|
||||
let team: Team;
|
||||
let bot: Bot;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
|
|
@ -33,7 +35,7 @@ describe('Bot channel intro and avatar', () => {
|
|||
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"]`).
|
||||
cy.get<HTMLImageElement[]>(`#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);
|
||||
|
|
@ -44,7 +46,7 @@ describe('Bot channel intro and avatar', () => {
|
|||
cy.wrap($img).
|
||||
should('be.visible').
|
||||
and('have.attr', 'src').
|
||||
then((url) => cy.request({url, encoding: 'binary'})).
|
||||
then((url) => cy.request({url, encoding: 'binary'} as unknown as Partial<Cypress.RequestOptions>)).
|
||||
then(({body}) => {
|
||||
// * Verify matches expected default bot avatar
|
||||
cy.fixture('bot-default-avatar.png', 'binary').should('deep.equal', body);
|
||||
|
|
@ -10,12 +10,14 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @not_cloud @bot_accounts
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
import {createBotInteractive} from './helpers';
|
||||
|
||||
describe('Bot accounts - CRUD Testing', () => {
|
||||
let newTeam;
|
||||
let newTeam: Team;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
|
@ -10,13 +10,16 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Bot} from '@mattermost/types/bots';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
import {createBotInteractive} from './helpers';
|
||||
|
||||
describe('Bot accounts - CRUD Testing', () => {
|
||||
let newTeam;
|
||||
let testBot;
|
||||
let newTeam: Team;
|
||||
let testBot: Bot & {fullDisplayName: string};
|
||||
|
||||
before(() => {
|
||||
// # Create and visit new channel
|
||||
|
|
@ -10,9 +10,13 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Bot} from '@mattermost/types/bots';
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
describe('Bot display name', () => {
|
||||
let offTopicChannel;
|
||||
let otherSysadmin;
|
||||
let offTopicChannel: Channel;
|
||||
let otherSysadmin: UserProfile;
|
||||
|
||||
before(() => {
|
||||
cy.intercept('**/api/v4/**').as('resources');
|
||||
|
|
@ -77,7 +81,7 @@ describe('Bot display name', () => {
|
|||
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.wrap(client.patchBot(bot.user_id, {display_name: `NEW ${bot.display_name}`})).then((newBot: Bot) => {
|
||||
cy.postBotMessage({token, message: secondMessage, props, channelId: offTopicChannel.id}).
|
||||
its('id').
|
||||
should('exist').
|
||||
|
|
@ -10,11 +10,12 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import * as MESSAGES from '../../../fixtures/messages';
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Edit bot', () => {
|
||||
let testTeam;
|
||||
let testTeam: Team;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, townSquareUrl}) => {
|
||||
|
|
@ -10,11 +10,12 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Edit bot username', () => {
|
||||
let team;
|
||||
let team: Team;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
|
|
@ -68,8 +69,9 @@ describe('Edit bot username', () => {
|
|||
// # Click update button
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
cy.wrap(newBotName);
|
||||
return cy.wrap(newBotName);
|
||||
}
|
||||
return cy.wrap(null);
|
||||
}).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');
|
||||
|
|
@ -97,7 +99,7 @@ describe('Edit bot username', () => {
|
|||
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) {
|
||||
function tryUsername(name: string, warningMessage?: string) {
|
||||
cy.get('#username').clear().type(name);
|
||||
cy.get('#saveBot').click();
|
||||
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {getRandomId} from '../../../utils';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
export function createBotInteractive(team, username = `bot-${getRandomId()}`) {
|
||||
export function createBotInteractive(team: Team, username = `bot-${getRandomId()}`) {
|
||||
// # Visit the Integrations > Bot Accounts page
|
||||
cy.visit(`/${team.name}/integrations/bots`);
|
||||
|
||||
|
|
@ -10,15 +10,19 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Bot} from '@mattermost/types/bots';
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import {generateRandomUser} from '../../../support/api/user';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
describe('Bots in lists', () => {
|
||||
let team;
|
||||
let channel;
|
||||
let bots;
|
||||
let createdUsers;
|
||||
let team: Team;
|
||||
let channel: Channel;
|
||||
let bots: Bot[];
|
||||
let createdUsers: UserProfile[];
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
|
|
@ -36,8 +40,8 @@ describe('Bots in lists', () => {
|
|||
|
||||
// # Create users
|
||||
createdUsers = await Promise.all([
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser() as UserProfile, '', ''),
|
||||
client.createUser(generateRandomUser() as UserProfile, '', ''),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
|
|
@ -48,8 +52,8 @@ describe('Bots in lists', () => {
|
|||
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);
|
||||
await client.addToTeam(team.id, (user as Bot).user_id ?? (user as UserProfile).id);
|
||||
await client.addToChannel((user as Bot).user_id ?? (user as UserProfile).id, channel.id);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
@ -9,13 +9,17 @@
|
|||
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Bot} from '@mattermost/types/bots';
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import {generateRandomUser} from '../../../support/api/user';
|
||||
|
||||
describe('Bots in lists', () => {
|
||||
let team;
|
||||
let channel;
|
||||
let testUser;
|
||||
let team: Team;
|
||||
let channel: Channel;
|
||||
let testUser: UserProfile;
|
||||
|
||||
const STATUS_PRIORITY = {
|
||||
online: 0,
|
||||
|
|
@ -42,8 +46,8 @@ describe('Bots in lists', () => {
|
|||
|
||||
// # Create users
|
||||
const createdUsers = await Promise.all([
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser() as UserProfile, '', ''),
|
||||
client.createUser(generateRandomUser() as UserProfile, '', ''),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
|
|
@ -54,8 +58,8 @@ describe('Bots in lists', () => {
|
|||
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);
|
||||
await client.addToTeam(team.id, (user as Bot).user_id ?? (user as UserProfile).id);
|
||||
await client.addToChannel((user as Bot).user_id ?? (user as UserProfile).id, channel.id);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
@ -10,11 +10,13 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import {createChannelPatch} from '../../../support/api/channel';
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
|
||||
describe('Managing bots in Teams and Channels', () => {
|
||||
let team;
|
||||
let team: Team;
|
||||
|
||||
before(() => {
|
||||
cy.apiUpdateConfig({
|
||||
|
|
@ -45,7 +47,7 @@ describe('Managing bots in Teams and Channels', () => {
|
|||
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'));
|
||||
const channel = await client.createChannel(createChannelPatch(team.id, 'a-chan', 'A Channel') as Channel);
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Add bot to team
|
||||
|
|
@ -63,7 +65,7 @@ describe('Managing bots in Teams and Channels', () => {
|
|||
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'));
|
||||
const channel = await client.createChannel(createChannelPatch(team.id, 'a-chan', 'A Channel') as Channel);
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # Invite bot to team
|
||||
|
|
@ -78,7 +80,7 @@ describe('Managing bots in Teams and Channels', () => {
|
|||
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'));
|
||||
const channel = await client.createChannel(createChannelPatch(team.id, 'a-chan', 'A Channel') as Channel);
|
||||
cy.visit(`/${team.name}/channels/${channel.name}`);
|
||||
|
||||
// # And bot to team
|
||||
|
|
@ -10,11 +10,12 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts @plugin @not_cloud
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
import {matterpollPlugin} from '../../../utils/plugins';
|
||||
|
||||
describe('Managing bot accounts', () => {
|
||||
let newTeam;
|
||||
let newTeam: Team;
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
|
@ -10,11 +10,12 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Managing bot accounts', () => {
|
||||
let newTeam;
|
||||
let newTeam: Team;
|
||||
|
||||
before(() => {
|
||||
// # Create and visit new channel
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
|
|
@ -11,7 +13,7 @@
|
|||
// Group: @channels @bot_accounts
|
||||
|
||||
describe('Bot post message', () => {
|
||||
let offTopicChannel;
|
||||
let offTopicChannel: Channel;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team}) => {
|
||||
|
|
@ -10,10 +10,11 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
|
||||
describe('Managing bots in Teams and Channels', () => {
|
||||
let team;
|
||||
let team: Team;
|
||||
|
||||
before(() => {
|
||||
cy.apiUpdateConfig({
|
||||
|
|
@ -10,15 +10,19 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts @not_cloud
|
||||
|
||||
import {Bot} from '@mattermost/types/bots';
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
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;
|
||||
let team: Team;
|
||||
let channel: Channel;
|
||||
let testUser: UserProfile;
|
||||
let bots: Bot[];
|
||||
let createdUsers: UserProfile[];
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
|
|
@ -39,8 +43,8 @@ describe('Bot accounts', () => {
|
|||
|
||||
// # Create users
|
||||
createdUsers = await Promise.all([
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser()),
|
||||
client.createUser(generateRandomUser() as UserProfile, '', ''),
|
||||
client.createUser(generateRandomUser() as UserProfile, '', ''),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
|
|
@ -51,8 +55,8 @@ describe('Bot accounts', () => {
|
|||
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);
|
||||
await client.addToTeam(team.id, (user as Bot).user_id ?? (user as UserProfile).id);
|
||||
await client.addToChannel((user as Bot).user_id ?? (user as UserProfile).id, channel.id);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
@ -72,7 +76,7 @@ describe('Bot accounts', () => {
|
|||
|
||||
// * Verify bot icon exists
|
||||
cy.wrap($link).find('.Avatar').should('exist').
|
||||
and('have.attr', 'src').
|
||||
invoke('attr', 'src').
|
||||
then((url) => cy.request({url, encoding: 'binary'})).
|
||||
then(({body}) => {
|
||||
// * Verify it matches default bot avatar
|
||||
|
|
@ -10,14 +10,17 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @bot_accounts
|
||||
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import {createBotPatch} from '../../../support/api/bots';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
describe('Bot tags', () => {
|
||||
let me;
|
||||
let team;
|
||||
let channel;
|
||||
let postId;
|
||||
let me: UserProfile;
|
||||
let team: Team;
|
||||
let channel: Channel;
|
||||
let postId: string;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then((out) => {
|
||||
|
|
@ -92,6 +95,6 @@ describe('Bot tags', () => {
|
|||
});
|
||||
});
|
||||
|
||||
function rhsPostHasBotBadge(postId) {
|
||||
function rhsPostHasBotBadge(postId: string) {
|
||||
cy.get(`.post#searchResult_${postId} .Tag`).should('be.visible').and('have.text', 'BOT');
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
// Group: @channels @channel_settings
|
||||
// node run_tests.js --group='@channel_settings'
|
||||
|
||||
import {ChannelType} from '@mattermost/types/channels';
|
||||
import {getRandomId} from '../../../utils';
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ describe('Channel Settings', () => {
|
|||
it('MM-T1808 Hover effect exists to add a channel description / header (when not already present)', () => {
|
||||
// # Create a new public channel and then private channel
|
||||
['O', 'P'].forEach((channelType) => {
|
||||
cy.apiCreateChannel(testTeam.id, `chan${getRandomId()}`, 'chan', channelType).then(({channel}) => {
|
||||
cy.apiCreateChannel(testTeam.id, `chan${getRandomId()}`, 'chan', channelType as ChannelType).then(({channel}) => {
|
||||
// # Go to new channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
|
|
|
|||
|
|
@ -260,17 +260,17 @@ describe('Group Mentions', () => {
|
|||
// # Link the group and the channel.
|
||||
cy.apiLinkGroupChannel(groupID1, channel.id);
|
||||
|
||||
cy.apiLogin({username: 'board.one', password: 'Password1'} as any).then((boardOne) => {
|
||||
cy.apiAddUserToChannel(channel.id, boardOne.id);
|
||||
cy.apiLogin({username: 'board.one', password: 'Password1'} as any).then(({user}: {user: UserProfile}) => {
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
|
||||
// # Make the channel private and group-synced.
|
||||
cy.apiPatchChannel(channel.id, {group_constrained: true, type: 'P'});
|
||||
|
||||
// # Login to create the dev user
|
||||
cy.apiLogin({username: 'dev.one', password: 'Password1'} as any).then((devOne) => {
|
||||
cy.apiLogin({username: 'dev.one', password: 'Password1'} as any).then(({user}: {user: UserProfile}) => {
|
||||
cy.apiAdminLogin();
|
||||
|
||||
cy.apiAddUserToTeam(testTeam.id, devOne.id);
|
||||
cy.apiAddUserToTeam(testTeam.id, user.id);
|
||||
|
||||
cy.apiLogin({username: 'board.one', password: 'Password1'} as any);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
reUrl,
|
||||
verifyEmailBody,
|
||||
} from '../../../../utils';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
describe('Guest Accounts', () => {
|
||||
let sysadmin: Cypress.UserProfile;
|
||||
|
|
@ -40,7 +41,7 @@ describe('Guest Accounts', () => {
|
|||
});
|
||||
|
||||
// # Log in as a team admin.
|
||||
cy.apiAdminLogin().then((user) => {
|
||||
cy.apiAdminLogin().then(({user}: {user: UserProfile}) => {
|
||||
sysadmin = user;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
// Stage: @prod
|
||||
// Group: @channels @enterprise @ldap
|
||||
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import ldapUsers from '../../../../fixtures/ldap_users.json';
|
||||
import {getRandomId} from '../../../../utils';
|
||||
|
||||
|
|
@ -220,7 +221,7 @@ function setLDAPTestSettings(config) {
|
|||
}
|
||||
|
||||
function disableOnboardingTaskList(ldapLogin) {
|
||||
cy.apiLogin(ldapLogin).then((user) => {
|
||||
cy.apiLogin(ldapLogin).then(({user}: {user: UserProfile}) => {
|
||||
cy.apiSaveOnboardingTaskListPreference(user.id, 'onboarding_task_list_open', 'false');
|
||||
cy.apiSaveOnboardingTaskListPreference(user.id, 'onboarding_task_list_show', 'false');
|
||||
cy.apiSaveSkipStepsPreference(user.id, 'true');
|
||||
|
|
@ -228,7 +229,7 @@ function disableOnboardingTaskList(ldapLogin) {
|
|||
}
|
||||
|
||||
function removeUserFromAllTeams(testUser) {
|
||||
cy.apiGetUsersByUsernames([testUser.username]).then((users) => {
|
||||
cy.apiGetUsersByUsernames([testUser.username]).then(({users}) => {
|
||||
if (users.length > 0) {
|
||||
users.forEach((user) => {
|
||||
cy.apiGetTeamsForUser(user.id).then((teams) => {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
// * Change mattermost-server utils/license.go to test public key
|
||||
// * e.g. see (https://github.com/mattermost/mattermost-server/pull/16778/files)
|
||||
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||
|
||||
function verifyPurchaseModal() {
|
||||
|
|
@ -136,7 +137,7 @@ function getCurrentUsers(): Cypress.Chainable<number> {
|
|||
}
|
||||
|
||||
describe('Self hosted Purchase', () => {
|
||||
let adminUser: Cypress.UserProfile | undefined;
|
||||
let adminUser: UserProfile;
|
||||
|
||||
beforeEach(() => {
|
||||
// prevent failed tests from bleeding over
|
||||
|
|
@ -145,9 +146,9 @@ describe('Self hosted Purchase', () => {
|
|||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(() => {
|
||||
cy.apiAdminLogin().then((result) => {
|
||||
cy.apiAdminLogin().then(({user}) => {
|
||||
// assertion because current typings are wrong.
|
||||
adminUser = (result as unknown as {user: Cypress.UserProfile}).user;
|
||||
adminUser = user;
|
||||
cy.apiDeleteLicense();
|
||||
cy.visit('/');
|
||||
|
||||
|
|
|
|||
67
e2e-tests/cypress/tests/support/api/bots.d.ts
vendored
67
e2e-tests/cypress/tests/support/api/bots.d.ts
vendored
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Specific link to https://api.mattermost.com
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `api` prefix, e.g. `apiLogin`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Create a bot.
|
||||
* See https://api.mattermost.com/#tag/bots/paths/~1bots/post
|
||||
* @param {string} options.bot - predefined `bot` object instead of random bot
|
||||
* @param {string} options.prefix - 'bot' (default) or any prefix to easily identify a bot
|
||||
* @returns {Bot} out.bot: `Bot` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateBot().then(({bot}) => {
|
||||
* // do something with bot
|
||||
* });
|
||||
*/
|
||||
apiCreateBot({bot: BotPatch, prefix: string}?): Chainable<{bot: Bot & {fullDisplayName: string}}>;
|
||||
|
||||
/**
|
||||
* Get bots.
|
||||
* See https://api.mattermost.com/#tag/bots/paths/~1bots/get
|
||||
* @param {number} options.page - The page to select
|
||||
* @param {number} options.perPage - The number of users per page. There is a maximum limit of 200 users per page
|
||||
* @param {boolean} options.includeDeleted - If deleted bots should be returned
|
||||
* @returns {Bot[]} out.bots: `Bot[]` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetBots();
|
||||
*/
|
||||
apiGetBots(page?: number, perPage?: number, includeDeleted?: boolean): Chainable<{bots: Bot[]}>;
|
||||
|
||||
/**
|
||||
* Disable bot.
|
||||
* See https://api.mattermost.com/#tag/bots/operation/DisableBot
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDisableBot('user-id);
|
||||
*/
|
||||
apiDisableBot(userId: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Deactivate test bots.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDeactivateTestBots();
|
||||
*/
|
||||
apiDeactivateTestBots(): Chainable<>;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getRandomId} from '../../utils';
|
||||
|
||||
// *****************************************************************************
|
||||
// Bots
|
||||
// https://api.mattermost.com/#tag/bots
|
||||
// *****************************************************************************
|
||||
|
||||
Cypress.Commands.add('apiCreateBot', ({prefix, bot = createBotPatch(prefix)} = {}) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/bots',
|
||||
method: 'POST',
|
||||
body: bot,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
const {body} = response;
|
||||
return cy.wrap({
|
||||
bot: {
|
||||
...body,
|
||||
fullDisplayName: `${body.display_name} (@${body.username})`,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetBots', (page = 0, perPage = 200, includeDeleted = false) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/bots?page=${page}&per_page=${perPage}&include_deleted=${includeDeleted}`,
|
||||
method: 'GET',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({bots: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiDisableBot', (userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/bots/${userId}/disable`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
export function createBotPatch(prefix = 'bot') {
|
||||
const randomId = getRandomId();
|
||||
|
||||
return {
|
||||
username: `${prefix}-${randomId}`,
|
||||
display_name: `Test Bot ${randomId}`,
|
||||
description: `Test bot description ${randomId}`,
|
||||
};
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiDeactivateTestBots', () => {
|
||||
return cy.apiGetBots().then(({bots}) => {
|
||||
bots.forEach((bot) => {
|
||||
if (bot?.display_name?.includes('Test Bot') || bot?.username.startsWith('bot-')) {
|
||||
cy.apiDisableBot(bot.user_id);
|
||||
cy.apiDeactivateUser(bot.user_id);
|
||||
|
||||
// Log for debugging
|
||||
cy.log(`Deactivated Bot: "${bot.username}"`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
137
e2e-tests/cypress/tests/support/api/bots.ts
Normal file
137
e2e-tests/cypress/tests/support/api/bots.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Bot, BotPatch} from '@mattermost/types/bots';
|
||||
import {getRandomId} from '../../utils';
|
||||
import {ChainableT} from 'tests/types';
|
||||
|
||||
// *****************************************************************************
|
||||
// Bots
|
||||
// https://api.mattermost.com/#tag/bots
|
||||
// *****************************************************************************
|
||||
|
||||
/**
|
||||
* Create a bot.
|
||||
* See https://api.mattermost.com/#tag/bots/paths/~1bots/post
|
||||
* @param {string} options.bot - predefined `bot` object instead of random bot
|
||||
* @param {string} options.prefix - 'bot' (default) or any prefix to easily identify a bot
|
||||
* @returns {Bot} out.bot: `Bot` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateBot().then(({bot}) => {
|
||||
* // do something with bot
|
||||
* });
|
||||
*/
|
||||
function apiCreateBot({prefix, bot}: Partial<{prefix: string; bot: BotPatch}> = {}): ChainableT<{bot: Bot & {fullDisplayName: string}}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/bots',
|
||||
method: 'POST',
|
||||
body: bot || createBotPatch(prefix),
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
const {body} = response;
|
||||
return cy.wrap({
|
||||
bot: {
|
||||
...body,
|
||||
fullDisplayName: `${body.display_name} (@${body.username})`,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateBot', apiCreateBot);
|
||||
|
||||
/**
|
||||
* Get bots.
|
||||
* See https://api.mattermost.com/#tag/bots/paths/~1bots/get
|
||||
* @param {number} options.page - The page to select
|
||||
* @param {number} options.perPage - The number of users per page. There is a maximum limit of 200 users per page
|
||||
* @param {boolean} options.includeDeleted - If deleted bots should be returned
|
||||
* @returns {Bot[]} out.bots: `Bot[]` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetBots();
|
||||
*/
|
||||
function apiGetBots(page = 0, perPage = 200, includeDeleted = false): ChainableT<{bots: Bot[]}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/bots?page=${page}&per_page=${perPage}&include_deleted=${includeDeleted}`,
|
||||
method: 'GET',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({bots: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetBots', apiGetBots);
|
||||
|
||||
/**
|
||||
* Disable bot.
|
||||
* See https://api.mattermost.com/#tag/bots/operation/DisableBot
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDisableBot('user-id);
|
||||
*/
|
||||
function apiDisableBot(userId) {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/bots/${userId}/disable`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
Cypress.Commands.add('apiDisableBot', apiDisableBot);
|
||||
|
||||
/**
|
||||
* Patches bot
|
||||
* @param {string} prefix - bot prefix
|
||||
* @returns {BotPatch} botPatch: Cypress-chainable bot
|
||||
*/
|
||||
export function createBotPatch(prefix = 'bot'): BotPatch {
|
||||
const randomId = getRandomId();
|
||||
|
||||
return {
|
||||
username: `${prefix}-${randomId}`,
|
||||
display_name: `Test Bot ${randomId}`,
|
||||
description: `Test bot description ${randomId}`,
|
||||
} as BotPatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate test bots.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDeactivateTestBots();
|
||||
*/
|
||||
function apiDeactivateTestBots() {
|
||||
return cy.apiGetBots().then(({bots}) => {
|
||||
bots.forEach((bot) => {
|
||||
if (bot?.display_name?.includes('Test Bot') || bot?.username.startsWith('bot-')) {
|
||||
cy.apiDisableBot(bot.user_id);
|
||||
cy.apiDeactivateUser(bot.user_id);
|
||||
|
||||
// Log for debugging
|
||||
cy.log(`Deactivated Bot: "${bot.username}"`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiDeactivateTestBots', apiDeactivateTestBots);
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
apiCreateBot: typeof apiCreateBot;
|
||||
apiDeactivateTestBots: typeof apiDeactivateTestBots;
|
||||
apiGetBots: typeof apiGetBots;
|
||||
apiDisableBot: typeof apiDisableBot;
|
||||
}
|
||||
}
|
||||
}
|
||||
225
e2e-tests/cypress/tests/support/api/channel.d.ts
vendored
225
e2e-tests/cypress/tests/support/api/channel.d.ts
vendored
|
|
@ -1,225 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Specific link to https://api.mattermost.com
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `api` prefix, e.g. `apiLogin`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Create a new channel.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels/post
|
||||
* @param {String} teamId - Unique handler for a team, will be present in the team URL
|
||||
* @param {String} name - Unique handler for a channel, will be present in the team URL
|
||||
* @param {String} displayName - Non-unique UI name for the channel
|
||||
* @param {String} type - 'O' for a public channel (default), 'P' for a private channel
|
||||
* @param {String} purpose - A short description of the purpose of the channel
|
||||
* @param {String} header - Markdown-formatted text to display in the header of the channel
|
||||
* @param {Boolean} [unique=true] - if true (default), it will create with unique/random channel name.
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateChannel('team-id', 'test-channel', 'Test Channel').then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
apiCreateChannel(
|
||||
teamId: string,
|
||||
name: string,
|
||||
displayName: string,
|
||||
type?: string,
|
||||
purpose?: string,
|
||||
header?: string,
|
||||
unique: boolean = true
|
||||
): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Create a new direct message channel between two users.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1direct/post
|
||||
* @param {string[]} userIds - The two user ids to be in the direct message
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateDirectChannel(['user-1-id', 'user-2-id']).then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
apiCreateDirectChannel(userIds: string[]): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Create a new group message channel to group of users via API. If the logged in user's id is not included in the list, it will be appended to the end.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1group/post
|
||||
* @param {string[]} userIds - User ids to be in the group message channel
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateGroupChannel(['user-1-id', 'user-2-id', 'current-user-id']).then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
apiCreateGroupChannel(userIds: string[]): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Update a channel.
|
||||
* The fields that can be updated are listed as parameters. Omitted fields will be treated as blanks.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}/put
|
||||
* @param {string} channelId - The channel ID to be updated
|
||||
* @param {Channel} channel - Channel object to be updated
|
||||
* @param {string} channel.name - The unique handle for the channel, will be present in the channel URL
|
||||
* @param {string} channel.display_name - The non-unique UI name for the channel
|
||||
* @param {string} channel.purpose - A short description of the purpose of the channel
|
||||
* @param {string} channel.header - Markdown-formatted text to display in the header of the channel
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiUpdateChannel('channel-id', {name: 'new-name', display_name: 'New Display Name'. 'purpose': 'Updated purpose', 'header': 'Updated header'});
|
||||
*/
|
||||
apiUpdateChannel(channelId: string, channel: Channel): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Partially update a channel by providing only the fields you want to update.
|
||||
* Omitted fields will not be updated.
|
||||
* The fields that can be updated are defined in the request body, all other provided fields will be ignored.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}~1patch/put
|
||||
* @param {string} channelId - The channel ID to be patched
|
||||
* @param {Channel} channel - Channel object to be patched
|
||||
* @param {string} channel.name - The unique handle for the channel, will be present in the channel URL
|
||||
* @param {string} channel.display_name - The non-unique UI name for the channel
|
||||
* @param {string} channel.purpose - A short description of the purpose of the channel
|
||||
* @param {string} channel.header - Markdown-formatted text to display in the header of the channel
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchChannel('channel-id', {name: 'new-name', display_name: 'New Display Name'});
|
||||
*/
|
||||
apiPatchChannel(channelId: string, channel: Partial<Channel>): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Updates channel's privacy allowing changing a channel from Public to Private and back.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}~1privacy/put
|
||||
* @param {string} channelId - The channel ID to be patched
|
||||
* @param {string} privacy - The privacy the channel should be set too. P = Private, O = Open
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchChannelPrivacy('channel-id', 'P');
|
||||
*/
|
||||
apiPatchChannelPrivacy(channelId: string, privacy: string): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Get channel from the provided channel id string.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}/get
|
||||
* @param {string} channelId - Channel ID
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetChannel('channel-id').then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
apiGetChannel(channelId: string): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Gets a channel from the provided team name and channel name strings.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1teams~1name~1{team_name}~1channels~1name~1{channel_name}/get
|
||||
* @param {string} teamName - Team name
|
||||
* @param {string} channelName - Channel name
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetChannelByName('team-name', 'channel-name').then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
apiGetChannelByName(teamName: string, channelName: string): Chainable<{channel: Channel}>;
|
||||
|
||||
/**
|
||||
* Get a list of all channels.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels/get
|
||||
* @returns {Channel[]} `out.channels` as `Channel[]`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetAllChannels().then(({channels}) => {
|
||||
* // do something with channels
|
||||
* });
|
||||
*/
|
||||
apiGetAllChannels(): Chainable<{channels: Channel[]}>;
|
||||
|
||||
/**
|
||||
* Get channels for user.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1users~1{user_id}~1teams~1{team_id}~1channels/get
|
||||
* @returns {Channel[]} `out.channels` as `Channel[]`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetChannelsForUser().then(({channels}) => {
|
||||
* // do something with channels
|
||||
* });
|
||||
*/
|
||||
apiGetChannelsForUser(): Chainable<{channels: Channel[]}>;
|
||||
|
||||
/**
|
||||
* Soft deletes a channel, by marking the channel as deleted in the database.
|
||||
* Soft deleted channels will not be accessible in the user interface.
|
||||
* Direct and group message channels cannot be deleted.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}/delete
|
||||
* @param {string} channelId - The channel ID to be deleted
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDeleteChannel('channel-id');
|
||||
*/
|
||||
apiDeleteChannel(channelId: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Add a user to a channel by creating a channel member object.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}~1members/post
|
||||
* @param {string} channelId - Channel ID
|
||||
* @param {string} userId - User ID to add to the channel
|
||||
* @returns {ChannelMembership} `out.member` as `ChannelMembership`
|
||||
*
|
||||
* @example
|
||||
* cy.apiAddUserToChannel('channel-id', 'user-id').then(({member}) => {
|
||||
* // do something with member
|
||||
* });
|
||||
*/
|
||||
apiAddUserToChannel(channelId: string, userId: string): Chainable<ChannelMembership>;
|
||||
|
||||
/**
|
||||
* Convenient command that create, post into and then archived a channel.
|
||||
* @param {string} name - name of channel to be created
|
||||
* @param {string} displayName - display name of channel to be created
|
||||
* @param {string} type - type of channel
|
||||
* @param {string} teamId - team Id where the channel will be added
|
||||
* @param {string[]} [messages] - messages to be posted before archiving a channel
|
||||
* @param {UserProfile} [user] - user who will be posting the messages
|
||||
* @returns {Channel} archived channel
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateArchivedChannel('channel-name', 'channel-display-name', 'team-id', messages, user).then((channel) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
apiCreateArchivedChannel(name: string, displayName: string, type: string, teamId: string, messages?: string[], user?: UserProfile): Chainable<Channel>;
|
||||
|
||||
/**
|
||||
* Command to convert a GM to a private channel
|
||||
* @param {string} channelId - channel id of GM to be converted
|
||||
* @param {string} teamId - id of team to move the converted private channel to
|
||||
* @param {string} displayName - display name of converted channel
|
||||
* @param {string} name - name of converted channel
|
||||
*/
|
||||
apiConvertGMToPrivateChannel(channelId: string, teamId: string, displayName: string, name: string): Chainable;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getRandomId} from '../../utils';
|
||||
|
||||
// *****************************************************************************
|
||||
// Channels
|
||||
// https://api.mattermost.com/#tag/channels
|
||||
// *****************************************************************************
|
||||
|
||||
export function createChannelPatch(teamId, name, displayName, type = 'O', purpose = '', header = '', unique = true) {
|
||||
const randomSuffix = getRandomId();
|
||||
|
||||
return {
|
||||
team_id: teamId,
|
||||
name: unique ? `${name}-${randomSuffix}` : name,
|
||||
display_name: unique ? `${displayName} ${randomSuffix}` : displayName,
|
||||
type,
|
||||
purpose,
|
||||
header,
|
||||
};
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateChannel', (...args) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels',
|
||||
method: 'POST',
|
||||
body: createChannelPatch(...args),
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiCreateDirectChannel', (userIds = []) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/direct',
|
||||
method: 'POST',
|
||||
body: userIds,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiCreateGroupChannel', (userIds = []) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/group',
|
||||
method: 'POST',
|
||||
body: userIds,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiUpdateChannel', (channelId, channelData) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId,
|
||||
method: 'PUT',
|
||||
body: {
|
||||
id: channelId,
|
||||
...channelData,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiPatchChannel', (channelId, channelData) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/channels/${channelId}/patch`,
|
||||
body: channelData,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiPatchChannelPrivacy', (channelId, privacy = 'O') => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/channels/${channelId}/privacy`,
|
||||
body: {privacy},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetChannel', (channelId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/channels/${channelId}`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetChannelByName', (teamName, channelName) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/teams/name/${teamName}/channels/name/${channelName}`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetAllChannels', () => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channels: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetChannelsForUser', (userId, teamId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/teams/${teamId}/channels`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channels: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiDeleteChannel', (channelId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId,
|
||||
method: 'DELETE',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiAddUserToChannel', (channelId, userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId + '/members',
|
||||
method: 'POST',
|
||||
body: {
|
||||
user_id: userId,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({member: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiRemoveUserFromChannel', (channelId, userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId + '/members/' + userId,
|
||||
method: 'DELETE',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({member: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiCreateArchivedChannel', (name, displayName, type = 'O', teamId, messages = [], user) => {
|
||||
return cy.apiCreateChannel(teamId, name, displayName, type).then(({channel}) => {
|
||||
Cypress._.forEach(messages, (message) => {
|
||||
cy.postMessageAs({
|
||||
sender: user,
|
||||
message,
|
||||
channelId: channel.id,
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiDeleteChannel(channel.id);
|
||||
return cy.wrap(channel);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiConvertGMToPrivateChannel', (channelId, teamId, displayName, name) => {
|
||||
const body = {
|
||||
channel_id: channelId,
|
||||
team_id: teamId,
|
||||
display_name: displayName,
|
||||
name,
|
||||
};
|
||||
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/channels/${channelId}/convert_to_channel?team_id=${teamId}`,
|
||||
method: 'POST',
|
||||
body,
|
||||
});
|
||||
});
|
||||
435
e2e-tests/cypress/tests/support/api/channel.ts
Normal file
435
e2e-tests/cypress/tests/support/api/channel.ts
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Channel, ChannelMembership, ChannelType} from '@mattermost/types/channels';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import {ChainableT} from 'tests/types';
|
||||
import {getRandomId} from '../../utils';
|
||||
|
||||
// *****************************************************************************
|
||||
// Channels
|
||||
// https://api.mattermost.com/#tag/channels
|
||||
// *****************************************************************************
|
||||
|
||||
export function createChannelPatch(teamId: string, name: string, displayName: string, type: ChannelType = 'O', purpose = '', header = '', unique = true): Partial<Channel> {
|
||||
const randomSuffix = getRandomId();
|
||||
|
||||
return {
|
||||
team_id: teamId,
|
||||
name: unique ? `${name}-${randomSuffix}` : name,
|
||||
display_name: unique ? `${displayName} ${randomSuffix}` : displayName,
|
||||
type,
|
||||
purpose,
|
||||
header,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new channel.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels/post
|
||||
* @param {String} teamId - Unique handler for a team, will be present in the team URL
|
||||
* @param {String} name - Unique handler for a channel, will be present in the team URL
|
||||
* @param {String} displayName - Non-unique UI name for the channel
|
||||
* @param {String} type - 'O' for a public channel (default), 'P' for a private channel
|
||||
* @param {String} purpose - A short description of the purpose of the channel
|
||||
* @param {String} header - Markdown-formatted text to display in the header of the channel
|
||||
* @param {Boolean} [unique=true] - if true (default), it will create with unique/random channel name.
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateChannel('team-id', 'test-channel', 'Test Channel').then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
function apiCreateChannel(
|
||||
teamId: string,
|
||||
name: string,
|
||||
displayName: string,
|
||||
type?: ChannelType,
|
||||
purpose?: string,
|
||||
header?: string,
|
||||
unique: boolean = true): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels',
|
||||
method: 'POST',
|
||||
body: createChannelPatch(teamId, name, displayName, type, purpose, header, unique),
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateChannel', apiCreateChannel);
|
||||
|
||||
/**
|
||||
* Create a new direct message channel between two users.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1direct/post
|
||||
* @param {string[]} userIds - The two user ids to be in the direct message
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateDirectChannel(['user-1-id', 'user-2-id']).then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
function apiCreateDirectChannel(userIds: string[] = []): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/direct',
|
||||
method: 'POST',
|
||||
body: userIds,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateDirectChannel', apiCreateDirectChannel);
|
||||
|
||||
/**
|
||||
* Create a new group message channel to group of users via API. If the logged in user's id is not included in the list, it will be appended to the end.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1group/post
|
||||
* @param {string[]} userIds - User ids to be in the group message channel
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateGroupChannel(['user-1-id', 'user-2-id', 'current-user-id']).then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
function apiCreateGroupChannel(userIds: string[]): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/group',
|
||||
method: 'POST',
|
||||
body: userIds,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateGroupChannel', apiCreateGroupChannel);
|
||||
|
||||
/**
|
||||
* Update a channel.
|
||||
* The fields that can be updated are listed as parameters. Omitted fields will be treated as blanks.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}/put
|
||||
* @param {string} channelId - The channel ID to be updated
|
||||
* @param {Channel} channel - Channel object to be updated
|
||||
* @param {string} channel.name - The unique handle for the channel, will be present in the channel URL
|
||||
* @param {string} channel.display_name - The non-unique UI name for the channel
|
||||
* @param {string} channel.purpose - A short description of the purpose of the channel
|
||||
* @param {string} channel.header - Markdown-formatted text to display in the header of the channel
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiUpdateChannel('channel-id', {name: 'new-name', display_name: 'New Display Name'. 'purpose': 'Updated purpose', 'header': 'Updated header'});
|
||||
*/
|
||||
function apiUpdateChannel(channelId: string, channel: Channel): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId,
|
||||
method: 'PUT',
|
||||
body: {
|
||||
id: channelId,
|
||||
...channel,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiUpdateChannel', apiUpdateChannel);
|
||||
|
||||
/**
|
||||
* Partially update a channel by providing only the fields you want to update.
|
||||
* Omitted fields will not be updated.
|
||||
* The fields that can be updated are defined in the request body, all other provided fields will be ignored.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}~1patch/put
|
||||
* @param {string} channelId - The channel ID to be patched
|
||||
* @param {Channel} channel - Channel object to be patched
|
||||
* @param {string} channel.name - The unique handle for the channel, will be present in the channel URL
|
||||
* @param {string} channel.display_name - The non-unique UI name for the channel
|
||||
* @param {string} channel.purpose - A short description of the purpose of the channel
|
||||
* @param {string} channel.header - Markdown-formatted text to display in the header of the channel
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchChannel('channel-id', {name: 'new-name', display_name: 'New Display Name'});
|
||||
*/
|
||||
function apiPatchChannel(channelId: string, channel: Partial<Channel>): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/channels/${channelId}/patch`,
|
||||
body: channel,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiPatchChannel', apiPatchChannel);
|
||||
|
||||
/**
|
||||
* Updates channel's privacy allowing changing a channel from Public to Private and back.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}~1privacy/put
|
||||
* @param {string} channelId - The channel ID to be patched
|
||||
* @param {string} privacy - The privacy the channel should be set too. P = Private, O = Open
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchChannelPrivacy('channel-id', 'P');
|
||||
*/
|
||||
function apiPatchChannelPrivacy(channelId: string, privacy = 'O'): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/channels/${channelId}/privacy`,
|
||||
body: {privacy},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiPatchChannelPrivacy', apiPatchChannelPrivacy);
|
||||
|
||||
/**
|
||||
* Get channel from the provided channel id string.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}/get
|
||||
* @param {string} channelId - Channel ID
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetChannel('channel-id').then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
function apiGetChannel(channelId: string): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/channels/${channelId}`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetChannel', apiGetChannel);
|
||||
|
||||
/**
|
||||
* Gets a channel from the provided team name and channel name strings.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1teams~1name~1{team_name}~1channels~1name~1{channel_name}/get
|
||||
* @param {string} teamName - Team name
|
||||
* @param {string} channelName - Channel name
|
||||
* @returns {Channel} `out.channel` as `Channel`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetChannelByName('team-name', 'channel-name').then(({channel}) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
function apiGetChannelByName(teamName: string, channelName: string): ChainableT<{channel: Channel}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/teams/name/${teamName}/channels/name/${channelName}`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channel: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetChannelByName', apiGetChannelByName);
|
||||
|
||||
/**
|
||||
* Get a list of all channels.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels/get
|
||||
* @returns {Channel[]} `out.channels` as `Channel[]`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetAllChannels().then(({channels}) => {
|
||||
* // do something with channels
|
||||
* });
|
||||
*/
|
||||
function apiGetAllChannels(): ChainableT<{channels: Channel[]}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channels: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetAllChannels', apiGetAllChannels);
|
||||
|
||||
/**
|
||||
* Get channels for user.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1users~1{user_id}~1teams~1{team_id}~1channels/get
|
||||
* @returns {Channel[]} `out.channels` as `Channel[]`
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetChannelsForUser().then(({channels}) => {
|
||||
* // do something with channels
|
||||
* });
|
||||
*/
|
||||
function apiGetChannelsForUser(userId: string, teamId: string): ChainableT<{channels: Channel[]}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/teams/${teamId}/channels`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({channels: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetChannelsForUser', apiGetChannelsForUser);
|
||||
|
||||
/**
|
||||
* Soft deletes a channel, by marking the channel as deleted in the database.
|
||||
* Soft deleted channels will not be accessible in the user interface.
|
||||
* Direct and group message channels cannot be deleted.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}/delete
|
||||
* @param {string} channelId - The channel ID to be deleted
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDeleteChannel('channel-id');
|
||||
*/
|
||||
function apiDeleteChannel(channelId: string): ChainableT<any> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId,
|
||||
method: 'DELETE',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiDeleteChannel', apiDeleteChannel);
|
||||
|
||||
/**
|
||||
* Add a user to a channel by creating a channel member object.
|
||||
* See https://api.mattermost.com/#tag/channels/paths/~1channels~1{channel_id}~1members/post
|
||||
* @param {string} channelId - Channel ID
|
||||
* @param {string} userId - User ID to add to the channel
|
||||
* @returns {ChannelMembership} `out.member` as `ChannelMembership`
|
||||
*
|
||||
* @example
|
||||
* cy.apiAddUserToChannel('channel-id', 'user-id').then(({member}) => {
|
||||
* // do something with member
|
||||
* });
|
||||
*/
|
||||
function apiAddUserToChannel(channelId: string, userId: string): ChainableT<{member: ChannelMembership}> {
|
||||
return cy.request<ChannelMembership>({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId + '/members',
|
||||
method: 'POST',
|
||||
body: {
|
||||
user_id: userId,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(201);
|
||||
return cy.wrap({member: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiAddUserToChannel', apiAddUserToChannel);
|
||||
|
||||
function apiRemoveUserFromChannel(channelId, userId): ChainableT<any> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/channels/' + channelId + '/members/' + userId,
|
||||
method: 'DELETE',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({member: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiRemoveUserFromChannel', apiRemoveUserFromChannel);
|
||||
|
||||
/**
|
||||
* Convenient command that create, post into and then archived a channel.
|
||||
* @param {string} name - name of channel to be created
|
||||
* @param {string} displayName - display name of channel to be created
|
||||
* @param {string} type - type of channel
|
||||
* @param {string} teamId - team Id where the channel will be added
|
||||
* @param {string[]} [messages] - messages to be posted before archiving a channel
|
||||
* @param {UserProfile} [user] - user who will be posting the messages
|
||||
* @returns {Channel} archived channel
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateArchivedChannel('channel-name', 'channel-display-name', 'team-id', messages, user).then((channel) => {
|
||||
* // do something with channel
|
||||
* });
|
||||
*/
|
||||
function apiCreateArchivedChannel(name: string, displayName: string, type: ChannelType = 'O', teamId: string, messages: string[] = [], user?: UserProfile): ChainableT<Channel> {
|
||||
return cy.apiCreateChannel(teamId, name, displayName, type).then(({channel}) => {
|
||||
Cypress._.forEach(messages, (message) => {
|
||||
cy.postMessageAs({
|
||||
sender: user,
|
||||
message,
|
||||
channelId: channel.id,
|
||||
});
|
||||
});
|
||||
|
||||
cy.apiDeleteChannel(channel.id);
|
||||
return cy.wrap(channel);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateArchivedChannel', apiCreateArchivedChannel);
|
||||
|
||||
/**
|
||||
* Command to convert a GM to a private channel
|
||||
* @param {string} channelId - channel id of GM to be converted
|
||||
* @param {string} teamId - id of team to move the converted private channel to
|
||||
* @param {string} displayName - display name of converted channel
|
||||
* @param {string} name - name of converted channel
|
||||
*/
|
||||
function apiConvertGMToPrivateChannel(channelId: string, teamId: string, displayName: string, name: string): ChainableT<any> {
|
||||
const body = {
|
||||
channel_id: channelId,
|
||||
team_id: teamId,
|
||||
display_name: displayName,
|
||||
name,
|
||||
};
|
||||
|
||||
return cy.request<void>({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/channels/${channelId}/convert_to_channel?team_id=${teamId}`,
|
||||
method: 'POST',
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiConvertGMToPrivateChannel', apiConvertGMToPrivateChannel);
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
apiCreateChannel: typeof apiCreateChannel;
|
||||
apiCreateDirectChannel: typeof apiCreateDirectChannel;
|
||||
apiCreateGroupChannel: typeof apiCreateGroupChannel;
|
||||
apiUpdateChannel: typeof apiUpdateChannel;
|
||||
apiPatchChannel: typeof apiPatchChannel;
|
||||
apiPatchChannelPrivacy: typeof apiPatchChannelPrivacy;
|
||||
apiGetChannel: typeof apiGetChannel;
|
||||
apiGetChannelByName: typeof apiGetChannelByName;
|
||||
apiGetAllChannels: typeof apiGetAllChannels;
|
||||
apiGetChannelsForUser: typeof apiGetChannelsForUser;
|
||||
apiDeleteChannel: typeof apiDeleteChannel;
|
||||
apiAddUserToChannel: typeof apiAddUserToChannel;
|
||||
apiRemoveUserFromChannel: typeof apiRemoveUserFromChannel;
|
||||
apiCreateArchivedChannel: typeof apiCreateArchivedChannel;
|
||||
apiConvertGMToPrivateChannel: typeof apiConvertGMToPrivateChannel;
|
||||
}
|
||||
}
|
||||
}
|
||||
165
e2e-tests/cypress/tests/support/api/preference.d.ts
vendored
165
e2e-tests/cypress/tests/support/api/preference.d.ts
vendored
|
|
@ -1,165 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Specific link to https://api.mattermost.com
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `api` prefix, e.g. `apiLogin`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
// *******************************************************************************
|
||||
// Preferences
|
||||
// https://api.mattermost.com/#tag/preferences
|
||||
// *******************************************************************************
|
||||
|
||||
/**
|
||||
* Save a list of the user's preferences.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {PreferenceType[]} preferences - List of preference objects
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveUserPreference([{user_id: 'user-id', category: 'display_settings', name: 'channel_display_mode', value: 'full'}], 'user-id');
|
||||
*/
|
||||
apiSaveUserPreference(preferences: PreferenceType[], userId: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Get the full list of the user's preferences.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/get
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have a list of preference objects
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUserPreference('user-id');
|
||||
*/
|
||||
apiGetUserPreference(userId: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save clock display mode to 24-hour preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {boolean} is24Hour - true (default) or false for 12-hour
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveClockDisplayModeTo24HourPreference(true);
|
||||
*/
|
||||
apiSaveClockDisplayModeTo24HourPreference(is24Hour: boolean): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save onboarding tasklist preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} name - options are complete_profile, team_setup, invite_members or hide
|
||||
* @param {string} value - options are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveOnboardingTaskListPreference('user-id', 'hide', 'true');
|
||||
*/
|
||||
apiSaveOnboardingTaskListPreference(userId: string, name: string, value: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save skip steps preference.
|
||||
* @param userId - User ID
|
||||
* @param {string} value - options are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveSkipStepsPreference('user-id', 'true');
|
||||
*/
|
||||
apiSaveSkipStepsPreference(userId: string, value: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save DM channel show preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} otherUserId - Other user in a DM channel
|
||||
* @param {string} value - options are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveDirectChannelShowPreference('user-id', 'other-user-id', 'false');
|
||||
*/
|
||||
apiSaveDirectChannelShowPreference(userId: string, otherUserId: string, value: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save Collapsed Reply Threads preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} value - options are 'on' or 'off'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveCRTPreference('user-id', 'on');
|
||||
*/
|
||||
apiSaveCRTPreference(userId: string, value: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Saves tutorial step of a user
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} value - value of tutorial step, e.g. '999' (default, completed tutorial)
|
||||
*/
|
||||
apiSaveTutorialStep(userId: string, value: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save cloud trial banner preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} name - options are trial or hide
|
||||
* @param {string} value - options are 'max_days_banner' or '3_days_banner' for trial, and 'true' or 'false' for hide
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveCloudTrialBannerPreference('user-id', 'hide', 'true');
|
||||
*/
|
||||
apiSaveCloudTrialBannerPreference(userId: string, name: string, value: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save show trial modal.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} name - trial_modal_auto_shown
|
||||
* @param {string} value - values are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveStartTrialModal('user-id', 'true');
|
||||
*/
|
||||
apiSaveStartTrialModal(userId: string, value: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Save drafts tour tip preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} value - values are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveDraftsTourTipPreference('user-id', 'true');
|
||||
*/
|
||||
apiSaveDraftsTourTipPreference(userId: string, value: boolean): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Mark Boards welcome page as viewed.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiBoardsWelcomePageViewed('user-id');
|
||||
*/
|
||||
apiBoardsWelcomePageViewed(userId: string): Chainable<Response>;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,409 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import theme from '../../fixtures/theme.json';
|
||||
|
||||
// *****************************************************************************
|
||||
// Preferences
|
||||
// https://api.mattermost.com/#tag/preferences
|
||||
// *****************************************************************************
|
||||
|
||||
/**
|
||||
* Saves user's preference directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Array} preference - a list of user's preferences
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveUserPreference', (preferences = [], userId = 'me') => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/preferences`,
|
||||
method: 'PUT',
|
||||
body: preferences,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves clock display mode 24-hour preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Boolean} is24Hour - Either true (default) or false
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveClockDisplayModeTo24HourPreference', (is24Hour = true) => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'use_military_time',
|
||||
value: is24Hour.toString(),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves channel display mode preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {String} value - Either "full" (default) or "centered"
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveChannelDisplayModePreference', (value = 'full') => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'channel_display_mode',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves message display preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {String} value - Either "clean" (default) or "compact"
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveMessageDisplayPreference', (value = 'clean') => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'message_display',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves teammate name display preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {String} value - Either "username" (default), "nickname_full_name" or "full_name"
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveTeammateNameDisplayPreference', (value = 'username') => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'name_format',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves theme preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Object} value - theme object. Will pass default value if none is provided.
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveThemePreference', (value = JSON.stringify(theme.default)) => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'theme',
|
||||
name: '',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
const defaultSidebarSettingPreference = {
|
||||
grouping: 'by_type',
|
||||
unreads_at_top: 'true',
|
||||
favorite_at_top: 'true',
|
||||
sorting: 'alpha',
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves theme preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Object} value - sidebar settings object. Will pass default value if none is provided.
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveSidebarSettingPreference', (value = {}) => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const newValue = {
|
||||
...defaultSidebarSettingPreference,
|
||||
...value,
|
||||
};
|
||||
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'sidebar_settings',
|
||||
name: '',
|
||||
value: JSON.stringify(newValue),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves the preference on whether to show link and image previews
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {boolean} show - Either "true" to show link and images previews (default), or "false"
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveLinkPreviewsPreference', (show = 'true') => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'link_previews',
|
||||
value: show,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves the preference on whether to show link and image previews expanded
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {boolean} collapse - Either "true" to show previews collapsed (default), or "false"
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveCollapsePreviewsPreference', (collapse = 'true') => {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'collapse_previews',
|
||||
value: collapse,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves tutorial step of a user
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {string} value - value of tutorial step, e.g. '999' (default, completed tutorial)
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveTutorialStep', (userId, value = '999') => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'tutorial_step',
|
||||
name: userId,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveOnboardingPreference', (userId, name, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'recommended_next_steps',
|
||||
name,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveDirectChannelShowPreference', (userId, otherUserId, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'direct_channel_show',
|
||||
name: otherUserId,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiHideSidebarWhatsNewModalPreference', (userId, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'whats_new_modal',
|
||||
name: 'has_seen_sidebar_whats_new_modal',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetUserPreference', (userId) => {
|
||||
return cy.request(`/api/v4/users/${userId}/preferences`).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response.body);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveCRTPreference', (userId, value = 'on') => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'display_settings',
|
||||
name: 'collapsed_reply_threads',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveCloudTrialBannerPreference', (userId, name, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'cloud_trial_banner',
|
||||
name,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveStartTrialModal', (userId, value = 'true') => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'start_trial_modal',
|
||||
name: 'trial_modal_auto_shown',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveOnboardingTaskListPreference', (userId, name, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'onboarding_task_list',
|
||||
name,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveSkipStepsPreference', (userId, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'recommended_next_steps',
|
||||
name: 'skip',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveUnreadScrollPositionPreference', (userId, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'advanced_settings',
|
||||
name: 'unread_scroll_position',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiSaveDraftsTourTipPreference', (userId, value) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'drafts',
|
||||
name: 'drafts_tour_tip_showed',
|
||||
value: JSON.stringify({drafts_tour_tip_showed: value}),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiBoardsWelcomePageViewed', (userId) => {
|
||||
const preferences = [{
|
||||
user_id: userId,
|
||||
category: 'boards',
|
||||
name: 'welcomePageViewed',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'boards',
|
||||
name: 'version72MessageCanceled',
|
||||
value: 'true',
|
||||
}];
|
||||
|
||||
return cy.apiSaveUserPreference(preferences, userId);
|
||||
});
|
||||
|
||||
/**
|
||||
* Saves Join/Leave messages preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Boolean} enable - Either true (default) or false
|
||||
*/
|
||||
Cypress.Commands.add('apiSaveJoinLeaveMessagesPreference', (userId, enable = true) => {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'advanced_settings',
|
||||
name: 'join_leave',
|
||||
value: enable.toString(),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
});
|
||||
|
||||
/**
|
||||
* Disables tutorials for user by marking them finished
|
||||
*/
|
||||
Cypress.Commands.add('apiDisableTutorials', (userId) => {
|
||||
const preferences = [
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'playbook_edit',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'tutorial_pb_run_details',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'crt_thread_pane_step',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'playbook_preview',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'tutorial_step',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'crt_tutorial_triggered',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'crt_thread_pane_step',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'drafts',
|
||||
name: 'drafts_tour_tip_showed',
|
||||
value: '{"drafts_tour_tip_showed":true}',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'app_bar',
|
||||
name: 'channel_with_board_tip_showed',
|
||||
value: '{"channel_with_board_tip_showed":true}',
|
||||
},
|
||||
];
|
||||
|
||||
return cy.apiSaveUserPreference(preferences, userId);
|
||||
});
|
||||
590
e2e-tests/cypress/tests/support/api/preference.ts
Normal file
590
e2e-tests/cypress/tests/support/api/preference.ts
Normal file
|
|
@ -0,0 +1,590 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ChainableT} from 'tests/types';
|
||||
import theme from '../../fixtures/theme.json';
|
||||
import {PreferenceType} from '@mattermost/types/preferences';
|
||||
|
||||
// *****************************************************************************
|
||||
// Preferences
|
||||
// https://api.mattermost.com/#tag/preferences
|
||||
// *****************************************************************************
|
||||
|
||||
/**
|
||||
* Save a list of the user's preferences.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {PreferenceType[]} preferences - List of preference objects
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveUserPreference([{user_id: 'user-id', category: 'display_settings', name: 'channel_display_mode', value: 'full'}], 'user-id');
|
||||
*/
|
||||
function apiSaveUserPreference(preferences: PreferenceType[] = [], userId = 'me'): ChainableT<any> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/preferences`,
|
||||
method: 'PUT',
|
||||
body: preferences,
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveUserPreference', apiSaveUserPreference);
|
||||
|
||||
/**
|
||||
* Save clock display mode to 24-hour preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {boolean} is24Hour - true (default) or false for 12-hour
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveClockDisplayModeTo24HourPreference(true);
|
||||
*/
|
||||
function apiSaveClockDisplayModeTo24HourPreference(is24Hour = true): ChainableT<any> {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'use_military_time',
|
||||
value: is24Hour.toString(),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveClockDisplayModeTo24HourPreference', apiSaveClockDisplayModeTo24HourPreference);
|
||||
|
||||
/**
|
||||
* Saves channel display mode preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {String} value - Either "full" (default) or "centered"
|
||||
*/
|
||||
function apiSaveChannelDisplayModePreference(value = 'full') {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'channel_display_mode',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
Cypress.Commands.add('apiSaveChannelDisplayModePreference', apiSaveChannelDisplayModePreference);
|
||||
|
||||
/**
|
||||
* Saves message display preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {String} value - Either "clean" (default) or "compact"
|
||||
*/
|
||||
function apiSaveMessageDisplayPreference(value = 'clean') {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'message_display',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveMessageDisplayPreference', apiSaveMessageDisplayPreference);
|
||||
|
||||
/**
|
||||
* Saves teammate name display preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {String} value - Either "username" (default), "nickname_full_name" or "full_name"
|
||||
*/
|
||||
function apiSaveTeammateNameDisplayPreference(value = 'username') {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'name_format',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveTeammateNameDisplayPreference', apiSaveTeammateNameDisplayPreference);
|
||||
|
||||
/**
|
||||
* Saves theme preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Object} value - theme object. Will pass default value if none is provided.
|
||||
*/
|
||||
function apiSaveThemePreference(value = JSON.stringify(theme.default)) {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'theme',
|
||||
name: '',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveThemePreference', apiSaveThemePreference);
|
||||
|
||||
const defaultSidebarSettingPreference = {
|
||||
grouping: 'by_type',
|
||||
unreads_at_top: 'true',
|
||||
favorite_at_top: 'true',
|
||||
sorting: 'alpha',
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves theme preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Object} value - sidebar settings object. Will pass default value if none is provided.
|
||||
*/
|
||||
function apiSaveSidebarSettingPreference(value = {}) {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const newValue = {
|
||||
...defaultSidebarSettingPreference,
|
||||
...value,
|
||||
};
|
||||
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'sidebar_settings',
|
||||
name: '',
|
||||
value: JSON.stringify(newValue),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveSidebarSettingPreference', apiSaveSidebarSettingPreference);
|
||||
|
||||
/**
|
||||
* Saves the preference on whether to show link and image previews
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {boolean} show - Either "true" to show link and images previews (default), or "false"
|
||||
*/
|
||||
function apiSaveLinkPreviewsPreference(show = 'true') {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'link_previews',
|
||||
value: show,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveLinkPreviewsPreference', apiSaveLinkPreviewsPreference);
|
||||
|
||||
/**
|
||||
* Saves the preference on whether to show link and image previews expanded
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {boolean} collapse - Either "true" to show previews collapsed (default), or "false"
|
||||
*/
|
||||
function apiSaveCollapsePreviewsPreference(collapse = 'true') {
|
||||
return cy.getCookie('MMUSERID').then((cookie) => {
|
||||
const preference = {
|
||||
user_id: cookie.value,
|
||||
category: 'display_settings',
|
||||
name: 'collapse_previews',
|
||||
value: collapse,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference]);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveCollapsePreviewsPreference', apiSaveCollapsePreviewsPreference);
|
||||
|
||||
/**
|
||||
* Saves tutorial step of a user
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} value - value of tutorial step, e.g. '999' (default, completed tutorial)
|
||||
*/
|
||||
function apiSaveTutorialStep(userId: string, value = '999'): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'tutorial_step',
|
||||
name: userId,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveTutorialStep', apiSaveTutorialStep);
|
||||
|
||||
function apiSaveOnboardingPreference(userId, name, value) {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'recommended_next_steps',
|
||||
name,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveOnboardingPreference', apiSaveOnboardingPreference);
|
||||
|
||||
/**
|
||||
* Save DM channel show preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} otherUserId - Other user in a DM channel
|
||||
* @param {string} value - options are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveDirectChannelShowPreference('user-id', 'other-user-id', 'false');
|
||||
*/
|
||||
function apiSaveDirectChannelShowPreference(userId: string, otherUserId: string, value: string): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'direct_channel_show',
|
||||
name: otherUserId,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveDirectChannelShowPreference', apiSaveDirectChannelShowPreference);
|
||||
|
||||
function apiHideSidebarWhatsNewModalPreference(userId, value) {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'whats_new_modal',
|
||||
name: 'has_seen_sidebar_whats_new_modal',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiHideSidebarWhatsNewModalPreference', apiHideSidebarWhatsNewModalPreference);
|
||||
|
||||
/**
|
||||
* Get the full list of the user's preferences.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/get
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have a list of preference objects
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUserPreference('user-id');
|
||||
*/
|
||||
function apiGetUserPreference(userId: string): ChainableT<any> {
|
||||
return cy.request(`/api/v4/users/${userId}/preferences`).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response.body);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetUserPreference', apiGetUserPreference);
|
||||
|
||||
/**
|
||||
* Save Collapsed Reply Threads preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} value - options are 'on' or 'off'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveCRTPreference('user-id', 'on');
|
||||
*/
|
||||
function apiSaveCRTPreference(userId: string, value = 'on'): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'display_settings',
|
||||
name: 'collapsed_reply_threads',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveCRTPreference', apiSaveCRTPreference);
|
||||
|
||||
/**
|
||||
* Save cloud trial banner preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} name - options are trial or hide
|
||||
* @param {string} value - options are 'max_days_banner' or '3_days_banner' for trial, and 'true' or 'false' for hide
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveCloudTrialBannerPreference('user-id', 'hide', 'true');
|
||||
*/
|
||||
function apiSaveCloudTrialBannerPreference(userId: string, name: string, value: string): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'cloud_trial_banner',
|
||||
name,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveCloudTrialBannerPreference', apiSaveCloudTrialBannerPreference);
|
||||
|
||||
/**
|
||||
* Save show trial modal.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} name - trial_modal_auto_shown
|
||||
* @param {string} value - values are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveStartTrialModal('user-id', 'true');
|
||||
*/
|
||||
function apiSaveStartTrialModal(userId: string, value = 'true'): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'start_trial_modal',
|
||||
name: 'trial_modal_auto_shown',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveStartTrialModal', apiSaveStartTrialModal);
|
||||
|
||||
/**
|
||||
* Save onboarding tasklist preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} name - options are complete_profile, team_setup, invite_members or hide
|
||||
* @param {string} value - options are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveOnboardingTaskListPreference('user-id', 'hide', 'true');
|
||||
*/
|
||||
function apiSaveOnboardingTaskListPreference(userId: string, name: string, value: string): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'onboarding_task_list',
|
||||
name,
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveOnboardingTaskListPreference', apiSaveOnboardingTaskListPreference);
|
||||
|
||||
/**
|
||||
* Save skip steps preference.
|
||||
* @param userId - User ID
|
||||
* @param {string} value - options are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveSkipStepsPreference('user-id', 'true');
|
||||
*/
|
||||
function apiSaveSkipStepsPreference(userId: string, value: string): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'recommended_next_steps',
|
||||
name: 'skip',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveSkipStepsPreference', apiSaveSkipStepsPreference);
|
||||
|
||||
function apiSaveUnreadScrollPositionPreference(userId, value) {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'advanced_settings',
|
||||
name: 'unread_scroll_position',
|
||||
value,
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveUnreadScrollPositionPreference', apiSaveUnreadScrollPositionPreference);
|
||||
|
||||
/**
|
||||
* Save drafts tour tip preference.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @param {string} value - values are 'true' or 'false'
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiSaveDraftsTourTipPreference('user-id', 'true');
|
||||
*/
|
||||
function apiSaveDraftsTourTipPreference(userId: string, value: boolean): ChainableT<any> {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'drafts',
|
||||
name: 'drafts_tour_tip_showed',
|
||||
value: JSON.stringify({drafts_tour_tip_showed: value}),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveDraftsTourTipPreference', apiSaveDraftsTourTipPreference);
|
||||
|
||||
/**
|
||||
* Mark Boards welcome page as viewed.
|
||||
* See https://api.mattermost.com/#tag/preferences/paths/~1users~1{user_id}~1preferences/put
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiBoardsWelcomePageViewed('user-id');
|
||||
*/
|
||||
function apiBoardsWelcomePageViewed(userId: string): ChainableT<any> {
|
||||
const preferences = [{
|
||||
user_id: userId,
|
||||
category: 'boards',
|
||||
name: 'welcomePageViewed',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'boards',
|
||||
name: 'version72MessageCanceled',
|
||||
value: 'true',
|
||||
}];
|
||||
|
||||
return cy.apiSaveUserPreference(preferences, userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiBoardsWelcomePageViewed', apiBoardsWelcomePageViewed);
|
||||
|
||||
/**
|
||||
* Saves Join/Leave messages preference of a user directly via API
|
||||
* This API assume that the user is logged in and has cookie to access
|
||||
* @param {Boolean} enable - Either true (default) or false
|
||||
*/
|
||||
function apiSaveJoinLeaveMessagesPreference(userId, enable = true) {
|
||||
const preference = {
|
||||
user_id: userId,
|
||||
category: 'advanced_settings',
|
||||
name: 'join_leave',
|
||||
value: enable.toString(),
|
||||
};
|
||||
|
||||
return cy.apiSaveUserPreference([preference], userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiSaveJoinLeaveMessagesPreference', apiSaveJoinLeaveMessagesPreference);
|
||||
|
||||
/**
|
||||
* Disables tutorials for user by marking them finished
|
||||
*/
|
||||
function apiDisableTutorials(userId) {
|
||||
const preferences = [
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'playbook_edit',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'tutorial_pb_run_details',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'crt_thread_pane_step',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'playbook_preview',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'tutorial_step',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'crt_tutorial_triggered',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'crt_thread_pane_step',
|
||||
name: userId,
|
||||
value: '999',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'drafts',
|
||||
name: 'drafts_tour_tip_showed',
|
||||
value: '{"drafts_tour_tip_showed":true}',
|
||||
},
|
||||
{
|
||||
user_id: userId,
|
||||
category: 'app_bar',
|
||||
name: 'channel_with_board_tip_showed',
|
||||
value: '{"channel_with_board_tip_showed":true}',
|
||||
},
|
||||
];
|
||||
|
||||
return cy.apiSaveUserPreference(preferences, userId);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiDisableTutorials', apiDisableTutorials);
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
apiSaveUserPreference: typeof apiSaveUserPreference;
|
||||
apiSaveClockDisplayModeTo24HourPreference: typeof apiSaveClockDisplayModeTo24HourPreference;
|
||||
apiSaveChannelDisplayModePreference: typeof apiSaveChannelDisplayModePreference;
|
||||
apiSaveMessageDisplayPreference: typeof apiSaveMessageDisplayPreference;
|
||||
apiSaveTeammateNameDisplayPreference: typeof apiSaveTeammateNameDisplayPreference;
|
||||
apiSaveThemePreference: typeof apiSaveThemePreference;
|
||||
apiSaveSidebarSettingPreference: typeof apiSaveSidebarSettingPreference;
|
||||
apiSaveLinkPreviewsPreference: typeof apiSaveLinkPreviewsPreference;
|
||||
apiSaveCollapsePreviewsPreference: typeof apiSaveCollapsePreviewsPreference;
|
||||
apiSaveTutorialStep: typeof apiSaveTutorialStep;
|
||||
apiSaveOnboardingPreference: typeof apiSaveOnboardingPreference;
|
||||
apiSaveDirectChannelShowPreference: typeof apiSaveDirectChannelShowPreference;
|
||||
apiHideSidebarWhatsNewModalPreference: typeof apiHideSidebarWhatsNewModalPreference;
|
||||
apiGetUserPreference: typeof apiGetUserPreference;
|
||||
apiSaveCRTPreference: typeof apiSaveCRTPreference;
|
||||
apiSaveCloudTrialBannerPreference: typeof apiSaveCloudTrialBannerPreference;
|
||||
apiSaveStartTrialModal: typeof apiSaveStartTrialModal;
|
||||
apiSaveOnboardingTaskListPreference: typeof apiSaveOnboardingTaskListPreference;
|
||||
apiSaveSkipStepsPreference: typeof apiSaveSkipStepsPreference;
|
||||
apiSaveUnreadScrollPositionPreference: typeof apiSaveUnreadScrollPositionPreference;
|
||||
apiSaveDraftsTourTipPreference: typeof apiSaveDraftsTourTipPreference;
|
||||
apiBoardsWelcomePageViewed: typeof apiBoardsWelcomePageViewed;
|
||||
apiSaveJoinLeaveMessagesPreference: typeof apiSaveJoinLeaveMessagesPreference;
|
||||
apiDisableTutorials: typeof apiDisableTutorials;
|
||||
}
|
||||
}
|
||||
}
|
||||
379
e2e-tests/cypress/tests/support/api/user.d.ts
vendored
379
e2e-tests/cypress/tests/support/api/user.d.ts
vendored
|
|
@ -1,379 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// ***************************************************************
|
||||
// Each command should be properly documented using JSDoc.
|
||||
// See https://jsdoc.app/index.html for reference.
|
||||
// Basic requirements for documentation are the following:
|
||||
// - Meaningful description
|
||||
// - Specific link to https://api.mattermost.com
|
||||
// - Each parameter with `@params`
|
||||
// - Return value with `@returns`
|
||||
// - Example usage with `@example`
|
||||
// Custom command should follow naming convention of having `api` prefix, e.g. `apiLogin`.
|
||||
// ***************************************************************
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
|
||||
/**
|
||||
* Login to server via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {string} user.username - username of a user
|
||||
* @param {string} user.password - password of user
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiLogin({username: 'sysadmin', password: 'secret'});
|
||||
*/
|
||||
apiLogin(user: UserProfile): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Login to server via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {string} user.username - username of a user
|
||||
* @param {string} user.password - password of user
|
||||
* @param {string} token - MFA token for the session
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiLoginWithMFA({username: 'sysadmin', password: 'secret', token: '123456'});
|
||||
*/
|
||||
apiLoginWithMFA(user: UserProfile, token: string): Chainable<{user: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Login as admin via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {Object} requestOptions - cypress' request options object, see https://docs.cypress.io/api/commands/request#Arguments
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiAdminLogin();
|
||||
*/
|
||||
apiAdminLogin(requestOptions?: Record<string, any>): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Login as admin via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {string} token - MFA token for the session
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiAdminLoginWithMFA(token);
|
||||
*/
|
||||
apiAdminLoginWithMFA(token: string): Chainable<{user: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Logout a user's active session from server via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1logout/post
|
||||
* Clears all cookies especially `MMAUTHTOKEN`, `MMUSERID` and `MMCSRF`.
|
||||
*
|
||||
* @example
|
||||
* cy.apiLogout();
|
||||
*/
|
||||
apiLogout();
|
||||
|
||||
/**
|
||||
* Get current user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}/get
|
||||
* @returns {user: UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetMe().then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
apiGetMe(): Chainable<{user: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Get a user by ID.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}/get
|
||||
* @param {String} userId - ID of a user to get profile
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUserById('user-id').then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
apiGetUserById(userId: string): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Get a user by email.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1email~1{email}/get
|
||||
* @param {String} email - email address of a user to get profile
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUserByEmail('email').then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
apiGetUserByEmail(email: string): Chainable<{user: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Get users by usernames.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1usernames/post
|
||||
* @param {String[]} usernames - list of usernames to get profiles
|
||||
* @returns {UserProfile[]} out.users: list of `UserProfile` objects
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUsersByUsernames().then(({users}) => {
|
||||
* // do something with users
|
||||
* });
|
||||
*/
|
||||
apiGetUsersByUsernames(usernames: string[]): Chainable<UserProfile[]>;
|
||||
|
||||
/**
|
||||
* Patch a user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1patch/put
|
||||
* @param {String} userId - ID of user to patch
|
||||
* @param {UserProfile} userData - user profile to be updated
|
||||
* @param {string} userData.email
|
||||
* @param {string} userData.username
|
||||
* @param {string} userData.first_name
|
||||
* @param {string} userData.last_name
|
||||
* @param {string} userData.nickname
|
||||
* @param {string} userData.locale
|
||||
* @param {Object} userData.timezone
|
||||
* @param {string} userData.position
|
||||
* @param {Object} userData.props
|
||||
* @param {Object} userData.notify_props
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchUser('user-id', {locale: 'en'}).then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
apiPatchUser(userId: string, userData: UserProfile): Chainable<{user: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Convenient command to patch a current user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1patch/put
|
||||
* @param {UserProfile} userData - user profile to be updated
|
||||
* @param {string} userData.email
|
||||
* @param {string} userData.username
|
||||
* @param {string} userData.first_name
|
||||
* @param {string} userData.last_name
|
||||
* @param {string} userData.nickname
|
||||
* @param {string} userData.locale
|
||||
* @param {Object} userData.timezone
|
||||
* @param {string} userData.position
|
||||
* @param {Object} userData.props
|
||||
* @param {Object} userData.notify_props
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchMe({locale: 'en'}).then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
apiPatchMe(userData: UserProfile): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Create an admin account based from the env variables defined in Cypress env.
|
||||
* @param {string} options.namePrefix - 'user' (default) or any prefix to easily identify a user
|
||||
* @param {boolean} options.bypassTutorial - true (default) or false for user to go thru tutorial steps
|
||||
* @param {boolean} options.showOnboarding - false (default) to hide or true to show Onboarding steps
|
||||
* @returns {UserProfile} `out.sysadmin` as `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateAdmin(options);
|
||||
*/
|
||||
apiCreateAdmin(options: Record<string, any>): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Create a randomly named admin account
|
||||
*
|
||||
* @param {boolean} options.loginAfter - false (default) or true if wants to login as the new admin.
|
||||
* @param {boolean} options.hideAdminTrialModal - true (default) or false if wants to hide Start Enterprise Trial modal.
|
||||
*
|
||||
* @returns {UserProfile} `out.sysadmin` as `UserProfile` object
|
||||
*/
|
||||
apiCreateCustomAdmin({loginAfter = false, hideAdminTrialModal = true} = {}): Chainable<{sysadmin: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Create a new user with an options to set name prefix and be able to bypass tutorial steps.
|
||||
* @param {string} options.user - predefined `user` object instead on random user
|
||||
* @param {string} options.prefix - 'user' (default) or any prefix to easily identify a user
|
||||
* @param {boolean} options.bypassTutorial - true (default) or false for user to go thru tutorial steps
|
||||
* @param {boolean} options.showOnboarding - false (default) to hide or true to show Onboarding steps
|
||||
* @returns {UserProfile} `out.user` as `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateUser(options);
|
||||
*/
|
||||
apiCreateUser(options?: {
|
||||
user?: Partial<UserProfile>;
|
||||
prefix?: string;
|
||||
createAt?: number;
|
||||
bypassTutorial?: boolean;
|
||||
showOnboarding?: boolean;
|
||||
}): Chainable<{user: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Create a new guest user with an options to set name prefix and be able to bypass tutorial steps.
|
||||
* @param {string} options.prefix - 'guest' (default) or any prefix to easily identify a guest
|
||||
* @param {boolean} options.bypassTutorial - true (default) or false for guest to go thru tutorial steps
|
||||
* @param {boolean} options.showOnboarding - false (default) to hide or true to show Onboarding steps
|
||||
* @returns {UserProfile} `out.guest` as `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateGuestUser(options);
|
||||
*/
|
||||
apiCreateGuestUser(options: Record<string, any>): Chainable<{guest: UserProfile}>;
|
||||
|
||||
/**
|
||||
* Revoke all active sessions for a user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1sessions~1revoke~1all/post
|
||||
* @param {String} userId - ID of a user
|
||||
* @returns {Object} `out.data` as response status
|
||||
*
|
||||
* @example
|
||||
* cy.apiRevokeUserSessions('user-id');
|
||||
*/
|
||||
apiRevokeUserSessions(userId: string): Chainable<Record<string, any>>;
|
||||
|
||||
/**
|
||||
* Get list of users based on query parameters
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users/get
|
||||
* @param {String} queryParams - see link on available query parameters
|
||||
* @returns {UserProfile[]} `out.users` as `UserProfile[]` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUsers().then(({users}) => {
|
||||
* // do something with users
|
||||
* });
|
||||
*/
|
||||
apiGetUsers(queryParams: Record<string, any>): Chainable<{users: UserProfile[]}>;
|
||||
|
||||
/**
|
||||
* Get list of users that are not team members.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users/get
|
||||
* @param {String} queryParams.teamId - Team ID
|
||||
* @param {String} queryParams.page - Page to select, 0 (default)
|
||||
* @param {String} queryParams.perPage - The number of users per page, 60 (default)
|
||||
* @returns {UserProfile[]} `out.users` as `UserProfile[]` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUsersNotInTeam({teamId: 'team-id'}).then(({users}) => {
|
||||
* // do something with users
|
||||
* });
|
||||
*/
|
||||
apiGetUsersNotInTeam(queryParams: Record<string, any>): Chainable<UserProfile[]>;
|
||||
|
||||
/**
|
||||
* Reactivate a user account.
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiActivateUser('user-id');
|
||||
*/
|
||||
apiActivateUser(userId: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Deactivate a user account.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}/delete
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDeactivateUser('user-id');
|
||||
*/
|
||||
apiDeactivateUser(userId: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Convert a regular user into a guest. This will convert the user into a guest for the whole system while retaining their existing team and channel memberships.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1demote/post
|
||||
* @param {string} userId - User ID
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiDemoteUserToGuest('user-id');
|
||||
*/
|
||||
apiDemoteUserToGuest(userId: string): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Convert a guest into a regular user. This will convert the guest into a user for the whole system while retaining any team and channel memberships and automatically joining them to the default channels.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1promote/post
|
||||
* @param {string} userId - User ID
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiPromoteGuestToUser('user-id');
|
||||
*/
|
||||
apiPromoteGuestToUser(userId: string): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Verifies a user's email via userId without having to go to the user's email inbox.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1email~1verify~1member/post
|
||||
* @param {string} userId - User ID
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiVerifyUserEmailById('user-id').then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
apiVerifyUserEmailById(userId: string): Chainable<UserProfile>;
|
||||
|
||||
/**
|
||||
* Update a user MFA.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1mfa/put
|
||||
* @param {String} userId - ID of user to patch
|
||||
* @param {boolean} activate - Whether MFA is going to be enabled or disabled
|
||||
* @param {string} token - MFA token/code
|
||||
* @example
|
||||
* cy.apiActivateUserMFA('user-id', activate: false);
|
||||
*/
|
||||
apiActivateUserMFA(userId: string, activate: boolean, token: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Create a user access token
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1tokens/post
|
||||
* @param {String} userId - ID of user for whom to generate token
|
||||
* @param {String} description - The description of the token usage
|
||||
* @example
|
||||
* cy.apiAccessToken('user-id', 'token for cypress tests');
|
||||
*/
|
||||
apiAccessToken(userId: string, description: string): Chainable<UserAccessToken>;
|
||||
|
||||
/**
|
||||
* Revoke a user access token
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1tokens~1revoke/post
|
||||
* @param {String} tokenId - The id of the token to revoke
|
||||
* @example
|
||||
* cy.apiRevokeAccessToken('token-id')
|
||||
*/
|
||||
apiRevokeAccessToken(tokenId: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Update a user auth method.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1mfa/put
|
||||
* @param {String} userId - ID of user to patch
|
||||
* @param {String} authData
|
||||
* @param {String} password
|
||||
* @param {String} authService
|
||||
* @example
|
||||
* cy.apiUpdateUserAuth('user-id', 'auth-data', 'password', 'auth-service');
|
||||
*/
|
||||
apiUpdateUserAuth(userId: string, authData: string, password: string, authService: string): Chainable<Response>;
|
||||
|
||||
/**
|
||||
* Get total count of users in the system
|
||||
* See https://api.mattermost.com/#operation/GetTotalUsersStats
|
||||
*
|
||||
* @returns {number} - total count of all users
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetTotalUsers().then(() => {
|
||||
* // do something with total users
|
||||
* });
|
||||
*/
|
||||
apiGetTotalUsers(): Chainable<number>;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,503 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import authenticator from 'authenticator';
|
||||
|
||||
import {getRandomId} from '../../utils';
|
||||
import {getAdminAccount} from '../env';
|
||||
|
||||
import {buildQueryString} from './helpers';
|
||||
|
||||
// *****************************************************************************
|
||||
// Users
|
||||
// https://api.mattermost.com/#tag/users
|
||||
// *****************************************************************************
|
||||
|
||||
Cypress.Commands.add('apiLogin', (user, requestOptions = {}) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/login',
|
||||
method: 'POST',
|
||||
body: {login_id: user.username || user.email, password: user.password},
|
||||
...requestOptions,
|
||||
}).then((response) => {
|
||||
if (requestOptions.failOnStatusCode) {
|
||||
expect(response.status).to.equal(200);
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
return cy.wrap({
|
||||
user: {
|
||||
...response.body,
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return cy.wrap({error: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiLoginWithMFA', (user, token) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/login',
|
||||
method: 'POST',
|
||||
body: {login_id: user.username, password: user.password, token},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({
|
||||
user: {
|
||||
...response.body,
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiAdminLogin', (requestOptions = {}) => {
|
||||
const admin = getAdminAccount();
|
||||
|
||||
// First, login with username
|
||||
cy.apiLogin(admin, requestOptions).then((resp) => {
|
||||
if (resp.error) {
|
||||
if (resp.error.id === 'mfa.validate_token.authenticate.app_error') {
|
||||
// On fail, try to login via MFA
|
||||
return cy.dbGetUser({username: admin.username}).then(({user: {mfasecret}}) => {
|
||||
const token = authenticator.generateToken(mfasecret);
|
||||
return cy.apiLoginWithMFA(admin, token);
|
||||
});
|
||||
}
|
||||
|
||||
// Or, try to login via email
|
||||
delete admin.username;
|
||||
return cy.apiLogin(admin, requestOptions);
|
||||
}
|
||||
|
||||
return resp;
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiAdminLoginWithMFA', (token) => {
|
||||
const admin = getAdminAccount();
|
||||
|
||||
return cy.apiLoginWithMFA(admin, token);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiLogout', () => {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/logout',
|
||||
method: 'POST',
|
||||
log: false,
|
||||
});
|
||||
|
||||
// * Verify logged out
|
||||
cy.visit('/login?extra=expired').url().should('include', '/login');
|
||||
|
||||
// # Ensure we clear out these specific cookies
|
||||
['MMAUTHTOKEN', 'MMUSERID', 'MMCSRF'].forEach((cookie) => {
|
||||
cy.clearCookie(cookie);
|
||||
});
|
||||
|
||||
// # Clear remainder of cookies
|
||||
cy.clearCookies();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetMe', () => {
|
||||
return cy.apiGetUserById('me');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetUserById', (userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/' + userId,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetUserByEmail', (email, failOnStatusCode = true) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/email/' + email,
|
||||
failOnStatusCode,
|
||||
}).then((response) => {
|
||||
const {body, status} = response;
|
||||
|
||||
if (failOnStatusCode) {
|
||||
expect(status).to.equal(200);
|
||||
return cy.wrap({user: body});
|
||||
}
|
||||
return cy.wrap({user: status === 200 ? body : null});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetUsersByUsernames', (usernames = []) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/usernames',
|
||||
method: 'POST',
|
||||
body: usernames,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({users: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiPatchUser', (userId, userData) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/patch`,
|
||||
body: userData,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiPatchMe', (data) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/me/patch',
|
||||
method: 'PUT',
|
||||
body: data,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiCreateCustomAdmin', ({loginAfter = false, hideAdminTrialModal = true} = {}) => {
|
||||
const sysadminUser = generateRandomUser('other-admin');
|
||||
|
||||
return cy.apiCreateUser({user: sysadminUser}).then(({user}) => {
|
||||
return cy.apiPatchUserRoles(user.id, ['system_admin', 'system_user']).then(() => {
|
||||
const data = {sysadmin: user};
|
||||
|
||||
cy.apiSaveStartTrialModal(user.id, hideAdminTrialModal.toString());
|
||||
|
||||
if (loginAfter) {
|
||||
return cy.apiLogin(user).then(() => {
|
||||
return cy.wrap(data);
|
||||
});
|
||||
}
|
||||
|
||||
return cy.wrap(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiCreateAdmin', () => {
|
||||
const {username, password} = getAdminAccount();
|
||||
|
||||
const sysadminUser = {
|
||||
username,
|
||||
password,
|
||||
first_name: 'Kenneth',
|
||||
last_name: 'Moreno',
|
||||
email: 'sysadmin@sample.mattermost.com',
|
||||
};
|
||||
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: '/api/v4/users',
|
||||
body: sysadminUser,
|
||||
};
|
||||
|
||||
// # Create a new user
|
||||
return cy.request(options).then((res) => {
|
||||
expect(res.status).to.equal(201);
|
||||
|
||||
return cy.wrap({sysadmin: {...res.body, password}});
|
||||
});
|
||||
});
|
||||
|
||||
function generateRandomUser(prefix = 'user', createAt = 0) {
|
||||
const randomId = getRandomId();
|
||||
|
||||
return {
|
||||
email: `${prefix}${randomId}@sample.mattermost.com`,
|
||||
username: `${prefix}${randomId}`,
|
||||
password: 'passwd',
|
||||
first_name: `First${randomId}`,
|
||||
last_name: `Last${randomId}`,
|
||||
nickname: `Nickname${randomId}`,
|
||||
create_at: createAt,
|
||||
};
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateUser', ({
|
||||
prefix = 'user',
|
||||
createAt = 0,
|
||||
bypassTutorial = true,
|
||||
hideOnboarding = true,
|
||||
bypassWhatsNewModal = true,
|
||||
user = null,
|
||||
} = {}) => {
|
||||
const newUser = user || generateRandomUser(prefix, createAt);
|
||||
|
||||
const createUserOption = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: '/api/v4/users',
|
||||
body: newUser,
|
||||
};
|
||||
|
||||
return cy.request(createUserOption).then((userRes) => {
|
||||
expect(userRes.status).to.equal(201);
|
||||
|
||||
const createdUser = userRes.body;
|
||||
|
||||
// hide the onboarding task list by default so it doesn't block the execution of subsequent tests
|
||||
cy.apiSaveSkipStepsPreference(createdUser.id, 'true');
|
||||
cy.apiSaveOnboardingTaskListPreference(createdUser.id, 'onboarding_task_list_open', 'false');
|
||||
cy.apiSaveOnboardingTaskListPreference(createdUser.id, 'onboarding_task_list_show', 'false');
|
||||
|
||||
// hide drafts tour tip so it doesn't block the execution of subsequent tests
|
||||
cy.apiSaveDraftsTourTipPreference(createdUser.id, true);
|
||||
|
||||
if (bypassTutorial) {
|
||||
cy.apiDisableTutorials(createdUser.id);
|
||||
}
|
||||
|
||||
if (hideOnboarding) {
|
||||
cy.apiSaveOnboardingPreference(createdUser.id, 'hide', 'true');
|
||||
cy.apiSaveOnboardingPreference(createdUser.id, 'skip', 'true');
|
||||
}
|
||||
|
||||
if (bypassWhatsNewModal) {
|
||||
cy.apiHideSidebarWhatsNewModalPreference(createdUser.id, 'false');
|
||||
}
|
||||
|
||||
return cy.wrap({user: {...createdUser, password: newUser.password}});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiCreateGuestUser', ({
|
||||
prefix = 'guest',
|
||||
bypassTutorial = true,
|
||||
} = {}) => {
|
||||
return cy.apiCreateUser({prefix, bypassTutorial}).then(({user}) => {
|
||||
cy.apiDemoteUserToGuest(user.id);
|
||||
|
||||
return cy.wrap({guest: user});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Revoke all active sessions for a user
|
||||
* @param {String} userId - ID of user to revoke sessions
|
||||
*/
|
||||
Cypress.Commands.add('apiRevokeUserSessions', (userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/sessions/revoke/all`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({data: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetUsers', (queryParams = {}) => {
|
||||
const queryString = buildQueryString(queryParams);
|
||||
|
||||
return cy.request({
|
||||
method: 'GET',
|
||||
url: `/api/v4/users?${queryString}`,
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({users: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetUsersNotInTeam', ({teamId, page = 0, perPage = 60} = {}) => {
|
||||
return cy.apiGetUsers({not_in_team: teamId, page, per_page: perPage});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiPatchUserRoles', (userId, roleNames = ['system_user']) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/roles`,
|
||||
method: 'PUT',
|
||||
body: {roles: roleNames.join(' ')},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiDeactivateUser', (userId) => {
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'DELETE',
|
||||
url: `/api/v4/users/${userId}`,
|
||||
};
|
||||
|
||||
// # Deactivate a user account
|
||||
return cy.request(options).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiActivateUser', (userId) => {
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/active`,
|
||||
body: {
|
||||
active: true,
|
||||
},
|
||||
};
|
||||
|
||||
// # Activate a user account
|
||||
return cy.request(options).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiDemoteUserToGuest', (userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/demote`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.apiGetUserById(userId).then(({user}) => {
|
||||
return cy.wrap({guest: user});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiPromoteGuestToUser', (userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/promote`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.apiGetUserById(userId);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify a user email via API
|
||||
* @param {String} userId - ID of user of email to verify
|
||||
*/
|
||||
Cypress.Commands.add('apiVerifyUserEmailById', (userId) => {
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: `/api/v4/users/${userId}/email/verify/member`,
|
||||
};
|
||||
|
||||
return cy.request(options).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiActivateUserMFA', (userId, activate, token) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/mfa`,
|
||||
method: 'PUT',
|
||||
body: {
|
||||
activate,
|
||||
code: token,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiResetPassword', (userId, currentPass, newPass) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/password`,
|
||||
body: {
|
||||
current_password: currentPass,
|
||||
new_password: newPass,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGenerateMfaSecret', (userId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: `/api/v4/users/${userId}/mfa/generate`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({code: response.body});
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiAccessToken', (userId, description) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/' + userId + '/tokens',
|
||||
method: 'POST',
|
||||
body: {
|
||||
description,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response.body);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiRevokeAccessToken', (tokenId) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/tokens/revoke',
|
||||
method: 'POST',
|
||||
body: {
|
||||
token_id: tokenId,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiUpdateUserAuth', (userId, authData, password, authService) => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/auth`,
|
||||
body: {
|
||||
auth_data: authData,
|
||||
password,
|
||||
auth_service: authService,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('apiGetTotalUsers', () => {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'GET',
|
||||
url: '/api/v4/users/stats',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response.body.total_users_count);
|
||||
});
|
||||
});
|
||||
|
||||
export {generateRandomUser};
|
||||
892
e2e-tests/cypress/tests/support/api/user.ts
Normal file
892
e2e-tests/cypress/tests/support/api/user.ts
Normal file
|
|
@ -0,0 +1,892 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {UserAccessToken, UserProfile} from '@mattermost/types/users';
|
||||
import authenticator from 'authenticator';
|
||||
import {ChainableT} from 'tests/types';
|
||||
|
||||
import {getRandomId} from '../../utils';
|
||||
import {getAdminAccount} from '../env';
|
||||
|
||||
import {buildQueryString} from './helpers';
|
||||
|
||||
// *****************************************************************************
|
||||
// Users
|
||||
// https://api.mattermost.com/#tag/users
|
||||
// *****************************************************************************
|
||||
|
||||
/**
|
||||
* Login to server via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {string} user.username - username of a user
|
||||
* @param {string} user.password - password of user
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiLogin({username: 'sysadmin', password: 'secret'});
|
||||
*/
|
||||
function apiLogin(user: Partial<Pick<UserProfile, 'username' | 'email' | 'password'>>, requestOptions: Record<string, any> = {}): ChainableT<{user: UserProfile} | {error: any}> {
|
||||
return cy.request<UserProfile | any>({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/login',
|
||||
method: 'POST',
|
||||
body: {login_id: user.username || user.email, password: user.password},
|
||||
...requestOptions,
|
||||
}).then((response) => {
|
||||
if (requestOptions.failOnStatusCode) {
|
||||
expect(response.status).to.equal(200);
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
return cy.wrap<{user: UserProfile}>({
|
||||
user: {
|
||||
...response.body,
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return cy.wrap({error: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiLogin', apiLogin);
|
||||
|
||||
/**
|
||||
* Login to server via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {string} user.username - username of a user
|
||||
* @param {string} user.password - password of user
|
||||
* @param {string} token - MFA token for the session
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiLoginWithMFA({username: 'sysadmin', password: 'secret', token: '123456'});
|
||||
*/
|
||||
function apiLoginWithMFA(user: {username: string; password: string}, token: string): ChainableT<{user: UserProfile}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/login',
|
||||
method: 'POST',
|
||||
body: {login_id: user.username, password: user.password, token},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap<{user: UserProfile}>({
|
||||
user: {
|
||||
...response.body,
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiLoginWithMFA', apiLoginWithMFA);
|
||||
|
||||
/**
|
||||
* Login as admin via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {Object} requestOptions - cypress' request options object, see https://docs.cypress.io/api/commands/request#Arguments
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiAdminLogin();
|
||||
*/
|
||||
function apiAdminLogin(requestOptions?: Record<string, any>): ChainableT<{user: UserProfile}> {
|
||||
const admin = getAdminAccount();
|
||||
|
||||
// First, login with username
|
||||
return cy.apiLogin(admin, requestOptions).then((resp) => {
|
||||
if ((<{error: any}>resp).error) {
|
||||
if ((<{error: any}>resp).error.id === 'mfa.validate_token.authenticate.app_error') {
|
||||
// On fail, try to login via MFA
|
||||
return cy.dbGetUser({username: admin.username}).then(({user: {mfasecret}}) => {
|
||||
const token = authenticator.generateToken(mfasecret);
|
||||
return cy.apiLoginWithMFA(admin, token);
|
||||
});
|
||||
}
|
||||
|
||||
// Or, try to login via email
|
||||
delete admin.username;
|
||||
return cy.apiLogin(admin, requestOptions) as ChainableT<{user: UserProfile}>;
|
||||
}
|
||||
|
||||
return cy.wrap(resp as {user: UserProfile});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiAdminLogin', apiAdminLogin);
|
||||
|
||||
/**
|
||||
* Login as admin via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1login/post
|
||||
* @param {string} token - MFA token for the session
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiAdminLoginWithMFA(token);
|
||||
*/
|
||||
function apiAdminLoginWithMFA(token): ChainableT<{user: UserProfile}> {
|
||||
const admin = getAdminAccount();
|
||||
|
||||
return cy.apiLoginWithMFA(admin, token);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiAdminLoginWithMFA', apiAdminLoginWithMFA);
|
||||
|
||||
/**
|
||||
* Logout a user's active session from server via API.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1logout/post
|
||||
* Clears all cookies especially `MMAUTHTOKEN`, `MMUSERID` and `MMCSRF`.
|
||||
*
|
||||
* @example
|
||||
* cy.apiLogout();
|
||||
*/
|
||||
function apiLogout() {
|
||||
cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/logout',
|
||||
method: 'POST',
|
||||
log: false,
|
||||
});
|
||||
|
||||
// * Verify logged out
|
||||
cy.visit('/login?extra=expired').url().should('include', '/login');
|
||||
|
||||
// # Ensure we clear out these specific cookies
|
||||
['MMAUTHTOKEN', 'MMUSERID', 'MMCSRF'].forEach((cookie) => {
|
||||
cy.clearCookie(cookie);
|
||||
});
|
||||
|
||||
// # Clear remainder of cookies
|
||||
cy.clearCookies();
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiLogout', apiLogout);
|
||||
|
||||
/**
|
||||
* Get current user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}/get
|
||||
* @returns {user: UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetMe().then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
function apiGetMe(): ChainableT<{user: UserProfile}> {
|
||||
return cy.apiGetUserById('me');
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetMe', apiGetMe);
|
||||
|
||||
/**
|
||||
* Get a user by ID.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}/get
|
||||
* @param {String} userId - ID of a user to get profile
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUserById('user-id').then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
function apiGetUserById(userId: string): ChainableT<{user: UserProfile}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/' + userId,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetUserById', apiGetUserById);
|
||||
|
||||
/**
|
||||
* Get a user by email.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1email~1{email}/get
|
||||
* @param {String} email - email address of a user to get profile
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUserByEmail('email').then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
function apiGetUserByEmail(email: string, failOnStatusCode = true): ChainableT<{user: UserProfile}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/email/' + email,
|
||||
failOnStatusCode,
|
||||
}).then((response) => {
|
||||
const {body, status} = response;
|
||||
|
||||
if (failOnStatusCode) {
|
||||
expect(status).to.equal(200);
|
||||
return cy.wrap({user: body});
|
||||
}
|
||||
return cy.wrap({user: status === 200 ? body : null});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetUserByEmail', apiGetUserByEmail);
|
||||
|
||||
/**
|
||||
* Get users by usernames.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1usernames/post
|
||||
* @param {String[]} usernames - list of usernames to get profiles
|
||||
* @returns {UserProfile[]} out.users: list of `UserProfile` objects
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUsersByUsernames().then(({users}) => {
|
||||
* // do something with users
|
||||
* });
|
||||
*/
|
||||
function apiGetUsersByUsernames(usernames: string[] = []): ChainableT<{users: UserProfile[]}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/usernames',
|
||||
method: 'POST',
|
||||
body: usernames,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({users: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetUsersByUsernames', apiGetUsersByUsernames);
|
||||
|
||||
/**
|
||||
* Patch a user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1patch/put
|
||||
* @param {String} userId - ID of user to patch
|
||||
* @param {UserProfile} userData - user profile to be updated
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchUser('user-id', {locale: 'en'}).then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
function apiPatchUser(userId: string, userData: Partial<UserProfile>): ChainableT<{user: UserProfile}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/patch`,
|
||||
body: userData,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
}
|
||||
Cypress.Commands.add('apiPatchUser', apiPatchUser);
|
||||
|
||||
/**
|
||||
* Convenient command to patch a current user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1patch/put
|
||||
* @param {UserProfile} userData - user profile to be updated
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiPatchMe({locale: 'en'}).then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
function apiPatchMe(data: Partial<UserProfile>): ChainableT<{user: UserProfile}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/me/patch',
|
||||
method: 'PUT',
|
||||
body: data,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiPatchMe', apiPatchMe);
|
||||
|
||||
/**
|
||||
* Create a randomly named admin account
|
||||
*
|
||||
* @param {boolean} options.loginAfter - false (default) or true if wants to login as the new admin.
|
||||
* @param {boolean} options.hideAdminTrialModal - true (default) or false if wants to hide Start Enterprise Trial modal.
|
||||
*
|
||||
* @returns {UserProfile} `out.sysadmin` as `UserProfile` object
|
||||
*/
|
||||
function apiCreateCustomAdmin({loginAfter = false, hideAdminTrialModal = true} = {}): ChainableT<{sysadmin: UserProfile}> {
|
||||
const sysadminUser = generateRandomUser('other-admin');
|
||||
|
||||
return cy.apiCreateUser({user: sysadminUser}).then(({user}) => {
|
||||
return cy.apiPatchUserRoles(user.id, ['system_admin', 'system_user']).then(() => {
|
||||
const data = {sysadmin: user};
|
||||
|
||||
cy.apiSaveStartTrialModal(user.id, hideAdminTrialModal.toString());
|
||||
|
||||
if (loginAfter) {
|
||||
return cy.apiLogin(user).then(() => {
|
||||
return cy.wrap(data);
|
||||
});
|
||||
}
|
||||
|
||||
return cy.wrap(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateCustomAdmin', apiCreateCustomAdmin);
|
||||
|
||||
/**
|
||||
* Create an admin account based from the env variables defined in Cypress env.
|
||||
* @returns {UserProfile} `out.sysadmin` as `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateAdmin();
|
||||
*/
|
||||
function apiCreateAdmin() {
|
||||
const {username, password} = getAdminAccount();
|
||||
|
||||
const sysadminUser = {
|
||||
username,
|
||||
password,
|
||||
first_name: 'Kenneth',
|
||||
last_name: 'Moreno',
|
||||
email: 'sysadmin@sample.mattermost.com',
|
||||
};
|
||||
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: '/api/v4/users',
|
||||
body: sysadminUser,
|
||||
};
|
||||
|
||||
// # Create a new user
|
||||
return cy.request(options).then((res) => {
|
||||
expect(res.status).to.equal(201);
|
||||
|
||||
return cy.wrap({sysadmin: {...res.body, password}});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateAdmin', apiCreateAdmin);
|
||||
|
||||
function generateRandomUser(prefix = 'user', createAt = 0): Partial<UserProfile> {
|
||||
const randomId = getRandomId();
|
||||
|
||||
return {
|
||||
email: `${prefix}${randomId}@sample.mattermost.com`,
|
||||
username: `${prefix}${randomId}`,
|
||||
password: 'passwd',
|
||||
first_name: `First${randomId}`,
|
||||
last_name: `Last${randomId}`,
|
||||
nickname: `Nickname${randomId}`,
|
||||
create_at: createAt,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user with an options to set name prefix and be able to bypass tutorial steps.
|
||||
* @param {string} options.user - predefined `user` object instead on random user
|
||||
* @param {string} options.prefix - 'user' (default) or any prefix to easily identify a user
|
||||
* @param {boolean} options.bypassTutorial - true (default) or false for user to go thru tutorial steps
|
||||
* @param {boolean} options.hideOnboarding - true (default) to hide or false to show Onboarding steps
|
||||
* @returns {UserProfile} `out.user` as `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateUser(options);
|
||||
*/
|
||||
interface CreateUserOptions {
|
||||
user: Partial<UserProfile>;
|
||||
prefix?: string;
|
||||
createAt?: number;
|
||||
bypassTutorial?: boolean;
|
||||
hideOnboarding: boolean;
|
||||
bypassWhatsNewModal: boolean;
|
||||
}
|
||||
|
||||
function apiCreateUser({
|
||||
prefix = 'user',
|
||||
createAt = 0,
|
||||
bypassTutorial = true,
|
||||
hideOnboarding = true,
|
||||
bypassWhatsNewModal = true,
|
||||
user = null,
|
||||
}: Partial<CreateUserOptions> = {}): ChainableT<{user: UserProfile}> {
|
||||
const newUser = user || generateRandomUser(prefix, createAt);
|
||||
|
||||
const createUserOption = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: '/api/v4/users',
|
||||
body: newUser,
|
||||
};
|
||||
|
||||
return cy.request(createUserOption).then((userRes) => {
|
||||
expect(userRes.status).to.equal(201);
|
||||
|
||||
const createdUser = userRes.body;
|
||||
|
||||
// hide the onboarding task list by default so it doesn't block the execution of subsequent tests
|
||||
cy.apiSaveSkipStepsPreference(createdUser.id, 'true');
|
||||
cy.apiSaveOnboardingTaskListPreference(createdUser.id, 'onboarding_task_list_open', 'false');
|
||||
cy.apiSaveOnboardingTaskListPreference(createdUser.id, 'onboarding_task_list_show', 'false');
|
||||
|
||||
// hide drafts tour tip so it doesn't block the execution of subsequent tests
|
||||
cy.apiSaveDraftsTourTipPreference(createdUser.id, true);
|
||||
|
||||
if (bypassTutorial) {
|
||||
cy.apiDisableTutorials(createdUser.id);
|
||||
}
|
||||
|
||||
if (hideOnboarding) {
|
||||
cy.apiSaveOnboardingPreference(createdUser.id, 'hide', 'true');
|
||||
cy.apiSaveOnboardingPreference(createdUser.id, 'skip', 'true');
|
||||
}
|
||||
|
||||
if (bypassWhatsNewModal) {
|
||||
cy.apiHideSidebarWhatsNewModalPreference(createdUser.id, 'false');
|
||||
}
|
||||
|
||||
return cy.wrap({user: {...createdUser, password: newUser.password}});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateUser', apiCreateUser);
|
||||
|
||||
/**
|
||||
* Create a new guest user with an options to set name prefix and be able to bypass tutorial steps.
|
||||
* @param {string} options.prefix - 'guest' (default) or any prefix to easily identify a guest
|
||||
* @param {boolean} options.bypassTutorial - true (default) or false for guest to go thru tutorial steps
|
||||
* @param {boolean} options.showOnboarding - false (default) to hide or true to show Onboarding steps
|
||||
* @returns {UserProfile} `out.guest` as `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiCreateGuestUser(options);
|
||||
*/
|
||||
function apiCreateGuestUser({
|
||||
prefix = 'guest',
|
||||
bypassTutorial = true,
|
||||
}: Partial<CreateUserOptions>): ChainableT<{guest: UserProfile}> {
|
||||
return cy.apiCreateUser({prefix, bypassTutorial}).then(({user}) => {
|
||||
cy.apiDemoteUserToGuest(user.id);
|
||||
|
||||
return cy.wrap({guest: user});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiCreateGuestUser', apiCreateGuestUser);
|
||||
|
||||
/**
|
||||
* Revoke all active sessions for a user
|
||||
* @param {String} userId - ID of user to revoke sessions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Revoke all active sessions for a user.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1sessions~1revoke~1all/post
|
||||
* @param {String} userId - ID of a user
|
||||
* @returns {Object} `out.data` as response status
|
||||
*
|
||||
* @example
|
||||
* cy.apiRevokeUserSessions('user-id');
|
||||
*/
|
||||
function apiRevokeUserSessions(userId: string): ChainableT<Record<string, any>> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/sessions/revoke/all`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({data: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiRevokeUserSessions', apiRevokeUserSessions);
|
||||
|
||||
/**
|
||||
* Get list of users based on query parameters
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users/get
|
||||
* @param {String} queryParams - see link on available query parameters
|
||||
* @returns {UserProfile[]} `out.users` as `UserProfile[]` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUsers().then(({users}) => {
|
||||
* // do something with users
|
||||
* });
|
||||
*/
|
||||
function apiGetUsers(queryParams: Record<string, any>): ChainableT<{users: UserProfile[]}> {
|
||||
const queryString = buildQueryString(queryParams);
|
||||
|
||||
return cy.request({
|
||||
method: 'GET',
|
||||
url: `/api/v4/users?${queryString}`,
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({users: response.body as UserProfile[]});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetUsers', apiGetUsers);
|
||||
|
||||
/**
|
||||
* Get list of users that are not team members.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users/get
|
||||
* @param {String} queryParams.teamId - Team ID
|
||||
* @param {String} queryParams.page - Page to select, 0 (default)
|
||||
* @param {String} queryParams.perPage - The number of users per page, 60 (default)
|
||||
* @returns {UserProfile[]} `out.users` as `UserProfile[]` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetUsersNotInTeam({teamId: 'team-id'}).then(({users}) => {
|
||||
* // do something with users
|
||||
* });
|
||||
*/
|
||||
function apiGetUsersNotInTeam({teamId, page = 0, perPage = 60}: Record<string, any>): ChainableT<{users: UserProfile[]}> {
|
||||
return cy.apiGetUsers({not_in_team: teamId, page, per_page: perPage});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetUsersNotInTeam', apiGetUsersNotInTeam);
|
||||
|
||||
/**
|
||||
* patch user roles
|
||||
* @param {String} userId - ID of user to patch
|
||||
* @param {String[]} roleNames - The user roles
|
||||
* @returns {any} - the result of patching the user roles
|
||||
* @example
|
||||
* cy.apiPatchUserRoles('user-id', ['system_user']);
|
||||
*/
|
||||
function apiPatchUserRoles(userId: string, roleNames: string[] = ['system_user']): any {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/roles`,
|
||||
method: 'PUT',
|
||||
body: {roles: roleNames.join(' ')},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiPatchUserRoles', apiPatchUserRoles);
|
||||
|
||||
/**
|
||||
* Deactivate a user account.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}/delete
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiDeactivateUser('user-id');
|
||||
*/
|
||||
function apiDeactivateUser(userId: string): ChainableT<any> {
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'DELETE',
|
||||
url: `/api/v4/users/${userId}`,
|
||||
};
|
||||
|
||||
// # Deactivate a user account
|
||||
return cy.request(options).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiDeactivateUser', apiDeactivateUser);
|
||||
|
||||
/**
|
||||
* Reactivate a user account.
|
||||
* @param {string} userId - User ID
|
||||
* @returns {Response} response: Cypress-chainable response which should have successful HTTP status of 200 OK to continue or pass.
|
||||
*
|
||||
* @example
|
||||
* cy.apiActivateUser('user-id');
|
||||
*/
|
||||
function apiActivateUser(userId: string): ChainableT<any> {
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/active`,
|
||||
body: {
|
||||
active: true,
|
||||
},
|
||||
};
|
||||
|
||||
// # Activate a user account
|
||||
return cy.request(options).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiActivateUser', apiActivateUser);
|
||||
|
||||
/**
|
||||
* Convert a regular user into a guest. This will convert the user into a guest for the whole system while retaining their existing team and channel memberships.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1demote/post
|
||||
* @param {string} userId - User ID
|
||||
* @returns {UserProfile} out.guest: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiDemoteUserToGuest('user-id');
|
||||
*/
|
||||
function apiDemoteUserToGuest(userId: string): ChainableT<{guest: UserProfile}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/demote`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.apiGetUserById(userId).then(({user}) => {
|
||||
return cy.wrap({guest: user});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiDemoteUserToGuest', apiDemoteUserToGuest);
|
||||
|
||||
/**
|
||||
* Convert a guest into a regular user. This will convert the guest into a user for the whole system while retaining any team and channel memberships and automatically joining them to the default channels.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1promote/post
|
||||
* @param {string} userId - User ID
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiPromoteGuestToUser('user-id');
|
||||
*/
|
||||
function apiPromoteGuestToUser(userId: string): ChainableT<{user: UserProfile}> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/promote`,
|
||||
method: 'POST',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.apiGetUserById(userId);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiPromoteGuestToUser', apiPromoteGuestToUser);
|
||||
|
||||
/**
|
||||
* Verifies a user's email via userId without having to go to the user's email inbox.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1email~1verify~1member/post
|
||||
* @param {string} userId - User ID
|
||||
* @returns {UserProfile} out.user: `UserProfile` object
|
||||
*
|
||||
* @example
|
||||
* cy.apiVerifyUserEmailById('user-id').then(({user}) => {
|
||||
* // do something with user
|
||||
* });
|
||||
*/
|
||||
function apiVerifyUserEmailById(userId: string): ChainableT<{user: UserProfile}> {
|
||||
const options = {
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: `/api/v4/users/${userId}/email/verify/member`,
|
||||
};
|
||||
|
||||
return cy.request(options).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiVerifyUserEmailById', apiVerifyUserEmailById);
|
||||
|
||||
/**
|
||||
* Update a user MFA.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1mfa/put
|
||||
* @param {String} userId - ID of user to patch
|
||||
* @param {boolean} activate - Whether MFA is going to be enabled or disabled
|
||||
* @param {string} token - MFA token/code
|
||||
* @example
|
||||
* cy.apiActivateUserMFA('user-id', activate: false);
|
||||
*/
|
||||
function apiActivateUserMFA(userId: string, activate: boolean, token: string): ChainableT<any> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: `/api/v4/users/${userId}/mfa`,
|
||||
method: 'PUT',
|
||||
body: {
|
||||
activate,
|
||||
code: token,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiActivateUserMFA', apiActivateUserMFA);
|
||||
|
||||
function apiResetPassword(userId, currentPass, newPass) {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/password`,
|
||||
body: {
|
||||
current_password: currentPass,
|
||||
new_password: newPass,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({user: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiResetPassword', apiResetPassword);
|
||||
|
||||
function apiGenerateMfaSecret(userId) {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'POST',
|
||||
url: `/api/v4/users/${userId}/mfa/generate`,
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap({code: response.body});
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGenerateMfaSecret', apiGenerateMfaSecret);
|
||||
|
||||
/**
|
||||
* Create a user access token
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1tokens/post
|
||||
* @param {String} userId - ID of user for whom to generate token
|
||||
* @param {String} description - The description of the token usage
|
||||
* @example
|
||||
* cy.apiAccessToken('user-id', 'token for cypress tests');
|
||||
*/
|
||||
function apiAccessToken(userId: string, description: string): ChainableT<UserAccessToken> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/' + userId + '/tokens',
|
||||
method: 'POST',
|
||||
body: {
|
||||
description,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response.body as UserAccessToken);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiAccessToken', apiAccessToken);
|
||||
|
||||
/**
|
||||
* Revoke a user access token
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1tokens~1revoke/post
|
||||
* @param {String} tokenId - The id of the token to revoke
|
||||
* @example
|
||||
* cy.apiRevokeAccessToken('token-id')
|
||||
*/
|
||||
function apiRevokeAccessToken(tokenId: string): ChainableT<any> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
url: '/api/v4/users/tokens/revoke',
|
||||
method: 'POST',
|
||||
body: {
|
||||
token_id: tokenId,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiRevokeAccessToken', apiRevokeAccessToken);
|
||||
|
||||
/**
|
||||
* Update a user auth method.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1{user_id}~1mfa/put
|
||||
* @param {String} userId - ID of user to patch
|
||||
* @param {String} authData
|
||||
* @param {String} password
|
||||
* @param {String} authService
|
||||
* @example
|
||||
* cy.apiUpdateUserAuth('user-id', 'auth-data', 'password', 'auth-service');
|
||||
*/
|
||||
function apiUpdateUserAuth(userId: string, authData: string, password: string, authService: string): ChainableT<any> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'PUT',
|
||||
url: `/api/v4/users/${userId}/auth`,
|
||||
body: {
|
||||
auth_data: authData,
|
||||
password,
|
||||
auth_service: authService,
|
||||
},
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiUpdateUserAuth', apiUpdateUserAuth);
|
||||
|
||||
/**
|
||||
* Get total count of users in the system
|
||||
* See https://api.mattermost.com/#operation/GetTotalUsersStats
|
||||
*
|
||||
* @returns {number} - total count of all users
|
||||
*
|
||||
* @example
|
||||
* cy.apiGetTotalUsers().then(() => {
|
||||
* // do something with total users
|
||||
* });
|
||||
*/
|
||||
function apiGetTotalUsers(): ChainableT<number> {
|
||||
return cy.request({
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
method: 'GET',
|
||||
url: '/api/v4/users/stats',
|
||||
}).then((response) => {
|
||||
expect(response.status).to.equal(200);
|
||||
return cy.wrap(response.body.total_users_count as number);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('apiGetTotalUsers', apiGetTotalUsers);
|
||||
|
||||
export {generateRandomUser};
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
apiLogin: typeof apiLogin;
|
||||
apiLoginWithMFA: typeof apiLoginWithMFA;
|
||||
apiAdminLogin: typeof apiAdminLogin;
|
||||
apiAdminLoginWithMFA: typeof apiAdminLoginWithMFA;
|
||||
apiLogout(): ChainableT<void>;
|
||||
apiGetMe: typeof apiGetMe;
|
||||
apiGetUserById: typeof apiGetUserById;
|
||||
apiGetUserByEmail: typeof apiGetUserByEmail;
|
||||
apiGetUsersByUsernames: typeof apiGetUsersByUsernames;
|
||||
apiPatchUser: typeof apiPatchUser;
|
||||
apiPatchMe: typeof apiPatchMe;
|
||||
apiCreateCustomAdmin: typeof apiCreateCustomAdmin;
|
||||
apiCreateAdmin: typeof apiCreateAdmin;
|
||||
apiCreateUser: typeof apiCreateUser;
|
||||
apiCreateGuestUser: typeof apiCreateGuestUser;
|
||||
apiRevokeUserSessions: typeof apiRevokeUserSessions;
|
||||
apiGetUsers: typeof apiGetUsers;
|
||||
apiGetUsersNotInTeam: typeof apiGetUsersNotInTeam;
|
||||
apiPatchUserRoles: typeof apiPatchUserRoles;
|
||||
apiDeactivateUser: typeof apiDeactivateUser;
|
||||
apiActivateUser: typeof apiActivateUser;
|
||||
apiDemoteUserToGuest: typeof apiDemoteUserToGuest;
|
||||
apiPromoteGuestToUser: typeof apiPromoteGuestToUser;
|
||||
apiVerifyUserEmailById: typeof apiVerifyUserEmailById;
|
||||
apiActivateUserMFA: typeof apiActivateUserMFA;
|
||||
apiResetPassword: typeof apiResetPassword;
|
||||
apiGenerateMfaSecret: typeof apiGenerateMfaSecret;
|
||||
apiAccessToken: typeof apiAccessToken;
|
||||
apiRevokeAccessToken: typeof apiRevokeAccessToken;
|
||||
apiUpdateUserAuth: typeof apiUpdateUserAuth;
|
||||
apiGetTotalUsers: typeof apiGetTotalUsers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ interface GetUserParam {
|
|||
username: string;
|
||||
}
|
||||
interface GetUserResult {
|
||||
user: Cypress.UserProfile;
|
||||
user: Cypress.UserProfile & {mfasecret: string};
|
||||
}
|
||||
function dbGetUser(params: GetUserParam): ChainableT<GetUserResult> {
|
||||
return cy.task('dbGetUser', {dbConfig, params}).then(({user, errorMessage, error}) => {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,16 @@ interface PostMessageArg {
|
|||
createAt?: number;
|
||||
}
|
||||
|
||||
interface PostMessageRequest {
|
||||
token: string;
|
||||
message: string;
|
||||
props?;
|
||||
channelId: string;
|
||||
rootId?;
|
||||
createAt?;
|
||||
failOnStatus?: boolean;
|
||||
}
|
||||
|
||||
function postMessageAs(arg: PostMessageArg): ChainableT<PostMessageResp> {
|
||||
const {sender, message, channelId, rootId, createAt} = arg;
|
||||
const baseUrl = Cypress.config('baseUrl');
|
||||
|
|
@ -149,7 +159,7 @@ Cypress.Commands.add('externalRequest', externalRequest);
|
|||
* @param {Object} channelId - where a post will be posted
|
||||
*/
|
||||
|
||||
function postBotMessage({token, message, props, channelId, rootId, createAt, failOnStatus = true}): ChainableT<PostMessageResp> {
|
||||
function postBotMessage({token, message, props, channelId, rootId, createAt, failOnStatus = true}: PostMessageRequest): ChainableT<PostMessageResp> {
|
||||
const baseUrl = Cypress.config('baseUrl');
|
||||
|
||||
return cy.task('postBotMessage', {token, message, props, channelId, rootId, createAt, baseUrl}).then(({status, data}) => {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ declare namespace Cypress {
|
|||
* @example
|
||||
* cy.uiOpenProductMenu().click();
|
||||
*/
|
||||
uiOpenProductMenu(item: string): Chainable;
|
||||
uiOpenProductMenu(item: string = ''): Chainable;
|
||||
|
||||
/**
|
||||
* Get set status button
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ declare global {
|
|||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
uiSearchPosts(searchTerm: string): ChainableT;
|
||||
uiJumpToSearchResult(postId: string): ChainableT;
|
||||
uiSearchPosts(searchTerm: string): ChainableT<void>;
|
||||
uiJumpToSearchResult(postId: string): ChainableT<void>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue