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

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

@@ -0,0 +1,558 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// ***************************************************************
// Stage: @prod
// Group: @playbooks
import {switchToChannel} from '../../../channels/mark_as_unread/helpers';
describe('channels > slash command > owner', () => {
let testTeam;
let testUser;
let testUser2;
let testPlaybook;
let playbookRunName;
let playbookRunChannelName;
before(() => {
cy.apiInitSetup().then(({team, user}) => {
testTeam = team;
testUser = user;
cy.apiCreateUser().then(({user: user2}) => {
testUser2 = user2;
cy.apiAddUserToTeam(testTeam.id, testUser2.id);
});
cy.apiLogin(testUser);
cy.apiCreatePlaybook({
teamId: testTeam.id,
title: 'Playbook',
checklists: [
{
title: 'Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
memberIDs: [testUser.id],
}).then((playbook) => {
testPlaybook = playbook;
const now = Date.now();
playbookRunName = `Playbook Run (${now})`;
playbookRunChannelName = `playbook-run-${now}`;
cy.apiRunPlaybook({
teamId: testTeam.id,
playbookId: testPlaybook.id,
playbookRunName,
ownerUserId: testUser.id,
});
});
});
});
beforeEach(() => {
// # Login as testUser
cy.apiLogin(testUser);
// # Size the viewport to show the RHS without covering posts.
cy.viewport('macbook-13');
// # Navigate directly to the application and the playbook run channel
cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`);
});
describe('single run channel', () => {
it('check', () => {
// # Type a command
cy.findByTestId('post_textbox').clear().type('/playbook check ');
// * Verify suggestions number: a single run with 4 tasks + 1 title
cy.get('.slash-command').should('have.length', 5);
// # Clear input
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook check 1 1');
// * Verify the task is checked
cy.get('[data-rbd-droppable-id="1"]').find('.checkbox').eq(1).should('be.checked');
});
it('check add', () => {
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkadd 1 new-task');
// * Verify the task was added
cy.get('[data-rbd-droppable-id="1"]').contains('new-task');
});
it('check remove', () => {
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkremove 1 1');
// * Verify the task was added
cy.get('[data-rbd-droppable-id="1"]').contains('Step 2').should('not.exist');
});
it('owner', () => {
// # Run a slash command
cy.uiPostMessageQuickly('/playbook owner');
// * Verify the message.
cy.verifyEphemeralMessage(`@${testUser.username} is the current owner for this playbook run.`);
// # Run a slash command
cy.uiPostMessageQuickly(`/playbook owner @${testUser2.username}`);
// * Verify that the owner was set.
cy.uiPostMessageQuickly('/playbook owner');
cy.verifyEphemeralMessage(`@${testUser2.username} is the current owner for this playbook run.`);
});
it('timeline', () => {
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly('/playbook timeline');
// * Verify the message.
cy.verifyEphemeralMessage(`Timeline for ${playbookRunName}`);
});
it('finish', () => {
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook finish');
// * Verify confirm modal is visible.
cy.get('#interactiveDialogModalLabel').should('exist');
// # Confirm finish
cy.get('#interactiveDialogSubmit').click();
// * Verify that the run is finished.
cy.get('#rhsContainer').findByTestId('badge').contains('Finished');
});
});
describe('multiple runs in the channel', () => {
let playbookRuns;
let testPrivatePlaybook;
let testPublicPlaybook;
let testPublicChannel;
let channelName;
before(() => {
// # Login as testUser
cy.apiLogin(testUser);
// # Create private playbook, channel mode set to link existing channel
cy.apiCreatePlaybook({
makePublic: false,
createPublicPlaybookRun: false,
teamId: testTeam.id,
title: 'Playbook private',
checklists: [
{
title: 'Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
memberIDs: [testUser.id],
channelMode: 'link_existing_channel',
}).then((playbook) => {
testPrivatePlaybook = playbook;
});
// # Create public playbook, channel mode set to link existing channel
cy.apiCreatePlaybook({
makePublic: true,
teamId: testTeam.id,
title: 'Playbook public',
checklists: [
{
title: 'Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
memberIDs: [testUser.id],
channelMode: 'link_existing_channel',
}).then((playbook) => {
testPublicPlaybook = playbook;
});
});
beforeEach(() => {
playbookRuns = [];
const now = Date.now();
channelName = 'public-channel-' + now;
// # Create channel for runs
cy.apiCreateChannel(
testTeam.id,
channelName,
'public channel',
'O',
).then(({channel: publicChannel}) => {
testPublicChannel = publicChannel;
cy.apiRunPlaybook({
teamId: testTeam.id,
playbookId: testPrivatePlaybook.id,
playbookRunName: 'run write access ' + now,
ownerUserId: testUser.id,
channelId: testPublicChannel.id,
}).then((playbookRun) => {
cy.apiAddUsersToRun(playbookRun.id, [testUser2.id]);// add test user to participants list
playbookRuns.push(playbookRun);
cy.apiRunPlaybook({
teamId: testTeam.id,
playbookId: testPublicPlaybook.id,
playbookRunName: 'run view access' + now,
ownerUserId: testUser.id,
channelId: testPublicChannel.id,
}).then((playbookRun2) => {
playbookRuns.push(playbookRun2);
cy.apiRunPlaybook({
teamId: testTeam.id,
playbookId: testPrivatePlaybook.id,
playbookRunName: 'run no access' + now,
ownerUserId: testUser.id,
channelId: testPublicChannel.id,
}).then((playbookRun3) => {
playbookRuns.push(playbookRun3);
// # Add testUser2 to the channel
cy.apiAddUserToChannel(testPublicChannel.id, testUser2.id);
// # Login as testUser2
cy.apiLogin(testUser2);
// # Navigate directly to the playbook run channel
cy.visit(`/${testTeam.name}/channels/${testPublicChannel.name}`);
switchToChannel(testPublicChannel);
});
});
});
});
});
it('check', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook check 1 1');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Command expects three arguments: the run number, the checklist number and the item number.');
// # Run a slash command wrong run number
cy.uiPostMessageQuickly('/playbook check 2 1 1');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly('/playbook check 0 1 1');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Become a participant to interact with this run');
// # Type a command
cy.findByTestId('post_textbox').clear().type('/playbook check ');
// * Verify suggestions number: 2 runs * 4 tasks + 1 title
cy.get('.slash-command').should('have.length', 9);
// # Clear input
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook check 1 1 1');
cy.get('#rhsContainer').within(() => {
// * Verify number of runs
cy.get('[data-testid="run-list-card"]').should('have.length', 2);
// # Open run details view
cy.findByText(playbookRuns[0].name).click({force: true});
});
// * Verify the task is checked
cy.get('[data-rbd-droppable-id="1"]').find('.checkbox').eq(1).should('be.checked');
});
it('check add', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook checkadd 1');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Command expects two arguments: the run number and the checklist number.');
// # Run a slash command wrong run number
cy.uiPostMessageQuickly('/playbook checkadd 2 1 1');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly('/playbook checkadd 0 1 new-task');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Become a participant to interact with this run');
// # Type a command
cy.findByTestId('post_textbox').clear().type('/playbook checkadd ');
// * Verify suggestions number: 2 runs * 2 checklists + 1 title
cy.get('.slash-command').should('have.length', 5);
// # Clear input
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkadd 1 1 new-task');
cy.get('#rhsContainer').within(() => {
// * Verify number of runs
cy.get('[data-testid="run-list-card"]').should('have.length', 2);
// # Open run details view
cy.findByText(playbookRuns[0].name).click({force: true});
});
// * Verify the task was added
cy.get('[data-rbd-droppable-id="1"]').contains('new-task');
});
it('check remove', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook checkremove 1 1');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Command expects three arguments: the run number, the checklist number and the item number.');
// # Run a slash command wrong run number
cy.uiPostMessageQuickly('/playbook checkremove 2 0 1');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly('/playbook checkremove 0 1 0');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Become a participant to interact with this run');
// # Type a command
cy.findByTestId('post_textbox').clear().type('/playbook checkremove ');
// * Verify suggestions number: 2 runs * 4 tasks + 1 title
cy.get('.slash-command').should('have.length', 9);
// # Clear input
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkremove 1 1 1');
cy.get('#rhsContainer').within(() => {
// * Verify number of runs
cy.get('[data-testid="run-list-card"]').should('have.length', 2);
// # Open run details view
cy.findByText(playbookRuns[0].name).click({force: true});
});
// * Verify the task was added
cy.get('[data-rbd-droppable-id="1"]').contains('Step 2').should('not.exist');
});
it('owner', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook owner');
// * Verify the expected error message.
cy.verifyEphemeralMessage('/playbook owner expects at most one argument.');
// # Run a slash command wrong run number
cy.uiPostMessageQuickly('/playbook owner 2');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly('/playbook owner 0');
// * Verify the message.
cy.verifyEphemeralMessage(`@${testUser.username} is the current owner for this playbook run.`);
// # Type a command
cy.findByTestId('post_textbox').clear().type('/playbook owner ');
// * Verify suggestions number: 2 runs + 1 title
cy.get('.slash-command').should('have.length', 3);
// # Clear input
cy.findByTestId('post_textbox').clear();
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly(`/playbook owner 0 @${testUser2.username}`);
// * Verify the expected error message.
cy.verifyEphemeralMessage('Become a participant to interact with this run');
// # Run a slash command on a run with write access
cy.uiPostMessageQuickly(`/playbook owner 1 @${testUser2.username}`);
// * Verify that the owner was set.
cy.uiPostMessageQuickly('/playbook owner 1');
cy.verifyEphemeralMessage(`@${testUser2.username} is the current owner for this playbook run.`);
});
it('finish', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook finish');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Command expects one argument: the run number.');
// # Run a slash command wrong run number
cy.uiPostMessageQuickly('/playbook finish 2');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly('/playbook finish 0');
// * Verify the message.
cy.verifyEphemeralMessage(`userID ${testUser2.id} is not an admin or channel member`);
// # Type a command
cy.findByTestId('post_textbox').clear().type('/playbook finish ');
// * Verify suggestions number: 2 runs + 1 title
cy.get('.slash-command').should('have.length', 3);
// # Clear input
cy.findByTestId('post_textbox').clear();
cy.get('#rhsContainer').within(() => {
// * Verify number of runs
cy.get('[data-testid="run-list-card"]').should('have.length', 2);
// # Open run details view
cy.findByText(playbookRuns[0].name).click({force: true});
});
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook finish 1');
// * Verify confirm modal is visible.
cy.get('#interactiveDialogModalLabel').should('exist');
// # Confirm finish
cy.get('#interactiveDialogSubmit').click();
// * Verify that the run is finished.
cy.get('#rhsContainer').findByTestId('badge').contains('Finished');
});
it('timeline', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook timeline');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Command expects one argument: the run number.');
// # Run a slash command wrong run number
cy.uiPostMessageQuickly('/playbook timeline 2');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly('/playbook timeline 0');
// * Verify the message.
cy.verifyEphemeralMessage(`Timeline for ${playbookRuns[1].name}`);
});
it('update', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook update');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Command expects one argument: the run number.');
// # Run a slash command wrong run number
cy.uiPostMessageQuickly('/playbook update 2');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
// # Type a command
cy.findByTestId('post_textbox').clear().type('/playbook update ');
// * Verify suggestions number: 2 runs + 1 title
cy.get('.slash-command').should('have.length', 3);
// # Clear input
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook update 1');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
// # Enter valid data
cy.findByTestId('update_run_status_textbox').type('valid update');
// # Submit the dialog.
cy.get('button.confirm').click();
});
// * Verify that the Post update dialog has gone.
cy.getStatusUpdateDialog().should('not.exist');
// * Verify that the status update was posted.
cy.getLastPost().within(() => {
cy.findByText('posted an update for').should('exist');
});
});
});
});

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

@@ -0,0 +1,120 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// ***************************************************************
// Stage: @prod
// Group: @playbooks
describe('channels > slash command > info', () => {
let testTeam;
let testUser;
let testUser2;
let testPlaybook;
let testPlaybookRun;
before(() => {
cy.apiInitSetup().then(({team, user}) => {
testTeam = team;
testUser = user;
cy.apiCreateUser().then(({user: user2}) => {
testUser2 = user2;
cy.apiAddUserToTeam(testTeam.id, testUser2.id);
});
cy.apiLogin(testUser);
cy.apiCreatePlaybook({
teamId: testTeam.id,
title: 'Playbook',
checklists: [
{
title: 'Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
memberIDs: [testUser.id],
}).then((playbook) => {
testPlaybook = playbook;
cy.apiRunPlaybook({
teamId: testTeam.id,
playbookId: testPlaybook.id,
playbookRunName: 'Playbook Run',
ownerUserId: testUser.id,
}).then((playbookRun) => {
testPlaybookRun = playbookRun;
});
});
});
});
beforeEach(() => {
// # Login as testUser
cy.apiLogin(testUser);
// # Size the viewport to show the RHS without covering posts.
cy.viewport('macbook-13');
// # Reset the owner back to testUser as necessary.
cy.apiChangePlaybookRunOwner(testPlaybookRun.id, testUser.id);
});
describe('/playbook info', () => {
it('should show an error when not in a playbook run channel', () => {
// # Navigate to a non-playbook run channel.
cy.visit(`/${testTeam.name}/channels/town-square`);
// # Run a slash command to show the playbook run's info.
cy.uiPostMessageQuickly('/playbook info');
// * Verify the expected error message.
cy.verifyEphemeralMessage('This command only works when run from a playbook run channel.');
});
it('should open the RHS when it is not open', () => {
// # Navigate directly to the application and the playbook run channel.
cy.visit(`/${testTeam.name}/channels/playbook-run`);
// # Close the RHS, which is opened by default when navigating to a playbook run channel.
cy.get('#searchResultsCloseButton').click();
// * Verify that the RHS is indeed closed.
cy.get('#rhsContainer').should('not.exist');
// # Run a slash command to show the playbook run's info.
cy.uiPostMessageQuickly('/playbook info');
// * Verify that the RHS is now open.
cy.get('#rhsContainer').should('be.visible');
});
it('should show an ephemeral post when the RHS is already open', () => {
// # Navigate directly to the application and the playbook run channel.
cy.visit(`/${testTeam.name}/channels/playbook-run`);
// * Verify that the RHS is open.
cy.get('#rhsContainer').should('be.visible');
// # Run a slash command to show the playbook run's info.
cy.uiPostMessageQuickly('/playbook info');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Your playbook run details are already open in the right hand side of the channel.');
});
});
});

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

@@ -0,0 +1,222 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// ***************************************************************
// Stage: @prod
// Group: @playbooks
describe('channels > slash command > owner', () => {
let testTeam;
let testUser;
let testUser2;
let testPlaybook;
let testPlaybookRun;
before(() => {
cy.apiInitSetup().then(({team, user}) => {
testTeam = team;
testUser = user;
cy.apiCreateUser().then(({user: user2}) => {
testUser2 = user2;
cy.apiAddUserToTeam(testTeam.id, testUser2.id);
});
cy.apiLogin(testUser);
cy.apiCreatePlaybook({
teamId: testTeam.id,
title: 'Playbook',
checklists: [
{
title: 'Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
memberIDs: [testUser.id],
}).then((playbook) => {
testPlaybook = playbook;
cy.apiRunPlaybook({
teamId: testTeam.id,
playbookId: testPlaybook.id,
playbookRunName: 'Playbook Run',
ownerUserId: testUser.id,
}).then((playbookRun) => {
testPlaybookRun = playbookRun;
});
});
});
});
beforeEach(() => {
// # Login as testUser
cy.apiLogin(testUser);
// # Size the viewport to show the RHS without covering posts.
cy.viewport('macbook-13');
// # Reset the owner back to testUser as necessary.
cy.apiChangePlaybookRunOwner(testPlaybookRun.id, testUser.id);
});
describe('/playbook owner', () => {
it('should show an error when not in a playbook run channel', () => {
// # Navigate to a non-playbook run channel
cy.visit(`/${testTeam.name}/channels/town-square`);
// # Run a slash command to show the current owner
cy.uiPostMessageQuickly('/playbook owner');
// * Verify the expected error message.
cy.verifyEphemeralMessage('This command only works when run from a playbook run channel.');
});
it('should show the current owner', () => {
// # Navigate directly to the application and the playbook run channel
cy.visit(`/${testTeam.name}/channels/playbook-run`);
// # Run a slash command to show the current owner
cy.uiPostMessageQuickly('/playbook owner');
// * Verify the expected owner.
cy.verifyEphemeralMessage(`@${testUser.username} is the current owner for this playbook run.`);
});
});
describe('/playbook owner @username', () => {
it('should show an error when not in a playbook run channel', () => {
// # Navigate to a non-playbook run channel
cy.visit(`/${testTeam.name}/channels/town-square`);
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly(`/playbook owner ${testUser2.username}`);
// * Verify the expected error message.
cy.verifyEphemeralMessage('This command only works when run from a playbook run channel.');
});
describe('should show an error when the user is not found', () => {
beforeEach(() => {
// # Navigate directly to the application and the playbook run channel
cy.visit(`/${testTeam.name}/channels/playbook-run`);
});
it('when the username has no @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly('/playbook owner unknown');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Unable to find user @unknown');
});
it('when the username has an @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly('/playbook owner @unknown');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Unable to find user @unknown');
});
});
describe('should not show an error when the user is not in the channel', () => {
beforeEach(() => {
// # Navigate directly to the application and the playbook run channel
cy.visit(`/${testTeam.name}/channels/playbook-run`);
// # Ensure the user3 is not part of the channel.
cy.uiPostMessageQuickly(`/kick ${testUser2.username}`);
});
it('when the username has no @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly(`/playbook owner ${testUser2.username}`);
// * Verify the owner has changed.
cy.findByTestId('owner-profile-selector').contains(testUser2.username);
});
it('when the username has an @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly(`/playbook owner @${testUser2.username}`);
// * Verify the owner has changed.
cy.findByTestId('owner-profile-selector').contains(testUser2.username);
});
});
describe('should show a message when the user is already the owner', () => {
beforeEach(() => {
// # Navigate directly to the application and the playbook run channel
cy.visit(`/${testTeam.name}/channels/playbook-run`);
});
it('when the username has no @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly(`/playbook owner ${testUser.username}`);
// * Verify the expected error message.
cy.verifyEphemeralMessage(`User @${testUser.username} is already owner of this playbook run.`);
});
it('when the username has an @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly(`/playbook owner @${testUser.username}`);
// * Verify the expected error message.
cy.verifyEphemeralMessage(`User @${testUser.username} is already owner of this playbook run.`);
});
});
describe('should change the current owner', () => {
beforeEach(() => {
// # Navigate directly to the application and the playbook run channel
cy.visit(`/${testTeam.name}/channels/playbook-run`);
// # Ensure the testUser2 is part of the channel.
cy.uiPostMessageQuickly(`/invite ${testUser2.username}`);
});
it('when the username has no @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly(`/playbook owner ${testUser2.username}`);
// # Verify the owner has changed.
cy.findByTestId('owner-profile-selector').contains(testUser2.username);
});
it('when the username has an @-prefix', () => {
// # Run a slash command to change the current owner
cy.uiPostMessageQuickly(`/playbook owner @${testUser2.username}`);
// # Verify the owner has changed.
cy.findByTestId('owner-profile-selector').contains(testUser2.username);
});
});
it('should show an error when specifying more than one username', () => {
// # Navigate directly to the application and the playbook run channel
cy.visit(`/${testTeam.name}/channels/playbook-run`);
// # Run a slash command with too many parameters
cy.uiPostMessageQuickly(`/playbook owner ${testUser.username} ${testUser2.username}`);
// * Verify the expected error message.
cy.verifyEphemeralMessage('/playbook owner expects at most one argument.');
});
});
});

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

@@ -0,0 +1,255 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// ***************************************************************
// Stage: @prod
// Group: @playbooks
describe('channels > slash command > test', () => {
let testTeam;
let testUser;
let testUser2;
let testPlaybook;
let testPlaybookRun;
before(() => {
cy.apiInitSetup().then(({team, user}) => {
testTeam = team;
testUser = user;
cy.apiCreateUser().then(({user: user2}) => {
testUser2 = user2;
cy.apiAddUserToTeam(testTeam.id, testUser2.id);
});
cy.apiLogin(testUser);
cy.apiCreatePlaybook({
teamId: testTeam.id,
title: 'Playbook',
checklists: [
{
title: 'Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
memberIDs: [testUser.id],
}).then((playbook) => {
testPlaybook = playbook;
cy.apiRunPlaybook({
teamId: testTeam.id,
playbookId: testPlaybook.id,
playbookRunName: 'Playbook Run',
ownerUserId: testUser.id,
}).then((playbookRun) => {
testPlaybookRun = playbookRun;
});
});
});
});
beforeEach(() => {
// # Login as testUser
cy.apiLogin(testUser);
// # Size the viewport to show the RHS without covering posts.
cy.viewport('macbook-13');
// # Reset the owner back to testUser as necessary.
cy.apiChangePlaybookRunOwner(testPlaybookRun.id, testUser.id);
});
describe('as a regular user', () => {
before(() => {
// # Login as sysadmin.
cy.apiAdminLogin();
// # Set EnableTesting to true.
cy.apiUpdateConfig({
ServiceSettings: {
EnableTesting: true,
},
});
});
beforeEach(() => {
// # Login as user-1
cy.apiLogin(testUser);
// # Navigate to a channel.
cy.visit(`/${testTeam.name}/channels/town-square`);
});
it('fails to run subcommand bulk-data', () => {
// # Execute the bulk-data command.
cy.uiPostMessageQuickly('/playbook test bulk-data');
// * Verify the ephemeral message warns that the user is not admin.
cy.verifyEphemeralMessage('Running the test command is restricted to system administrators.');
});
it('fails to run subcommand create-playbook-run', () => {
// # Execute the create-playbook-run command.
cy.uiPostMessageQuickly('/playbook test create-playbook-run');
// * Verify the ephemeral message warns that the user is not admin.
cy.verifyEphemeralMessage('Running the test command is restricted to system administrators.');
});
it('fails to run subcommand self', () => {
// # Execute the self command.
cy.uiPostMessageQuickly('/playbook test self');
// * Verify the ephemeral message warns that the user is not admin.
cy.verifyEphemeralMessage('Running the test command is restricted to system administrators.');
});
});
describe('as an admin', () => {
describe('with EnableTesting set to false', () => {
before(() => {
// # Login as sysadmin.
cy.apiAdminLogin();
// # Set EnableTesting to false.
cy.apiUpdateConfig({
ServiceSettings: {
EnableTesting: false,
},
});
});
beforeEach(() => {
// # Login as sysadmin.
cy.apiAdminLogin();
// # Navigate to a channel.
cy.visit(`/${testTeam.name}/channels/town-square`);
});
it('fails to run subcommand bulk-data', () => {
// # Execute the bulk-data command.
cy.uiPostMessageQuickly('/playbook test bulk-data');
// * Verify the ephemeral message warns that the user is not admin.
cy.verifyEphemeralMessage('Setting EnableTesting must be set to true to run the test command.');
});
it('fails to run subcommand create-playbook-run', () => {
// # Execute the create-playbook-run command.
cy.uiPostMessageQuickly('/playbook test create-playbook-run');
// * Verify the ephemeral message warns that the user is not admin.
cy.verifyEphemeralMessage('Setting EnableTesting must be set to true to run the test command.');
});
it('fails to run subcommand self', () => {
// # Execute the self command.
cy.uiPostMessageQuickly('/playbook test self');
// * Verify the ephemeral message warns that the user is not admin.
cy.verifyEphemeralMessage('Setting EnableTesting must be set to true to run the test command.');
});
});
describe('with EnableTesting set to true', () => {
before(() => {
// # Login as sysadmin.
cy.apiAdminLogin();
// # Set EnableTesting to true.
cy.apiUpdateConfig({
ServiceSettings: {
EnableTesting: true,
},
});
});
beforeEach(() => {
// # Login as sysadmin.
cy.apiAdminLogin();
// # Size the viewport to show the RHS without covering posts.
cy.viewport('macbook-13');
// # Navigate to a channel.
cy.visit(`/${testTeam.name}/channels/town-square`);
});
describe('with subcommand self', () => {
it('asks for confirmation', () => {
// # Execute the self command.
cy.uiPostMessageQuickly('/playbook test self');
// * Verify the ephemeral message asks for the confirmation keywords.
cy.verifyEphemeralMessage('Are you sure you want to self-test (which will nuke the database and delete all data -- instances, configuration)? All data will be lost. To self-test, type /playbook test self CONFIRM TEST SELF');
});
});
describe('with subcommand create', () => {
it('fails to run with no arguments', () => {
// # Execute the create-playbook-run command with no arguments.
cy.uiPostMessageQuickly('/playbook test create-playbook-run');
// * Verify the ephemeral message warns about the parameters.
cy.verifyEphemeralMessage('The command expects three parameters: <playbook_id> <timestamp> <name>');
});
it('fails to run with one argument', () => {
// # Execute the create-playbook-run command with one argument.
cy.uiPostMessageQuickly(`/playbook test create-playbook-run ${testPlaybook.id}`);
// * Verify the ephemeral message warns about the parameters.
cy.verifyEphemeralMessage('The command expects three parameters: <playbook_id> <timestamp> <name>');
});
it('fails to run with two arguments', () => {
// # Execute the create-playbook-run command with two arguments.
cy.uiPostMessageQuickly(`/playbook test create-playbook-run ${testPlaybook.id} 2020-01-01`);
// * Verify the ephemeral message warns about the parameters.
cy.verifyEphemeralMessage('The command expects three parameters: <playbook_id> <timestamp> <name>');
});
it('fails to run with a malformed playbook ID', () => {
// # Execute the create-playbook-run command with all arguments, but a malformed plabook ID.
cy.uiPostMessageQuickly('/playbook test create-playbook-run unknownID 2020-01-01 The playbook run name');
// * Verify the ephemeral message warns about the ID.
cy.verifyEphemeralMessage('The first parameter, <playbook_id>, must be a valid ID.');
});
it('fails to run with a valid, but unknown playbook ID', () => {
// # Execute the create-playbook-run command with all arguments, but an unknown plabook ID.
cy.uiPostMessageQuickly('/playbook test create-playbook-run abcdefghijklmnopqrstuvwxyz 2020-01-01 The playbook run name');
// * Verify the ephemeral message warns about the parameter.
cy.verifyEphemeralMessage('The playbook with ID \'abcdefghijklmnopqrstuvwxyz\' does not exist.');
});
it('fails to run with a malformed date', () => {
// # Execute the create-playbook-run command with all arguments, but a malformed creation timestamp.
cy.uiPostMessageQuickly(`/playbook test create-playbook-run ${testPlaybook.id} 2020-1-1 The playbook run name`);
// * Verify the ephemeral message warns about the parameter.
cy.verifyEphemeralMessage('Timestamp \'2020-1-1\' could not be parsed as a date. If you want the playbook run to start on January 2, 2006, the timestamp should be \'2006-01-02\'.');
});
});
});
});
});

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

@@ -0,0 +1,322 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// ***************************************************************
// Stage: @prod
// Group: @playbooks
describe('channels > slash command > todo', () => {
let team1;
let team2;
let testUser;
let testOtherUser;
let run1;
let run2;
let run3;
let run4;
before(() => {
cy.apiInitSetup().then(({team, user}) => {
team1 = team;
testUser = user;
cy.apiCreateUser().then(({user: otherUser}) => {
testOtherUser = otherUser;
// # Add this new user to the team
cy.apiAddUserToTeam(team1.id, testOtherUser.id);
// # Login as testUser
cy.apiLogin(testUser);
// # Create a public playbook
cy.apiCreatePlaybook({
teamId: team1.id,
title: 'Playbook One',
memberIDs: [],
createPublicPlaybookRun: true,
checklists: [
{
title: 'Playbook One - Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Playbook One - Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
}).then(({id: playbookId}) => {
// # Create two runs in team 1.
const now = Date.now();
cy.apiRunPlaybook({
teamId: team1.id,
playbookId,
playbookRunName: 'Playbook Run (' + now + ')',
ownerUserId: testUser.id,
}).then((run) => {
run1 = run;
});
const now2 = Date.now() + 100;
cy.apiRunPlaybook({
teamId: team1.id,
playbookId,
playbookRunName: 'Playbook Run (' + now2 + ')',
ownerUserId: testUser.id,
}).then((run) => {
run2 = run;
});
});
// # Create a second team to test cross-team notifications
cy.apiCreateTeam('team2', 'Team 2').then(({team: secondTeam}) => {
team2 = secondTeam;
cy.apiAdminLogin();
cy.apiAddUserToTeam(team2.id, testUser.id);
cy.apiLogin(testUser);
// # Create a public playbook
cy.apiCreatePlaybook({
teamId: team2.id,
title: 'Playbook Two',
memberIDs: [],
createPublicPlaybookRun: true,
checklists: [
{
title: 'Playbook Two - Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Playbook Two - Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
}).then(({id: playbookId}) => {
// # Create one run in team 2.
const now = Date.now() + 200;
cy.apiRunPlaybook({
teamId: team2.id,
playbookId,
playbookRunName: 'Playbook Run (' + now + ')',
ownerUserId: testUser.id,
}).then((run) => {
run3 = run;
});
});
});
// # Create another playbook with runs owned by another user
cy.apiCreatePlaybook({
teamId: team1.id,
title: 'Playbook Other',
memberIDs: [],
createPublicPlaybookRun: true,
checklists: [
{
title: 'Playbook Other - Stage 1',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
{
title: 'Playbook Other - Stage 2',
items: [
{title: 'Step 1'},
{title: 'Step 2'},
],
},
],
}).then(({id: playbookId}) => {
// # Login as testOtherUser
cy.apiLogin(testOtherUser);
// # Create a run in team 1, with testOtherUser as owner and inviting testUser
const now = Date.now();
cy.apiRunPlaybook({
teamId: team1.id,
playbookId,
playbookRunName: 'Other Playbook Run (' + now + ')',
ownerUserId: testOtherUser.id,
}).then((run) => {
run4 = run;
// # Invite testUser to the channel
// cy.apiAddUserToChannel(run.channel_id, testUser.id);
cy.apiAddUsersToRun(run.id, [testUser.id]);
// # Force this run to be overdue
cy.apiUpdateStatus({
playbookRunId: run4.id,
message: 'no message 4',
reminder: 1,
});
});
// # Create a run in team 1, with testOtherUser as owner but not inviting testUser
const now2 = Date.now() + 100;
cy.apiRunPlaybook({
teamId: team1.id,
playbookId,
playbookRunName: 'Other Playbook Run (' + now2 + ')',
ownerUserId: testOtherUser.id,
}).then((run) => {
// # Force this run to be overdue
cy.apiUpdateStatus({
playbookRunId: run.id,
message: 'no message 5',
reminder: 1,
});
});
});
});
});
});
beforeEach(() => {
// # Size the viewport to show the RHS without covering posts.
cy.viewport('macbook-13');
// # Login as testUser
cy.apiLogin(testUser);
});
describe('/playbook todo should show', () => {
it('three runs', () => {
// # Navigate to a non-playbook run channel.
cy.visit(`/${team2.name}/channels/town-square`);
// # Run a slash command to show the to-do list.
cy.uiPostMessageQuickly('/playbook todo');
cy.getLastPost().within((post) => {
// * Should show titles
cy.wrap(post).contains('You have 0 runs overdue.');
cy.wrap(post).contains('You have 0 assigned tasks.');
cy.wrap(post).contains('You have 4 runs currently in progress:');
// * Should show four active runs
cy.get('li').then((liItems) => {
expect(liItems[0]).to.contain.text(run4.name);
expect(liItems[1]).to.contain.text(run1.name);
expect(liItems[2]).to.contain.text(run2.name);
expect(liItems[3]).to.contain.text(run3.name);
});
});
});
it('four assigned tasks', () => {
// # assign self four tasks
cy.apiChangeChecklistItemAssignee(run1.id, 0, 0, testUser.id);
cy.apiChangeChecklistItemAssignee(run1.id, 1, 1, testUser.id);
cy.apiChangeChecklistItemAssignee(run2.id, 0, 1, testUser.id);
cy.apiChangeChecklistItemAssignee(run3.id, 1, 0, testUser.id);
// # Navigate to a non-playbook run channel.
cy.visit(`/${team2.name}/channels/town-square`);
// # Run a slash command to show the to-do list.
cy.uiPostMessageQuickly('/playbook todo');
cy.getLastPost().within((post) => {
// * Should show titles
cy.wrap(post).contains('You have 0 runs overdue.');
cy.wrap(post).contains('You have 4 total assigned tasks:');
// * Should show 3 runs w/ tasks
cy.get('.post__body a').then((links) => {
expect(links[0]).to.contain.text(run1.name);
expect(links[1]).to.contain.text(run2.name);
expect(links[2]).to.contain.text(run3.name);
});
cy.get('.post__body li').then((items) => {
// * first run
expect(items[0]).to.contain.text('Playbook One - Stage 1: Step 1');
expect(items[1]).to.contain.text('Playbook One - Stage 2: Step 2');
// * second run
expect(items[2]).to.contain.text('Playbook One - Stage 1: Step 2');
// * third run
expect(items[3]).to.contain.text('Playbook Two - Stage 2: Step 1');
});
});
// # check two of the items via API
cy.apiSetChecklistItemState(run1.id, 0, 0, 'closed');
cy.apiSetChecklistItemState(run3.id, 1, 0, 'closed');
// # Show the to-do list.
cy.uiPostMessageQuickly('/playbook todo');
// * Should show 2 tasks
cy.getLastPost().within((post) => {
// * Should show titles
cy.wrap(post).contains('You have 0 runs overdue.');
cy.wrap(post).contains('You have 2 total assigned tasks:');
// * Should show 2 runs w/ tasks
cy.get('.post__body a').then((links) => {
expect(links[0]).to.contain.text(run1.name);
expect(links[1]).to.contain.text(run2.name);
});
cy.get('.post__body li').then((items) => {
// * first run
expect(items[0]).to.contain.text('Playbook One - Stage 2: Step 2');
// * second run
expect(items[1]).to.contain.text('Playbook One - Stage 1: Step 2');
});
});
});
it('two overdue status updates', () => {
// # set two updates with short timers
cy.apiUpdateStatus({
playbookRunId: run1.id,
message: 'no message 1',
reminder: 1,
});
cy.apiUpdateStatus({
playbookRunId: run3.id,
message: 'no message 3',
reminder: 1,
});
cy.wait(1100);
// # Switch to playbooks DM channel
cy.visit(`/${team2.name}/messages/@playbooks`);
// # Run a slash command to show the to-do list.
cy.uiPostMessageQuickly('/playbook todo');
// # Should show two runs overdue -- ignoring the rest
cy.getLastPost().within(() => {
cy.get('.post__body li').then((liItems) => {
expect(liItems[0]).to.contain.text(run1.name);
expect(liItems[1]).to.contain.text(run3.name);
});
});
});
});
});