From 1cb244e8760d979d06c59856bf7ff3b62aaac0e9 Mon Sep 17 00:00:00 2001 From: sabril <5334504+saturninoabril@users.noreply.github.com> Date: Wed, 21 May 2025 16:37:01 +0800 Subject: [PATCH] remove cypress tests of playbooks (#31128) --- .../tests/fixtures/playbook-export.json | 23 - .../playbooks/adminconsole/analytics_spec.js | 107 -- .../integration/playbooks/api/runs_spec.js | 189 --- .../playbooks/channels/app_bar_spec.js | 69 -- .../playbooks/channels/broadcast_spec.js | 390 ------ .../playbooks/channels/channel_header_spec.js | 138 --- .../channels/general_actions_spec.js | 391 ------ .../channels/playbook_run_actions.js | 644 ---------- .../channels/post_type_components_spec.js | 173 --- .../playbooks/channels/retrospective_spec.js | 242 ---- .../playbooks/channels/rhs/about_spec.js | 132 -- .../playbooks/channels/rhs/checklist_spec.js | 489 -------- .../playbooks/channels/rhs/header_spec.js | 225 ---- .../playbooks/channels/rhs/home_spec.js | 159 --- .../playbooks/channels/rhs/list_spec.js | 263 ---- .../channels/rhs/start_run_rhs_spec.js | 589 --------- .../channels/rhs/status_update_spec.js | 495 -------- .../playbooks/channels/rhs/template_spec.js | 74 -- .../playbooks/channels/rhs/title_spec.js | 94 -- .../playbooks/channels/rhs_spec.js | 417 ------- .../playbooks/channels/run_dialog_spec.js | 132 -- .../playbooks/channels/run_spec.js | 120 -- .../channels/slash_command/commands_spec.js | 557 --------- .../channels/slash_command/info_spec.js | 120 -- .../channels/slash_command/owner_spec.js | 222 ---- .../channels/slash_command/test_spec.js | 257 ---- .../channels/slash_command/todo_spec.js | 321 ----- .../channels/update_request_post_spec.js | 199 ---- .../integration/playbooks/digest_spec.js | 178 --- .../tests/integration/playbooks/lhs_spec.js | 394 ------ .../integration/playbooks/navigation_spec.js | 72 -- .../playbooks/playbooks/access_spec.js | 114 -- .../playbooks/creation_button_spec.js | 201 ---- .../playbooks/playbooks/edit/actions_spec.js | 1058 ----------------- .../playbooks/edit/checklists_spec.js | 185 --- .../playbooks/playbooks/edit/header_spec.js | 99 -- .../playbooks/edit/task_actions_spec.js | 465 -------- .../playbooks/playbooks/edit_metrics_spec.js | 568 --------- .../playbooks/playbooks/feedback_spec.js | 75 -- .../playbooks/playbooks/list_spec.js | 217 ---- .../playbooks/playbooks/overview_spec.js | 468 -------- .../playbooks/playbooks/pagination_spec.js | 68 -- .../playbooks/playbooks/start_run_spec.js | 578 --------- .../playbooks/playbooks/status_update_spec.js | 196 --- .../integration/playbooks/runs/list_spec.js | 262 ---- .../playbooks/runs/permissions_spec.js | 498 -------- .../playbooks/runs/rdp_general_spec.js | 83 -- .../playbooks/runs/rdp_main_checklist_spec.js | 150 --- .../playbooks/runs/rdp_main_finish_spec.js | 130 -- .../playbooks/runs/rdp_main_header_spec.js | 869 -------------- .../playbooks/runs/rdp_main_restore_spec.js | 107 -- .../runs/rdp_main_retrospective_spec.js | 500 -------- .../runs/rdp_main_statusupdate_spec.js | 304 ----- .../playbooks/runs/rdp_main_summary_spec.js | 162 --- .../runs/rdp_main_taskactions_spec.js | 712 ----------- .../runs/rdp_rhs_participants_spec.js | 266 ----- .../playbooks/runs/rdp_rhs_runinfo_spec.js | 549 --------- .../playbooks/runs/rdp_rhs_spec.js | 129 -- .../runs/rdp_rhs_statusupdates_spec.js | 150 --- .../playbooks/runs/taskinbox_spec.js | 189 --- .../playbooks/tours_spec_ignore_.js | 121 -- e2e-tests/cypress/tests/support/api/index.js | 1 - .../cypress/tests/support/api/playbooks.js | 483 -------- e2e-tests/cypress/tests/support/ui/index.js | 1 - .../cypress/tests/support/ui/playbooks.js | 324 ----- 65 files changed, 18157 deletions(-) delete mode 100644 e2e-tests/cypress/tests/fixtures/playbook-export.json delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/adminconsole/analytics_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/api/runs_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/broadcast_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/channel_header_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/general_actions_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/playbook_run_actions.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/post_type_components_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/retrospective_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/about_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/checklist_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/header_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/home_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/list_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/start_run_rhs_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/status_update_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/template_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs/title_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/rhs_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/run_dialog_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/run_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/commands_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/info_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/owner_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/test_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/todo_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/channels/update_request_post_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/digest_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/lhs_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/navigation_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/access_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/creation_button_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/actions_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/checklists_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/header_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/task_actions_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/edit_metrics_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/feedback_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/list_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/overview_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/pagination_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/start_run_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/playbooks/status_update_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/list_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/permissions_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_general_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_checklist_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_finish_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_header_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_restore_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_retrospective_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_statusupdate_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_summary_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_taskactions_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_participants_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_runinfo_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_statusupdates_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/runs/taskinbox_spec.js delete mode 100644 e2e-tests/cypress/tests/integration/playbooks/tours_spec_ignore_.js delete mode 100644 e2e-tests/cypress/tests/support/api/playbooks.js delete mode 100644 e2e-tests/cypress/tests/support/ui/playbooks.js diff --git a/e2e-tests/cypress/tests/fixtures/playbook-export.json b/e2e-tests/cypress/tests/fixtures/playbook-export.json deleted file mode 100644 index 99a1ed655a..0000000000 --- a/e2e-tests/cypress/tests/fixtures/playbook-export.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "checklists": [ - { - "items": [ - { - "title": "Untitled task" - } - ], - "title": "Default checklist" - } - ], - "create_channel_member_on_new_participant": true, - "create_channel_member_on_removed_participant": true, - "description": "Customize this playbook's description to give an overview of when and how this playbook is run.", - "message_on_join": "Welcome! This channel was automatically created as part of a playbook run.", - "metrics": [], - "reminder_timer_default_seconds": 604800, - "retrospective_enabled": true, - "retrospective_template": "### Summary\nThis should contain 2-3 sentences that give a reader an overview of what happened, what was the cause, and what was done. The briefer the better as this is what future teams will look at first for reference.\n\n### What was the impact?\nThis section describes the impact of this playbook run as experienced by internal and external customers as well as stakeholders.\n\n### What were the contributing factors?\nThis playbook may be a reactive protocol to a situation that is otherwise undesirable. If that's the case, this section explains the reasons that caused the situation in the first place. There may be multiple root causes - this helps stakeholders understand why.\n\n### What was done?\nThis section tells the story of how the team collaborated throughout the event to achieve the outcome. This will help future teams learn from this experience on what they could try.\n\n### What did we learn?\nThis section should include perspective from everyone that was involved to celebrate the victories and identify areas for improvement. For example: What went well? What didn't go well? What should be done differently next time?\n\n### Follow-up tasks\nThis section lists the action items to turn learnings into changes that help the team become more proficient with iterations. It could include tweaking the playbook, publishing the retrospective, or other improvements. The best follow-ups will have a clear owner as well as due date.\n\n### Timeline highlights\nThis section is a curated log that details the most important moments. It can contain key communications, screen shots, or other artifacts. Use the built-in timeline feature to help you retrace and replay the sequence of events.", - "status_update_enabled": true, - "title": "Example Playbook", - "version": 1 -} diff --git a/e2e-tests/cypress/tests/integration/playbooks/adminconsole/analytics_spec.js b/e2e-tests/cypress/tests/integration/playbooks/adminconsole/analytics_spec.js deleted file mode 100644 index f1ac8709d3..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/adminconsole/analytics_spec.js +++ /dev/null @@ -1,107 +0,0 @@ -// 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('admin console', {testIsolation: true}, () => { - let testUser; - let testTeam; - let testPlaybook; - let testSysadmin; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - cy.apiCreateCustomAdmin().then(({sysadmin}) => { - testSysadmin = sysadmin; - }); - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Login as testSysddmin - cy.apiLogin(testSysadmin); - }); - - describe('site statistics', () => { - it('playbooks and runs counters are visible', () => { - // # Go to admin console > site statistics - cy.visit('/admin_console/reporting/system_analytics'); - - // * Check that the playbook and run counters are visible - cy.findByTestId('playbooks.playbook_count').should('exist'); - cy.findByTestId('playbooks.playbook_run_count').should('exist'); - }); - - it('playbook counter increases after creating a playbook', () => { - let counter; - - // # Go to admin console > site statistics - cy.visit('/admin_console/reporting/system_analytics'); - - // # Capture current value of playbook counter - cy.findByTestId('playbooks.playbook_count').invoke('prop', 'innerText').then((pbCount) => { - counter = parseInt(pbCount, 10); - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - }).then(() => { - cy.apiLogin(testSysadmin); - - // # Go to admin console > site statistics - cy.visit('/admin_console/reporting/system_analytics'); - - // * Verify that the Playbook Counter has been increased by 1 - cy.findByTestId('playbooks.playbook_count').contains(String(counter + 1)); - }); - }); - }); - - it('run counter increases after creating a run', () => { - let counter; - - // # Go to admin console > site statistics - cy.visit('/admin_console/reporting/system_analytics'); - - // # Capture current value of run counter - cy.findByTestId('playbooks.playbook_run_count').invoke('prop', 'innerText').then((runCount) => { - counter = parseInt(runCount, 10); - cy.apiLogin(testUser); - - // # create a run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'My run for test', - ownerUserId: testUser.id, - }).then(() => { - cy.apiLogin(testSysadmin); - - // # Go to admin console > site statistics - cy.visit('/admin_console/reporting/system_analytics'); - - // * Verify that the Run Counter has been increased by 1 - cy.findByTestId('playbooks.playbook_run_count').contains(String(counter + 1)); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/api/runs_spec.js b/e2e-tests/cypress/tests/integration/playbooks/api/runs_spec.js deleted file mode 100644 index 5af3e20957..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/api/runs_spec.js +++ /dev/null @@ -1,189 +0,0 @@ -// 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('api > runs', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('creating a run', () => { - describe('in an existing, public channel', () => { - it('with no team_id specified', () => { - // # Create a test channel without a playbook run - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel').then(({channel}) => { - // # Run the testPlaybook in the previously created channel - - cy.apiRunPlaybook({ - ownerUserId: testUser.id, - channelId: channel.id, - playbookId: testPlaybook.id, - }, {expectedStatusCode: 201}).then((body) => { - expect(body).to.have.property('owner_user_id', testUser.id); - expect(body).to.have.property('reporter_user_id', testUser.id); - expect(body).to.have.property('team_id', testTeam.id); - expect(body).to.have.property('channel_id', channel.id); - expect(body).to.have.property('playbook_id', testPlaybook.id); - }); - }); - }); - - it('with correct team_id specified', () => { - // # Create a test channel without a playbook run - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel').then(({channel}) => { - // # Run the testPlaybook in the previously created channel - cy.apiRunPlaybook({ - ownerUserId: testUser.id, - channelId: channel.id, - playbookId: testPlaybook.id, - teamId: testTeam.id, - }, {expectedStatusCode: 201}).then((body) => { - expect(body).to.have.property('owner_user_id', testUser.id); - expect(body).to.have.property('reporter_user_id', testUser.id); - expect(body).to.have.property('team_id', testTeam.id); - expect(body).to.have.property('channel_id', channel.id); - expect(body).to.have.property('playbook_id', testPlaybook.id); - }); - }); - }); - - it('with wrong team_id specified', () => { - // # Create a test channel without a playbook run - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel').then(({channel}) => { - // # Run the testPlaybook in the previously created channel - cy.apiRunPlaybook({ - ownerUserId: testUser.id, - channelId: channel.id, - playbookId: testPlaybook.id, - teamId: 'other_team_id', - }, {expectedStatusCode: 400}).then((body) => { - expect(body).to.have.property('error', 'unable to create playbook run'); - }); - }); - }); - }); - - describe('in an existing, private channel', () => { - it('with no team_id specified', () => { - // # Create a test channel without a playbook run - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel', 'P').then(({channel}) => { - // # Run the testPlaybook in the previously created channel - cy.apiRunPlaybook({ - ownerUserId: testUser.id, - channelId: channel.id, - playbookId: testPlaybook.id, - }, {expectedStatusCode: 201}).then((body) => { - expect(body).to.have.property('owner_user_id', testUser.id); - expect(body).to.have.property('reporter_user_id', testUser.id); - expect(body).to.have.property('team_id', testTeam.id); - expect(body).to.have.property('channel_id', channel.id); - expect(body).to.have.property('playbook_id', testPlaybook.id); - }); - }); - }); - - it('with correct team_id specified', () => { - // # Create a test channel without a playbook run - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel', 'P').then(({channel}) => { - // # Run the testPlaybook in the previously created channel - cy.apiRunPlaybook({ - ownerUserId: testUser.id, - channelId: channel.id, - playbookId: testPlaybook.id, - teamId: testTeam.id, - }, {expectedStatusCode: 201}).then((body) => { - expect(body).to.have.property('owner_user_id', testUser.id); - expect(body).to.have.property('reporter_user_id', testUser.id); - expect(body).to.have.property('team_id', testTeam.id); - expect(body).to.have.property('channel_id', channel.id); - expect(body).to.have.property('playbook_id', testPlaybook.id); - }); - }); - }); - - it('with wrong team_id specified', () => { - // # Create a test channel without a playbook run - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel', 'P').then(({channel}) => { - // # Run the testPlaybook in the previously created channel - cy.apiRunPlaybook({ - ownerUserId: testUser.id, - channelId: channel.id, - playbookId: testPlaybook.id, - teamId: 'other_team_id', - }, {expectedStatusCode: 400}).then((body) => { - expect(body).to.have.property('error', 'unable to create playbook run'); - }); - }); - }); - }); - - it('in an existing, private channel, of which the user is not a member', () => { - // # Create a test channel without a playbook run - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel', 'P').then(({channel}) => { - // # Leave the channel - cy.apiRemoveUserFromChannel(channel.id, testUser.id); - - // # Run the testPlaybook in the previously created channel - cy.apiRunPlaybook({ - ownerUserId: testUser.id, - channelId: channel.id, - playbookId: testPlaybook.id, - teamId: testTeam.id, - }, {expectedStatusCode: 403}).then((body) => { - expect(body).to.have.property('error', 'unable to create playbook run'); - }); - }); - }); - - it('in a channel with an existing playbook run', () => { - // # Run the playbook, creating a channel. - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'Playbook', - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # Run the testPlaybook in the previously created channel - cy.apiRunPlaybook({ - owner_user_id: testUser.id, - channel_id: playbookRun.channel_id, - playbook_id: testPlaybook.id, - }, {expectedStatusCode: 400}).then((body) => { - expect(body).to.have.property('error', 'unable to create playbook run'); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js deleted file mode 100644 index c9b3883584..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/app_bar_spec.js +++ /dev/null @@ -1,69 +0,0 @@ -// 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 > App Bar', {testIsolation: true}, () => { - let testTeam; - let testUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - }); - }); - - beforeEach(() => { - cy.apiAdminLogin(); - }); - - describe('App Bar disabled', () => { - it('should not show the Playbook App Bar icon', () => { - cy.apiUpdateConfig({ExperimentalSettings: {DisableAppBar: true}}); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Navigate directly to a non-playbook run channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // * Verify App Bar icon is not showing - cy.get('.app-bar').should('not.exist'); - }); - }); - - describe('App Bar enabled', () => { - beforeEach(() => { - cy.apiUpdateConfig({ExperimentalSettings: {DisableAppBar: false}}); - - // # Login as testUser - cy.apiLogin(testUser); - }); - - it('should show the Playbook App Bar icon', () => { - // # Navigate directly to a non-playbook run channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // * Verify App Bar icon is showing - cy.getPlaybooksAppBarIcon().should('exist'); - }); - - it('should show "Playbooks" tooltip for Playbook App Bar icon', () => { - // # Navigate directly to a non-playbook run channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Hover over the channel header icon - cy.getPlaybooksAppBarIcon().trigger('mouseenter'); - - // * Verify tooltip text - cy.findByRole('tooltip').should('be.visible').and('contain', 'Playbooks'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/broadcast_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/broadcast_spec.js deleted file mode 100644 index f658c615c8..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/broadcast_spec.js +++ /dev/null @@ -1,390 +0,0 @@ -// 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 > broadcast', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testAdmin; - let testPublicChannel1; - let testPublicChannel2; - let testPrivateChannel1; - let testPrivateChannel2; - let publicBroadcastPlaybook; - let privateBroadcastPlaybook; - let allBroadcastPlaybook; - let rootDeletePlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateCustomAdmin().then(({sysadmin: adminUser}) => { - testAdmin = adminUser; - cy.apiAddUserToTeam(testTeam.id, adminUser.id); - cy.apiSaveJoinLeaveMessagesPreference(adminUser.id, false); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public channel - cy.apiCreateChannel( - testTeam.id, - 'public-channel', - 'Public Channel 1', - 'O', - ).then(({channel: publicChannel1}) => { - testPublicChannel1 = publicChannel1; - - // # Create a public channel - cy.apiCreateChannel( - testTeam.id, - 'public-channel', - 'Public Channel 2', - 'O', - ).then(({channel: publicChannel2}) => { - testPublicChannel2 = publicChannel2; - - // # Create a private channel - cy.apiCreateChannel( - testTeam.id, - 'private-channel', - 'Private Channel 1', - 'P', - ).then(({channel: privateChannel1}) => { - testPrivateChannel1 = privateChannel1; - - // # Create a private channel - cy.apiCreateChannel( - testTeam.id, - 'private-channel', - 'Private Channel 2', - 'P', - ).then(({channel: privateChannel2}) => { - testPrivateChannel2 = privateChannel2; - - // # Create a playbook that will broadcast to public channel1 - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook - public broadcast', - userId: testUser.id, - broadcastChannelIds: [testPublicChannel1.id], - broadcastEnabled: true, - }).then((playbook) => { - publicBroadcastPlaybook = playbook; - }); - - // # Create a playbook that will broadcast to private channel1 - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook - private broadcast', - userId: testUser.id, - broadcastChannelIds: [testPrivateChannel1.id], - broadcastEnabled: true, - }).then((playbook) => { - privateBroadcastPlaybook = playbook; - }); - - // # Create a playbook that will broadcast to all 4 channels - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook - public and private broadcast', - userId: testUser.id, - broadcastChannelIds: [testPublicChannel1.id, testPublicChannel2.id, testPrivateChannel1.id, testPrivateChannel2.id], - broadcastEnabled: true, - }).then((playbook) => { - allBroadcastPlaybook = playbook; - }); - - // # Create a playbook for testing deleting root posts - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook - test deleting root posts', - userId: testUser.id, - broadcastChannelIds: [testPublicChannel1.id, testPrivateChannel1.id], - broadcastEnabled: true, - otherMembers: [testAdmin.id], - invitedUserIds: [testAdmin.id], - }).then((playbook) => { - rootDeletePlaybook = playbook; - }); - - // # invite testAdmin to the channel they will need to be in to delete the post - cy.apiAddUserToChannel(testPublicChannel1.id, testAdmin.id); - cy.apiAddUserToChannel(testPrivateChannel1.id, testAdmin.id); - }); - }); - }); - }); - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Go to Town Square - cy.visit(`/${testTeam.name}/channels/town-square`); - }); - - it('to public channels', () => { - // # Create a new playbook run - const now = Date.now(); - const playbookRunName = `Playbook Run (${now})`; - const playbookRunChannelName = `playbook-run-${now}`; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: publicBroadcastPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Update the playbook run's status - const updateMessage = 'Update - ' + now; - cy.updateStatus(updateMessage); - - // * Verify the posts - const initialMessage = playbookRunName; - verifyInitialAndStatusPostInBroadcast(testTeam, testPublicChannel1.name, playbookRunName, initialMessage, updateMessage); - }); - - it('does not broadcast when broadcast is disabled, even if broadcastChannelIds contain data', () => { - // # Create a brand new channel - cy.apiCreateChannel( - testTeam.id, - 'public-channel-do-not-broadcast', - 'Public Channel 1 - do not broadcast', - 'O', - ).then(({channel}) => { - // # Create a playbook with broadcast disabled, but with broadcastChannelIds containing channel1 - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook - disabled public broadcast', - userId: testUser.id, - broadcastChannelIds: [channel.id], - broadcastEnabled: false, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Playbook Run (${now})`; - const playbookRunChannelName = `playbook-run-${now}`; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Update the playbook run's status - const updateMessage = 'Update - ' + now; - cy.updateStatus(updateMessage); - - // # Navigate to the broadcast channel - cy.visit(`/${testTeam.name}/channels/${channel.name}`); - - // * Verify that the last post is the system post containing the join message, - // so no announcement nor update was posted - cy.getLastPostId().then((lastPostId) => { - cy.get(`#postMessageText_${lastPostId}`).contains('You joined the channel'); - }); - }); - }); - }); - - it('to private channels', () => { - // # Create a new playbook run - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: privateBroadcastPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Update the playbook run's status - const updateMessage = 'Update - ' + now; - cy.updateStatus(updateMessage); - - // * Verify the posts - const initialMessage = playbookRunName; - verifyInitialAndStatusPostInBroadcast(testTeam, testPrivateChannel1.name, playbookRunName, initialMessage, updateMessage); - }); - - it('to 4 public and private channels', () => { - // # Create a new playbook run - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: allBroadcastPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Update the playbook run's status - const updateMessage = 'Update - ' + now; - cy.updateStatus(updateMessage, 0); - - // * Verify the posts - const initialMessage = playbookRunName; - verifyInitialAndStatusPostInBroadcast(testTeam, testPublicChannel1.name, playbookRunName, initialMessage, updateMessage); - verifyInitialAndStatusPostInBroadcast(testTeam, testPrivateChannel1.name, playbookRunName, initialMessage, updateMessage); - verifyInitialAndStatusPostInBroadcast(testTeam, testPublicChannel2.name, playbookRunName, initialMessage, updateMessage); - verifyInitialAndStatusPostInBroadcast(testTeam, testPrivateChannel2.name, playbookRunName, initialMessage, updateMessage); - }); - - it('to 2 channels, delete the root post, update again', () => { - // # Create a new playbook run - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: rootDeletePlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Update the playbook run's status - const updateMessage = 'Update - ' + now; - cy.updateStatus(updateMessage, 0); - - // * Verify the posts - const initialMessage = playbookRunName; - verifyInitialAndStatusPostInBroadcast(testTeam, testPublicChannel1.name, playbookRunName, initialMessage, updateMessage); - verifyInitialAndStatusPostInBroadcast(testTeam, testPrivateChannel1.name, playbookRunName, initialMessage, updateMessage); - - // # need to be admin to delete the bot's posts - cy.apiLogin(testAdmin); - - // # Delete both root posts - deleteLatestPostRoot(testTeam, testPublicChannel1.name); - deleteLatestPostRoot(testTeam, testPrivateChannel1.name); - - // # Log back in as testUser - cy.apiLogin(testUser); - - // # Make two more updates - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Update the playbook run's status twice - const updateMessage2 = updateMessage + ' - 2'; - cy.updateStatus(updateMessage2, 0); - const updateMessage3 = updateMessage + ' - 3'; - cy.updateStatus(updateMessage3, 0); - - // * Verify the posts - verifyInitialAndStatusPostInBroadcast(testTeam, testPublicChannel1.name, playbookRunName, updateMessage2, updateMessage3); - verifyInitialAndStatusPostInBroadcast(testTeam, testPrivateChannel1.name, playbookRunName, updateMessage2, updateMessage3); - }); -}); - -const verifyInitialAndStatusPostInBroadcast = (testTeam, channelName, runName, initialMessage, updateMessage) => { - cy.log(`Verifying initial and status post in broadcast (channel ${channelName}, run ${runName})`); - - // # Navigate to the broadcast channel - cy.visit(`/${testTeam.name}/channels/${channelName}`); - - // * Verify that the last post contains the expected header and the update message verbatim - cy.getLastPostId().then((lastPostId) => { - // # Open RHS comment menu - cy.clickPostCommentIcon(lastPostId); - - cy.get('#rhsContainer'). - should('exist'). - within(() => { - // * Thread should have two posts - cy.findAllByTestId('postContent').should('have.length', 2); - - // * The first should be announcement - cy.findAllByTestId('postContent').eq(0).contains(initialMessage); - - // * Latest post should be update - cy.get(`#rhsPost_${lastPostId}`).contains( - `posted an update for ${runName}`, - ); - cy.get(`#rhsPost_${lastPostId}`).contains('tasks checked'); - cy.get(`#rhsPost_${lastPostId}`).contains('participant'); - cy.get(`#rhsPost_${lastPostId}`).contains(updateMessage); - }); - }); -}; - -const deleteLatestPostRoot = (testTeam, channelName) => { - cy.log(`Deleting latest root post (channel ${channelName})`); - - // # Navigate to the channel - cy.visit(`/${testTeam.name}/channels/${channelName}`); - - cy.getLastPostId().then((lastPostId) => { - // # Open RHS comment menu - cy.clickPostCommentIcon(lastPostId); - - cy.get('#rhsContainer'). - should('exist'). - within(() => { - cy.findAllByTestId('postContent').eq(0).parent().then((root) => { - const rootId = root.attr('id').slice(8); - - // # Click root's post dot menu. - cy.clickPostDotMenu(rootId, 'RHS_ROOT'); - - // # Click delete button. - const id = `#delete_post_${rootId}`; - cy.wrap(id).as('deleteId'); - }); - }); - - // * Post extra options is visible - cy.findByLabelText('Post extra options').should('have.attr', 'role', 'menu').and('exist'); - - // # Click delete button. - cy.get('@deleteId').then((deleteId) => { - cy.get(deleteId).should('be.visible').click(); - }); - - // * Check that confirmation dialog is open. - cy.get('#deletePostModal').should('be.visible'); - - // * Check that confirmation dialog contains correct text - cy.get('#deletePostModal'). - should('contain', 'Are you sure you want to delete this message?'); - - // * Check that confirmation dialog shows that the post has one comment on it - cy.get('#deletePostModal').should('contain', 'This message has 1 comment on it.'); - - // # Confirm deletion. - cy.get('#deletePostModalButton').click(); - }); -}; diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/channel_header_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/channel_header_spec.js deleted file mode 100644 index f104665260..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/channel_header_spec.js +++ /dev/null @@ -1,138 +0,0 @@ -// 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 > channel header', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - let testPlaybookRun; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - - // # Start a playbook run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'Playbook Run', - ownerUserId: testUser.id, - }).then((run) => { - testPlaybookRun = run; - }); - }); - }); - }); - - describe('App Bar enabled', () => { - it('webapp should hide the Playbook channel header button', () => { - cy.apiAdminLogin(); - cy.apiUpdateConfig({ExperimentalSettings: {DisableAppBar: false}}); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Navigate directly to a non-playbook run channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // * Verify channel header button is not showing - cy.get('#channel-header').within(() => { - cy.get('#incidentIcon').should('not.exist'); - }); - }); - }); - - describe('App Bar disabled', () => { - beforeEach(() => { - cy.apiAdminLogin(); - cy.apiUpdateConfig({ExperimentalSettings: {DisableAppBar: true}}); - - // # Login as testUser - cy.apiLogin(testUser); - }); - - it.skip('webapp should show the Playbook channel header button', () => { - // # Navigate directly to a non-playbook run channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // * Verify channel header button is showing - cy.get('#channel-header').within(() => { - cy.get('#incidentIcon').should('exist'); - }); - }); - - it('tooltip text should show "Playbooks" for Playbook channel header button', () => { - // # Navigate directly to a non-playbook run channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Hover over the channel header icon - cy.get('#channel-header').within(() => { - cy.get('#incidentIcon').trigger('mouseover'); - }); - - // * Verify tooltip text - cy.get('#playbooksChannelHeaderButton').contains('Playbooks'); - }); - - it.skip('webapp should make the Playbook channel header button active when opened', () => { - // # Navigate directly to a non-playbook run channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - cy.get('#channel-header').within(() => { - // # Click the channel header button - cy.get('#incidentIcon').click(); - - // * Verify channel header button is showing active className - cy.get('#incidentIcon').parent(). - should('have.class', 'channel-header__icon--active-inverted'); - }); - }); - }); - - describe('description text', () => { - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - it('should contain a link to the playbook', () => { - // # Navigate directly to a playbook run channel - cy.visit(`/${testTeam.name}/channels/playbook-run`); - - // * Verify link to playbook - cy.get('.header-description__text').findByText('Playbook').should('have.attr', 'href').then((href) => { - expect(href).to.equals(`/playbooks/playbooks/${testPlaybook.id}`); - }); - }); - - it('should contain a link to the overview page', () => { - // # Navigate directly to a playbook run channel - cy.visit(`/${testTeam.name}/channels/playbook-run`); - - // * Verify link to overview page - cy.get('.header-description__text').findByText('the overview page').should('have.attr', 'href').then((href) => { - expect(href).to.equals(`/playbooks/runs/${testPlaybookRun.id}`); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/general_actions_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/general_actions_spec.js deleted file mode 100644 index e73d35e1ee..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/general_actions_spec.js +++ /dev/null @@ -1,391 +0,0 @@ -// 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 * as TIMEOUTS from '../../../fixtures/timeouts'; - -describe('channels > general actions', {testIsolation: true}, () => { - let testTeam; - let testSysadmin; - let testUser; - let testChannel; - - beforeEach(() => { - cy.apiAdminLogin(); - - cy.apiInitSetup({promoteNewUserAsAdmin: true}).then(({team, user}) => { - testTeam = team; - testSysadmin = user; - - cy.apiCreateUser().then((resp) => { - testUser = resp.user; - cy.apiAddUserToTeam(team.id, resp.user.id); - - cy.apiLogin(testUser); - - // TODO: Make this work with CRT enabled. - cy.apiSaveCRTPreference(testUser.id, 'off'); - }); - - cy.apiLogin(testSysadmin); - - // TODO: Make this work with CRT enabled. - cy.apiSaveCRTPreference(testSysadmin.id, 'off'); - - cy.apiCreateChannel( - testTeam.id, - 'action-channel', - 'Action Channel', - 'O', - ).then(({channel}) => { - testChannel = channel; - }); - }); - }); - - describe('on join trigger', () => { - it('channel categorization can be enabled and works', () => { - // # Go to the test channel - cy.visit(`/${testTeam.name}/channels/${testChannel.name}`); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // # Enable the categorization action and set the name - cy.contains('sidebar category').click(); - cy.contains('Enter category name').click().type('example category{enter}'); - - cy.get('#channel-actions-modal').within(() => { - // # Save action - cy.findByRole('button', {name: /save/i}).click(); - }); - - // # Switch to another user and reload - // # This drops them into the same channel - cy.apiLogin(testUser); - cy.reload(); - cy.wait(TIMEOUTS.TEN_SEC); - - // * Verify the channel category + channel exists - cy.contains('.SidebarChannelGroup', 'example category', {matchCase: false}). - should('exist'). - within(() => { - cy.contains(testChannel.display_name).should('exist'); - }); - }); - - it('welcome message can be enabled and is shown to a joining user', () => { - // # Go to the test channel - cy.visit(`/${testTeam.name}/channels/${testChannel.name}`); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // # Toggle on and set the welcome message - cy.contains('temporary welcome message').click(); - cy.findByTestId('channel-actions-modal_welcome-msg'). - type('test ephemeral welcome message'); - - cy.get('#channel-actions-modal').within(() => { - // # Save action - cy.findByRole('button', {name: /save/i}).click(); - }); - - // # Switch to another user and reload - // # This drops them into the same channel - cy.apiLogin(testUser); - cy.reload(); - cy.wait(TIMEOUTS.FIVE_SEC); - - // * Verify the welcome message is shown - cy.verifyEphemeralMessage('test ephemeral welcome message'); - }); - }); - - describe('keyword trigger', () => { - it('prompt to run playbook can be enabled and works', () => { - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }); - - // # Login as the non-sysadmin user first - // # to do the channel & action creation. - // # In the 'Select a playbook' dropdown later in this test, - // # sysadmin users could potentially see many other playbooks - // # besides the one created directly above. `testUser` will not. - cy.apiLogin(testUser); - cy.apiCreateChannel( - testTeam.id, - 'action-channel', - 'Action Channel', - 'O', - ).then(({channel}) => { - // # Go to the test channel - cy.visit(`/${testTeam.name}/channels/${channel.name}`); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // # Set a keyword, enable the playbook trigger, - // # and select the Playbook to run - cy.contains('Type a keyword or phrase, then press Enter on your keyboard').click().type('red alert{enter}'); - cy.contains('Prompt to run a playbook').click(); - cy.contains('Select a playbook').click(); - cy.findByText('Public Playbook').click(); - - cy.get('#channel-actions-modal').within(() => { - // # Save action - cy.findByRole('button', {name: /save/i}).click(); - }); - - // # Post the trigger phrase - cy.uiPostMessageQuickly('error detected red alert!'); - - // * Verify that the bot posts the expected prompt - // # Open the playbook run modal - cy.getLastPostId().then((postId) => { - cy.get(`#post_${postId}`).within(() => { - cy.contains('trigger for the Public Playbook').should('exist'); - cy.contains('Yes, run playbook').should('exist').click(); - }); - }); - - // # Enter a name and start the run - cy.findByTestId('playbookRunNameinput').type('run from trigger'); - cy.findByRole('button', {name: /start run/i}).click(); - - // * Verify text from the run channel description - cy.contains('start of the run').should('exist'); - }); - }); - - it('deletes the post and ignores the thread when clicking on No, ignore thread', () => { - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }); - - // # Login as the non-sysadmin user first - // # to do the channel & action creation. - // # In the 'Select a playbook' dropdown later in this test, - // # sysadmin users could potentially see many other playbooks - // # besides the one created directly above. `testUser` will not. - cy.apiLogin(testUser); - cy.apiCreateChannel( - testTeam.id, - 'action-channel', - 'Action Channel', - 'O', - ).then(({channel}) => { - // # Go to the test channel - cy.visit(`/${testTeam.name}/channels/${channel.name}`); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // # Set a keyword, enable the playbook trigger, - // # and select the Playbook to run - cy.contains('Type a keyword or phrase, then press Enter on your keyboard').click().type('red alert{enter}'); - cy.contains('Prompt to run a playbook').click(); - cy.contains('Select a playbook').click(); - cy.findByText('Public Playbook').click(); - - cy.get('#channel-actions-modal').within(() => { - // # Save action - cy.findByRole('button', {name: /save/i}).click(); - }); - - // # Post the trigger phrase - cy.uiPostMessageQuickly('error detected red alert!'); - - // * Verify that the bot posts the expected prompt - // # Click on No, ignore thread - cy.getLastPostId().then((postId) => { - cy.get(`#post_${postId}`).within(() => { - cy.contains('trigger for the Public Playbook').should('exist'); - cy.contains('No, ignore thread').should('exist').click(); - }); - }); - - // # Reload the channel - cy.visit(`/${testTeam.name}/channels/${channel.name}`); - - // * Verify that the prompt post is no longer there - cy.getLastPostId().then((postId) => { - cy.get(`#post_${postId}`).within(() => { - cy.contains('No, ignore thread').should('not.exist'); - }); - }); - - // # Reply to the last thread with the trigger phrase - cy.getLastPostId().then((postId) => { - cy.clickPostCommentIcon(postId); - cy.postMessageReplyInRHS('error detected red alert!'); - }); - - // * Verify that the bot did not post the prompt - cy.getLastPostId().then((postId) => { - cy.get(`#post_${postId}`).within(() => { - cy.contains('trigger for the Public Playbook').should('not.exist'); - }); - }); - }); - }); - - it('disabled triggers do not run even with a keyword set', () => { - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }); - - // # Login as the non-sysadmin user first - // # to do the channel & action creation. - // # In the 'Select a playbook' dropdown later in this test, - // # sysadmin users could potentially see many other playbooks - // # besides the one created directly above. `testUser` will not. - cy.apiLogin(testUser); - cy.apiCreateChannel( - testTeam.id, - 'action-channel', - 'Action Channel', - 'O', - ).then(({channel}) => { - // # Go to the test channel - cy.visit(`/${testTeam.name}/channels/${channel.name}`); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // # Set a keyword, enable the playbook trigger, - // # and select the playbook to run. Turn the - // # trigger back off but leave the keyword set. - cy.contains('Type a keyword or phrase, then press Enter on your keyboard').click().type('red alert{enter}'); - cy.contains('Prompt to run a playbook').click(); - cy.contains('Select a playbook').click(); - cy.findByText('Public Playbook').click(); - cy.contains('Prompt to run a playbook').click(); - - cy.get('#channel-actions-modal').within(() => { - // # Save action - cy.findByRole('button', {name: /save/i}).click(); - }); - - // # Post the trigger phrase - cy.uiPostMessageQuickly('error detected red alert!'); - - // * Verify that the bot _has not_ posted the expected prompt - cy.getLastPostId().then((postId) => { - cy.get(`#post_${postId}`).within(() => { - cy.contains('trigger for the Public Playbook').should('not.exist'); - cy.contains('Yes, run playbook').should('not.exist'); - }); - }); - }); - }); - }); - - it('action settings are disabled for non-channel admin', () => { - // # Login as non-channel admin - cy.apiLogin(testUser); - - // # Go to the test channel - cy.visit(`/${testTeam.name}/channels/${testChannel.name}`); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // * Verify the toggles are disabled - cy.findByRole('dialog', {name: /channel actions/i}).within(() => { - cy.get('input').should('be.disabled'); - }); - }); - - it('action settings are reset to the default when switching to a channel with no actions configured', () => { - // # Create an additional channel - const name = 'New channel ' + Date.now(); - cy.apiCreateChannel( - testTeam.id, - 'new-channel', - name, - 'O', - ).then(({channel}) => { - // # Visit the first channel - cy.visit(`/${testTeam.name}/channels/${testChannel.name}`); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // # Enable the categorization action and set the name - const categoryName = 'example category ' + Date.now(); - cy.contains('sidebar category').click(); - cy.contains('Enter category name').click().type(categoryName + '{enter}'); - - cy.get('#channel-actions-modal').within(() => { - // # Save action - cy.findByRole('button', {name: /save/i}).click(); - }); - - // # wait to avoid MM-45969 - cy.wait(5000); - - // # Switch to the additional channel - cy.get('#sidebarItem_' + channel.name).click(); - - // # Open Channel Header and the Channel Actions modal - cy.get('#channelHeaderTitle').click(); - - // * More actions menu option should be visible - cy.findByText('More actions').should('be.visible').trigger('mouseover'); - cy.findByText('Channel Actions').click(); - - // * Verify that the categorization action is disabled - cy.findByText('Add the channel to a sidebar category for the user').parent().within(() => { - cy.get('input').should('not.be.checked'); - }); - - // * Verify that the category name is not there - cy.findByText(categoryName).should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/playbook_run_actions.js b/e2e-tests/cypress/tests/integration/playbooks/channels/playbook_run_actions.js deleted file mode 100644 index 171659ca05..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/playbook_run_actions.js +++ /dev/null @@ -1,644 +0,0 @@ -// 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 > actions', {testIsolation: true}, () => { - let testTeam; - let testSysadmin; - let testUser; - let testPublicChannel; - const testUsers = []; - - before(() => { - cy.apiInitSetup({userPrefix: 'u'}).then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateCustomAdmin().then(({sysadmin}) => { - testSysadmin = sysadmin; - }); - - // # Create extra test users in this team - cy.apiCreateUser({prefix: 'u'}).then((payload) => { - cy.apiAddUserToTeam(testTeam.id, payload.user.id); - testUsers.push(payload.user); - }); - - cy.apiCreateUser({prefix: 'u'}).then((payload) => { - cy.apiAddUserToTeam(testTeam.id, payload.user.id); - testUsers.push(payload.user); - }); - - // # Create a public channel - cy.apiCreateChannel( - testTeam.id, - 'public-channel', - 'Public Channel', - 'O', - ).then(({channel}) => { - testPublicChannel = channel; - cy.apiAddUserToChannel(channel.id, testUser.id); - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Go to Town Square - cy.visit(`/${testTeam.name}/channels/town-square`); - }); - - describe(('when a playbook run starts'), () => { - describe('invite members setting', () => { - it('with no invited users and setting disabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - let playbookId; - - // # Create a playbook with the invite users disabled and no invited users - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - invitedUserIds: [], - inviteUsersEnabled: false, - }).then((playbook) => { - playbookId = playbook.id; - }); - - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that no users were invited - cy.getFirstPostId().then((id) => { - cy.get(`#postMessageText_${id}`). - contains('You were added to the channel by @playbooks.'). - should('not.contain', 'joined the channel'); - }); - }); - - it('with invited users and setting enabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with a couple of invited users and the setting enabled, and a playbook run with it - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - invitedUserIds: [testUsers[0].id, testUsers[1].id], - inviteUsersEnabled: true, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the users were invited - cy.getFirstPostId().then((id) => { - cy.get(`#postMessageText_${id}`).within(() => { - cy.findByText('2 others').click(); - }); - - cy.get(`#postMessageText_${id}`).contains(`@${testUsers[0].username}`); - cy.get(`#postMessageText_${id}`).contains(`@${testUsers[1].username}`); - cy.get(`#postMessageText_${id}`).contains('added to the channel by @playbooks.'); - }); - }); - }); - - it('with invited users and setting disabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with a couple of invited users and the setting enabled, and a playbook run with it - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - invitedUserIds: [testUsers[0].id, testUsers[1].id], - inviteUsersEnabled: false, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that no users were invited - cy.getFirstPostId().then((id) => { - cy.get(`#postMessageText_${id}`). - contains('You were added to the channel by @playbooks.'). - should('not.contain', 'joined the channel'); - }); - }); - }); - - it('with non-existent users', () => { - let userToRemove; - let playbook; - - // # Create a playbook with a user that is later removed from the team - cy.apiLogin(testSysadmin).then(() => { - cy.apiCreateUser().then((result) => { - userToRemove = result.user; - cy.apiAddUserToTeam(testTeam.id, userToRemove.id); - - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with the user that will be removed from the team. - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id, testSysadmin.id], - invitedUserIds: [userToRemove.id], - inviteUsersEnabled: true, - }).then((res) => { - playbook = res; - }); - - // # Remove user from the team - cy.apiDeleteUserFromTeam(testTeam.id, userToRemove.id); - }); - }).then(() => { - cy.apiLogin(testUser); - - // # Create a new playbook run with the playbook. - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that there is an error message from the bot - cy.getNthPostId(1).then((id) => { - cy.get(`#postMessageText_${id}`). - contains(`Failed to invite the following users: @${userToRemove.username}`); - }); - }); - }); - }); - - describe('default owner setting', () => { - it('defaults to the creator when no owner is specified', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - let playbookId; - - // # Create a playbook with the default owner setting set to false - // and no owner specified - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - defaultOwnerId: '', - defaultOwnerEnabled: false, - }).then((playbook) => { - playbookId = playbook.id; - }); - - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the RHS shows the owner being the creator - cy.get('#rhsContainer').within(() => { - cy.findByText('Owner').parent().within(() => { - cy.findByText(`@${testUser.username}`); - }); - }); - }); - - it('defaults to the creator when no owner is specified, even if the setting is enabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - let playbookId; - - // # Create a playbook with the default owner setting set to false - // and no owner specified - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - defaultOwnerId: '', - defaultOwnerEnabled: true, - }).then((playbook) => { - playbookId = playbook.id; - }); - - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the RHS shows the owner being the creator - cy.get('#rhsContainer').within(() => { - cy.findByText('Owner').parent().within(() => { - cy.findByText(`@${testUser.username}`); - }); - }); - }); - - it('assigns the owner when they are part of the invited members list', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with the owner being part of the invited users - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - invitedUserIds: [testUsers[0].id], - inviteUsersEnabled: true, - defaultOwnerId: testUsers[0].id, - defaultOwnerEnabled: true, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the RHS shows the owner being the invited user - cy.get('#rhsContainer').within(() => { - cy.findByText('Owner').parent().within(() => { - cy.findByText(`@${testUsers[0].username}`); - }); - }); - }); - }); - - it('assigns the owner even if they are not invited', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with the owner being part of the invited users - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - invitedUserIds: [], - inviteUsersEnabled: false, - defaultOwnerId: testUsers[0].id, - defaultOwnerEnabled: true, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the RHS shows the owner being the invited user - cy.get('#rhsContainer').within(() => { - cy.findByText('Owner').parent().within(() => { - cy.findByText(`@${testUsers[0].username}`); - }); - }); - }); - }); - - it('assigns the owner when they and the creator are the same', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - let playbookId; - - // # Create a playbook with the default owner setting set to false - // and no owner specified - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - defaultOwnerId: testUser.id, - defaultOwnerEnabled: true, - }).then((playbook) => { - playbookId = playbook.id; - }); - - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the RHS shows the owner being the creator - cy.get('#rhsContainer').within(() => { - cy.findByText('Owner').parent().within(() => { - cy.findByText(`@${testUser.username}`); - }); - }); - }); - }); - - describe('broadcast channel setting', () => { - it('with channel configured and setting enabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with a couple of invited users and the setting enabled, and a playbook run with it - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - broadcastChannelIds: [testPublicChannel.id], - broadcastEnabled: true, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel. - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the channel is created and that the first post exists. - cy.getFirstPostId().then((id) => { - cy.get(`#postMessageText_${id}`). - contains('You were added to the channel by @playbooks.'). - should('not.contain', 'joined the channel'); - }); - - // # Navigate to the broadcast channel - cy.visit(`/${testTeam.name}/channels/${testPublicChannel.name}`); - - cy.getLastPostId().then((lastPostId) => { - cy.get(`#postMessageText_${lastPostId}`).contains(`${playbookRunName}`); - cy.get(`#postMessageText_${lastPostId}`).contains(`@${testUser.username} ran the ${playbookName} playbook.`); - }); - }); - }); - - it('with channel configured and setting disabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with a couple of invited users and the setting enabled, and a playbook run with it - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - broadcastChannelIds: [testPublicChannel.id], - broadcastEnabled: false, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the channel is created and that the first post exists. - cy.getFirstPostId().then((id) => { - cy.get(`#postMessageText_${id}`). - contains('You were added to the channel by @playbooks.'). - should('not.contain', 'joined the channel'); - }); - - // # Navigate to the broadcast channel - cy.visit(`/${testTeam.name}/channels/${testPublicChannel.name}`); - - cy.getLastPostId().then((lastPostId) => { - cy.get(`#postMessageText_${lastPostId}`).should('not.contain', `New Run: ~${playbookRunName}`); - }); - }); - }); - - it('with non-existent channel', () => { - let playbookId; - - // # Create a playbook with a channel that is later deleted - cy.apiLogin(testSysadmin).then(() => { - const channelDisplayName = String('Channel to delete ' + Date.now()); - const channelName = channelDisplayName.replace(/ /g, '-').toLowerCase(); - cy.apiCreateChannel(testTeam.id, channelName, channelDisplayName).then(({channel}) => { - // # Create a playbook with the channel to be deleted as the announcement channel - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - createPublicPlaybookRun: true, - memberIDs: [testUser.id, testSysadmin.id], - broadcastChannelIds: [channel.id], - broadcastEnabled: true, - }).then((playbook) => { - playbookId = playbook.id; - }); - - // # Delete channel - cy.apiDeleteChannel(channel.id); - }); - }).then(() => { - cy.apiLogin(testUser); - - // # Create a new playbook run with the playbook. - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that there is an error message from the bot - cy.getLastPostId().then((id) => { - cy.get(`#postMessageText_${id}`). - contains('Failed to broadcast run creation to the configured channel.'); - }); - }); - }); - }); - - describe('creation webhook setting', () => { - it('with webhook correctly configured and setting enabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a playbook with a correct webhook and the setting enabled - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - webhookOnCreationURLs: ['https://httpbin.org/post'], - webhookOnCreationEnabled: true, - }).then((playbook) => { - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - description: 'Playbook run description.', - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the bot has not posted a message informing of the failure to send the webhook - cy.getLastPostId().then((lastPostId) => { - cy.get(`#postMessageText_${lastPostId}`). - should('not.contain', 'Playbook run creation announcement through the outgoing webhook failed. Contact your System Admin for more information.'); - }); - }); - }); - }); - }); - - describe('when a playbook run is finished', () => { - it('retrospective is disabled', () => { - const playbookName = 'Playbook (' + Date.now() + ')'; - - // # Create a new playbook run with that playbook - const now = Date.now(); - const playbookRunName = `Run (${now})`; - const playbookRunChannelName = `run-${now}`; - - // # Create a playbook with the disabled retrospective functionality - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookName, - createPublicPlaybookRun: true, - memberIDs: [testUser.id], - retrospectiveEnabled: false, - }).then((playbook) => { - // # Run playbook - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - }).then((playbookRun) => { - // # End the playbook run - cy.apiFinishRun(playbookRun.id); - }); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that playbook run finished message was posted - cy.findAllByTestId('postView').contains(`marked ${playbookName} as finished`); - - // * Verify that retrospective dialog was not posted - cy.findAllByTestId('retrospective-reminder').should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/post_type_components_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/post_type_components_spec.js deleted file mode 100644 index 52648693ce..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/post_type_components_spec.js +++ /dev/null @@ -1,173 +0,0 @@ -// 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 > post type components', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testChannel; - let testPlaybookRun; - - beforeEach(() => { - cy.apiAdminLogin(); - - cy.apiInitSetup({loginAfter: true}).then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - }).then((playbook) => { - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: 'Test Run', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testPlaybookRun = playbookRun; - }); - }); - - cy.apiCreateChannel( - testTeam.id, - 'other-channel', - 'Other Channel', - 'O', - ).then(({channel}) => { - testChannel = channel; - }); - }); - }); - - describe('update post (custom_run_update)', () => { - it('displays in run channel', () => { - // # Go to the playbook run channel - cy.visit(`/${testTeam.name}/channels/test-run`); - - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Post a status update - cy.apiUpdateStatus({ - playbookRunId: testPlaybookRun.id, - message: 'status update', - reminder: 60, - }); - - // Grab the post id - cy.getLastPostId().then((postId) => { - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'run_status_update', - type: 'page', - properties: { - post_id: postId, - playbook_run_id: testPlaybookRun.id, - channel_type: 'O', - }, - }, - ]); - }); - }); - - it('displays when permalinked in a different channel', () => { - // # Go to the playbook run channel - cy.visit(`/${testTeam.name}/channels/test-run`); - - // # Post a status update - cy.apiUpdateStatus({ - playbookRunId: testPlaybookRun.id, - message: 'status update', - reminder: 60, - }); - - // Grab the post id - cy.getLastPostId().then((postId) => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Go to the other channel - cy.visit(`/${testTeam.name}/channels/${testChannel.name}`); - - // # Post a permalink to the status update - cy.uiPostMessageQuickly(`${Cypress.config('baseUrl')}/${testTeam.name}/pl/${postId}`); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'run_status_update', - type: 'page', - properties: { - post_id: postId, - playbook_run_id: testPlaybookRun.id, - channel_type: 'O', - }, - }, - ]); - - cy.getLastPost().then((element) => { - // # Verify the expected message text - cy.get(element).contains(`${testUser.username} posted an update for ${testPlaybookRun.name}`); - cy.get(element).contains('status update'); - }); - }); - }); - - it('displays when permalinked in a different channel, even if not a member of the original channel', () => { - // # Go to the playbook run channel - cy.visit(`/${testTeam.name}/channels/test-run`); - - // # Post a status update - cy.apiUpdateStatus({ - playbookRunId: testPlaybookRun.id, - message: 'status update', - reminder: 60, - }); - - cy.getLastPostId().then((postId) => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Leave the playbook run channel - cy.uiLeaveChannel(); - - // # Go to the other channel - cy.visit(`/${testTeam.name}/channels/${testChannel.name}`); - - // # Post a permalink to the status update - cy.uiPostMessageQuickly(`${Cypress.config('baseUrl')}/${testTeam.name}/pl/${postId}`); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'run_status_update', - type: 'page', - properties: { - post_id: postId, - playbook_run_id: testPlaybookRun.id, - channel_type: '', - }, - }, - ]); - - cy.getLastPost().then((element) => { - // # Verify the expected message text - cy.get(element).contains(`${testUser.username} posted an update for ${testPlaybookRun.name}`); - cy.get(element).contains('status update'); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/retrospective_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/retrospective_spec.js deleted file mode 100644 index f8541a9061..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/retrospective_spec.js +++ /dev/null @@ -1,242 +0,0 @@ -// 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('runs > retrospective', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybookWithMetrics; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create playbook with metrics - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook with metrics', - memberIDs: [], - createPublicPlaybookRun: true, - metrics: [ - { - title: 'Time to acknowledge', - description: 'some description text', - type: 'metric_duration', - target: 7200000, - }, - { - title: 'Cost', - description: 'Cost of some events', - type: 'metric_currency', - target: 400, - }, - { - title: 'Number of customers', - description: 'Number of customers who had issues', - type: 'metric_integer', - target: 30, - }, - { - title: 'Duration', - description: 'Duration of incident', - type: 'metric_duration', - }, - ], - }).then((playbook) => { - testPlaybookWithMetrics = playbook; - }); - }); - - describe('runs with metrics', () => { - let runId; - let runName; - let playbookRunChannelName; - - beforeEach(() => { - // # Create a new playbook run - const now = Date.now(); - runName = `Run (${now})`; - playbookRunChannelName = `run-${now}`; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybookWithMetrics.id, - playbookRunName: runName, - ownerUserId: testUser.id, - createPublicPlaybookRun: true, - }).then((run) => { - runId = run.id; - }); - }); - - describe('publish retrospective', () => { - it('retrospective with 4 key metrics', () => { - // # Navigate directly to the retro tab - cy.visit(`/playbooks/runs/${runId}/retrospective`); - - // * Verify metrics number - cy.getStyledComponent('InputContainer').should('have.length', 4); - - // # Enter metrics values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('00:11:10'). - tab().type('560'). - tab().type('12'). - tab().type('14:00:59'); - - // # Publish retrospective - publishRetro(); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify channel retro post content - cy.findAllByTestId('postView').last().contains(`Retrospective for ${runName} has been published by`); - cy.getStyledComponent('MetricInfo').should('have.length', 4); - cy.getStyledComponent('MetricInfo').eq(0).contains('11 hours, 10 minutes'); - cy.getStyledComponent('MetricInfo').eq(1).contains('560'); - cy.getStyledComponent('MetricInfo').eq(2).contains('12'); - cy.getStyledComponent('MetricInfo').eq(3).contains('14 days, 59 minutes'); - }); - - it('retrospective with 3 key metrics', () => { - // # Remove first metric, leave only 3 - testPlaybookWithMetrics.metrics.splice(0, 1); - cy.apiUpdatePlaybook(testPlaybookWithMetrics).then(() => { - // # Navigate directly to the retro tab - cy.visit(`/playbooks/runs/${runId}/retrospective`); - - // * Verify metrics number - cy.getStyledComponent('InputContainer').should('have.length', 3); - - // # Enter metrics values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('43'). - tab().type('121'). - tab().type('11:00:02'); - - // # Publish retrospective - publishRetro(); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify channel retro post content - cy.findAllByTestId('postView').last().contains(`Retrospective for ${runName} has been published by`); - cy.getStyledComponent('MetricInfo').should('have.length', 3); - cy.getStyledComponent('MetricInfo').eq(0).contains('43'); - cy.getStyledComponent('MetricInfo').eq(1).contains('121'); - cy.getStyledComponent('MetricInfo').eq(2).contains('11 days, 2 minutes'); - }); - }); - - it('retrospective with 2 key metrics', () => { - // # Remove first two metrics, leave only 2 - testPlaybookWithMetrics.metrics.splice(0, 2); - cy.apiUpdatePlaybook(testPlaybookWithMetrics).then(() => { - // # Navigate directly to the retro tab - cy.visit(`/playbooks/runs/${runId}/retrospective`); - - // * Verify metrics number - cy.getStyledComponent('InputContainer').should('have.length', 2); - - // # Enter metrics values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('0'). - tab().type('00:04:02'); - - // # Publish retrospective - publishRetro(); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify channel retro post content - cy.findAllByTestId('postView').last().contains(`Retrospective for ${runName} has been published by`); - cy.getStyledComponent('MetricInfo').should('have.length', 2); - cy.getStyledComponent('MetricInfo').eq(0).contains('0'); - cy.getStyledComponent('MetricInfo').eq(1).contains('4 hours, 2 minutes'); - }); - }); - - it('retrospective with 1 key metrics', () => { - // # Remove first 3 metrics, leave only 1 - testPlaybookWithMetrics.metrics.splice(0, 3); - cy.apiUpdatePlaybook(testPlaybookWithMetrics).then(() => { - // # Navigate directly to the retro tab - cy.visit(`/playbooks/runs/${runId}/retrospective`); - - // * Verify metrics number - cy.getStyledComponent('InputContainer').should('have.length', 1); - - // # Enter metrics values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('00:00:00'); - - // # Publish retrospective - publishRetro(); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify channel retro post content - cy.findAllByTestId('postView').last().contains(`Retrospective for ${runName} has been published by`); - cy.getStyledComponent('MetricInfo').should('have.length', 1); - cy.getStyledComponent('MetricInfo').eq(0).contains('0 seconds'); - }); - }); - - it('retrospective with no metrics', () => { - // # Remove all metrics - testPlaybookWithMetrics.metrics.splice(0, 4); - cy.apiUpdatePlaybook(testPlaybookWithMetrics).then(() => { - // # Navigate directly to the retro tab - cy.visit(`/playbooks/runs/${runId}/retrospective`); - - // * Verify there are no metrics inputs - cy.getStyledComponent('InputContainer').should('not.exist'); - - // # Publish retrospective - publishRetro(); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify channel retro post content - cy.findAllByTestId('postView').last().contains(`Retrospective for ${runName} has been published by`); - cy.getStyledComponent('MetricInfo').should('not.exist'); - }); - }); - }); - }); -}); - -const publishRetro = () => { - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - - cy.get('#confirm-modal-light').within(() => { - // * Verify we're showing the publish retro confirmation modal - cy.findByText('Are you sure you want to publish?'); - - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - }); -}; diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/about_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/about_spec.js deleted file mode 100644 index 7e6465ee17..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/about_spec.js +++ /dev/null @@ -1,132 +0,0 @@ -// 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 > rhs > header', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - let testPlaybookRun; - let playbookRunChannelName; - let playbookRunName; - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Run the 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, - }).then((run) => { - testPlaybookRun = run; - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - }); - - describe('shows name', () => { - it('of active playbook run', () => { - // * Verify the title is displayed - cy.get('#rhsContainer').contains(playbookRunName); - }); - - it('of renamed playbook run', () => { - // * Verify the existing title is displayed - cy.get('#rhsContainer').contains(playbookRunName); - - // # Rename the channel - cy.apiPatchChannel(testPlaybookRun.channel_id, { - id: testPlaybookRun.channel_id, - display_name: 'Updated', - }); - - // * Verify the updated title is displayed - cy.get('#rhsContainer').contains(playbookRunName); - }); - }); - - describe('edit run name', () => { - it('by clicking on name', () => { - cy.get('#rhsContainer').findByTestId('rendered-run-name').should('be.visible').click(); - - // # type text in textarea - cy.get('#rhsContainer').findByTestId('textarea-run-name').should('be.visible').clear().type('new run name{ctrl+enter}'); - - // * make sure the updated name is here - cy.get('#rhsContainer').findByTestId('rendered-run-name').should('be.visible').contains('new run name'); - - // * make sure the channel name remains unchanged - cy.get('#channelHeaderInfo').contains(playbookRunName); - }); - }); - - describe('edit summary', () => { - it('by clicking on placeholder', () => { - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').click(); - - // # type text in textarea - cy.get('#rhsContainer').findByTestId('textarea-description').should('be.visible').type('new summary{ctrl+enter}'); - - // * make sure the updated summary is here - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').contains('new summary'); - }); - - it('by clicking on dot menu item', () => { - // # click on the field - cy.get('#rhsContainer').within(() => { - cy.findByTestId('buttons-row').invoke('show').within(() => { - cy.findAllByRole('button').eq(1).click(); - }); - }); - - cy.findByText('Edit run summary').click({force: true}); - - // # type text in textarea - cy.focused().should('be.visible').type('new summary{ctrl+enter}'); - - // * make sure the updated summary is here - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').contains('new summary'); - }); - }); - - describe('participate', () => { - it('icon is not visible if I am a participant', () => { - // * assert icon is not visible if I'm participant - cy.get('#rhsContainer').findByTestId('rhs-participate-icon').should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/checklist_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/checklist_spec.js deleted file mode 100644 index b4b2611caf..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/checklist_spec.js +++ /dev/null @@ -1,489 +0,0 @@ -// 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 {HALF_SEC, ONE_SEC} from '../../../../fixtures/timeouts'; - -describe('channels > rhs > checklist', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreatePlaybook({ - teamId: team.id, - title: 'Playbook', - checklists: [ - { - title: 'Stage 1', - items: [ - {title: 'Step 1', command: '/invalid'}, - {title: 'Step 2', command: '/echo VALID'}, - {title: 'Step 3', command: '/playbook check 0 0'}, - {title: 'Step 4'}, - {title: 'Step 5'}, - {title: 'Step 6'}, - {title: 'Step 7'}, - {title: 'Step 8'}, - {title: 'Step 9'}, - {title: 'Step 10'}, - {title: 'Step 11'}, - {title: 'Step 12'}, - ], - }, - { - title: 'Stage 2', - items: [ - {title: 'Step 1', command: '/invalid'}, - {title: 'Step 2', command: '/echo VALID'}, - {title: 'Step 3'}, - {title: 'Step 4'}, - {title: 'Step 5'}, - {title: 'Step 6'}, - {title: 'Step 7'}, - {title: 'Step 8'}, - {title: 'Step 9'}, - {title: 'Step 10'}, - {title: 'Step 11'}, - {title: 'Step 12'}, - ], - }, - { - title: 'Stage 3', - items: [ - {title: 'Step 1', command: '/invalid'}, - {title: 'Step 2', command: '/echo VALID'}, - {title: 'Step 3'}, - {title: 'Step 4'}, - {title: 'Step 5'}, - {title: 'Step 6'}, - {title: 'Step 7'}, - {title: 'Step 8'}, - {title: 'Step 9'}, - {title: 'Step 10'}, - {title: 'Step 11'}, - {title: 'Step 12'}, - ], - }, - { - title: 'Stage 3', - items: [ - {title: 'Step 1', command: '/invalid'}, - {title: 'Step 2', command: '/echo VALID'}, - {title: 'Step 3'}, - {title: 'Step 4'}, - {title: 'Step 5'}, - {title: 'Step 6'}, - {title: 'Step 7'}, - {title: 'Step 8'}, - {title: 'Step 9'}, - {title: 'Step 10'}, - {title: 'Step 11'}, - {title: 'Step 12'}, - ], - }, - ], - memberIDs: [ - user.id, - ], - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - // // # Switch to clean display mode - // cy.apiSaveMessageDisplayPreference('clean'); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Size the viewport to task list without scrolling issues - cy.viewport('macbook-13'); - }); - - describe('rhs stuff', () => { - let playbookRunName; - let playbookRunChannelName; - - beforeEach(() => { - // # Run the 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, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify the playbook run RHS is open. - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText(playbookRunName).should('exist'); - }); - }); - - describe('header', () => { - it('has title', () => { - cy.get('#rhsContainer').within(() => { - cy.findByText('Tasks').should('exist'); - }); - }); - }); - - it('shows an ephemeral error when running an invalid slash command', () => { - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify the command has not yet been run. - cy.findAllByTestId('run').eq(0).should('have.text', 'Run'); - - // * Run the /invalid slash command - cy.findAllByTestId('run').eq(0).click(); - - // * Verify the command still has not yet been run. - cy.findAllByTestId('run').eq(0).should('have.text', 'Run'); - }); - - // * Verify the expected error message. - cy.verifyEphemeralMessage('Failed to execute slash command /invalid'); - }); - - it('successfully runs a valid slash command', () => { - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify the command has not yet been run. - cy.findAllByTestId('run').eq(1).should('have.text', 'Run'); - - // * Run the /invalid slash command - cy.findAllByTestId('run').eq(1).click(); - - // * Verify the command has now been run. - cy.findAllByTestId('run').eq(1).should('have.text', 'Rerun'); - }); - - // # Verify the expected output. - cy.verifyPostedMessage('VALID'); - }); - - it('still shows slash commands as having been run after reload', () => { - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify the command has not yet been run. - cy.findAllByTestId('run').eq(1).should('have.text', 'Run'); - - // * Run the /invalid slash command - cy.findAllByTestId('run').eq(1).click(); - - // * Verify the command has now been run. - cy.findAllByTestId('run').eq(1).should('have.text', 'Rerun'); - }); - - // # Verify the expected output. - cy.verifyPostedMessage('VALID'); - - // # Reload the page - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify the invalid command still has not yet been run. - cy.findAllByTestId('run').eq(0).should('have.text', 'Run'); - - // * Verify the valid command has been run. - cy.findAllByTestId('run').eq(1).should('have.text', 'Rerun'); - }); - }); - - it('runs /playbook slash commands', () => { - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify the `/playbook check 0 0` command has not yet been run. - cy.findAllByTestId('run').eq(2).should('have.text', 'Run'); - - // * Run the slash command - cy.findAllByTestId('run').eq(2).click(); - - // * Verify the command has now been run. - cy.findAllByTestId('run').eq(2).should('have.text', 'Rerun'); - - // * Verify the first checklist item is checked - cy.findAllByTestId('checkbox-item-container').eq(0).within(() => { - // # Check the overdue task - cy.get('input').should('be.checked'); - }); - }); - - // # Reload the page - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify the command has still been run. - cy.findAllByTestId('run').eq(2).should('have.text', 'Rerun'); - - // * Verify the first checklist item is still checked - cy.findAllByTestId('checkbox-item-container').eq(0).within(() => { - // # Check the overdue task - cy.get('input').should('be.checked'); - }); - }); - }); - - it('can skip and restore task', () => { - // # Skip task and verify - skipTask(0); - - // # Hover over the checklist item - cy.findAllByTestId('checkbox-item-container').eq(0).trigger('mouseover'); - - // # Click dot menu - cy.findAllByTestId('checkbox-item-container').eq(0).within(() => { - cy.findByTitle('More').click(); - }); - - // # Click the restore button - cy.findByRole('button', {name: 'Restore task'}).click(); - - // * Verify the item has been restored - cy.findAllByTestId('checkbox-item-container').eq(0).within(() => { - cy.get('[data-cy=skipped]').should('not.exist'); - }); - }); - - it('add new task', () => { - const newTasktext = 'This is my new task' + Date.now(); - - cy.addNewTaskFromRHS(newTasktext); - - // Check that it was created - cy.findByText(newTasktext).should('exist'); - }); - - it('add new task slash command', () => { - const newTasktext = 'Task from slash command' + Date.now(); - - cy.uiPostMessageQuickly(`/playbook checkadd 0 ${newTasktext}`); - - // Check that it was created - cy.findByText(newTasktext).should('exist'); - }); - - it('creates a new checklist', () => { - // # Click on the button to add a checklist - cy.get('#rhsContainer').within(() => { - cy.findByTestId('add-a-checklist-button').click(); - }); - - // # Type a title and click on the Add button - const title = 'Checklist - ' + Date.now(); - cy.findByTestId('checklist-title-input').type(title); - cy.findByTestId('checklist-item-save-button').click(); - - // # Click on the button to add a checklist - cy.get('#rhsContainer').within(() => { - cy.findByText(title).should('exist'); - }); - }); - - it('renames a checklist', () => { - const oldTitle = 'Stage 1'; - const newTitle = 'New title - ' + Date.now(); - - // # Open the dot menu and click on the rename button - cy.get('#rhsContainer').within(() => { - cy.findByText(oldTitle).trigger('mouseover'); - cy.findAllByTestId('checklistHeader').eq(0).within(() => { - cy.findByTitle('More').click(); - }); - }); - cy.findByTestId('dropdownmenu').findByText('Rename checklist').click(); - - // # Type the new title and click the confirm button - cy.findByTestId('checklist-title-input').type(newTitle); - cy.findByTestId('checklist-item-save-button').click(); - - // * Verify that the checklist changed its name - cy.get('#rhsContainer').within(() => { - cy.findByText(oldTitle).should('not.exist'); - cy.findByText(oldTitle + newTitle).should('exist'); - }); - }); - - it('can set due date, from hover menu', () => { - // # Set due date and verify - setTaskDueDate(6, 'in 10 minutes'); - }); - - it('can set due date, from edit mode', () => { - // # Hover over the checklist item - cy.findAllByTestId('checkbox-item-container').eq(6).trigger('mouseover'); - - // # Click the edit button - cy.findAllByTestId('hover-menu-edit-button').eq(0).click(); - - cy.findAllByTestId('due-date-info-button').eq(0).click(); - - // # Enter due date in 3 days - cy.get('.playbook-react-select__value-container').type('in 3 days'). - wait(HALF_SEC). - trigger('keydown', { - key: 'Enter', - }); - - // * Verify if Due in 3 days info is added - cy.findAllByTestId('due-date-info-button').eq(0).should('exist').within(() => { - cy.findByText('in 3 days').should('exist'); - cy.findByText('Due').should('exist'); - }); - }); - - it('filter overdue tasks', {retries: {runMode: 3}}, () => { - // # Set overdue date for several items - setTaskDueDate(2, '1 hour ago'); - - setTaskDueDate(3, '7 hours ago', 1); - setTaskDueDate(5, '3 hours ago', 2); - setTaskDueDate(6, '6 hours ago', 3); - - // # Skip task - skipTask(3); - - // # Mark a task as completed - cy.findAllByTestId('checkbox-item-container').eq(5).within(() => { - // # Check the overdue task - cy.get('input').click(); - }); - - // * Verify if overdue tasks info was added. Should not include skipped / completed tasks. - cy.findAllByTestId('overdue-tasks-filter').eq(0).should('exist').within(() => { - cy.findByText('2 tasks overdue').should('exist'); - }); - - // # Filter overdue tasks - cy.findAllByTestId('overdue-tasks-filter').eq(0).click(); - - // * Verify if filter works. Should not include skipped / completed tasks. - cy.findAllByTestId('checkbox-item-container').should('have.length', 2); - - // # Cancel filter overdue tasks - cy.findAllByTestId('overdue-tasks-filter').eq(0).click(); - - // * Verify if filter was canceled - cy.findAllByTestId('checkbox-item-container').should('have.length', 48); - }); - - it('filter overdue automatically disappear if we check all overdue items', () => { - // # Set due date - setTaskDueDate(2, '1 minute ago'); - - // * Verify if overdue tasks info was added - cy.findAllByTestId('overdue-tasks-filter').eq(0).should('exist').within(() => { - cy.findByText('1 task overdue').should('exist'); - }); - - // # Filter overdue tasks - cy.findAllByTestId('overdue-tasks-filter').eq(0).click(); - - // * Verify if filter works - cy.findAllByTestId('checkbox-item-container').should('have.length', 1); - - // # Mark a task as completed - cy.findAllByTestId('checkbox-item-container').within(() => { - // # Check the overdue task - cy.get('input').click(); - }); - - // * Verify there is no filter - cy.findAllByTestId('overdue-tasks-filter').should('not.exist'); - - // * Verify if filter was canceled - cy.findAllByTestId('checkbox-item-container').should('have.length', 48); - }); - - it('switching between runs with the same checklist', () => { - // # Create another run using the same playbook - const playbookRunName2 = 'RunWithSameChecklist'; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: playbookRunName2, - ownerUserId: testUser.id, - }); - - // # Set due date for the first channel's task - setTaskDueDate(2, 'in 2 hours'); - - // # Switch to the second run channel - cy.get('#sidebarItem_runwithsamechecklist').click(); - - // * Verify that tasks do not have due dates - cy.findAllByTestId('checkbox-item-container').eq(2).within(() => { - cy.findAllByTestId('due-date-info-button').should('not.exist'); - }); - }); - - it('scroll 2-3 pages and open due date selector- unexpected scroll issue', () => { - // # Hover over the checklist item that is ~3 pages down - cy.findAllByTestId('checkbox-item-container').eq(26).trigger('mouseover').within(() => { - // # Click the set due date button - cy.get('.icon-calendar-outline').click(); - }); - - // * Verify if date selector is visible - cy.get('.playbook-react-select').should('be.visible'); - }); - }); -}); - -const setTaskDueDate = (taskIndex, dateQuery, offset = 0) => { - // # Hover over the checklist item - cy.findAllByTestId('checkbox-item-container').eq(taskIndex).trigger('mouseover').within(() => { - // # Click the set due date button - cy.get('.icon-calendar-outline').click(); - }); - - // # Wait for react select to finish rendering. - cy.wait(ONE_SEC); - - // # Enter due date query - cy.get('.playbook-react-select').within(() => { - cy.get('input').type(dateQuery, {force: true}). - wait(HALF_SEC). - trigger('keydown', { - key: 'Enter', - }); - }); - - // * Verify if Due date info is added - cy.findAllByTestId('due-date-info-button').eq(offset).should('exist').within(() => { - cy.findByText(dateQuery).should('exist'); - cy.findByText('Due').should('exist'); - }); -}; - -const skipTask = (taskIndex) => { - // # Hover over the checklist item - cy.findAllByTestId('checkbox-item-container').eq(taskIndex).trigger('mouseover'); - - // # Click dot menu - cy.findAllByTestId('checkbox-item-container').eq(taskIndex).within(() => { - cy.findByTitle('More').click(); - }); - - // # Click the skip button - cy.findByRole('button', {name: 'Skip task'}).click(); -}; diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/header_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/header_spec.js deleted file mode 100644 index 5ed1af22d2..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/header_spec.js +++ /dev/null @@ -1,225 +0,0 @@ -// 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 > rhs > header', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - }); - - describe('shows name', () => { - it('of active playbook run', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify the title is displayed - cy.get('#rhsContainer').contains(playbookRunName); - }); - - it('of renamed playbook run', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify the existing title is displayed - cy.get('#rhsContainer').contains(playbookRunName); - - // # Rename the channel - cy.apiPatchChannel(playbookRun.channel_id, { - id: playbookRun.channel_id, - display_name: 'Updated', - }); - - // * Verify the updated title is displayed - cy.get('#rhsContainer').contains(playbookRunName); - }); - }); - }); - - describe('edit summary', () => { - it('by clicking on placeholder', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # click on the field - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').click(); - - // # type text in textarea - cy.get('#rhsContainer').findByTestId('textarea-description').should('be.visible').type('new summary{ctrl+enter}'); - - // * make sure the updated summary is here - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').contains('new summary'); - - // * reload the page - cy.reload(); - - // * make sure the updated summary is still there - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').contains('new summary'); - }); - - it('by clicking on dot menu item', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # click on the field - cy.get('#rhsContainer').within(() => { - cy.findByTestId('buttons-row').invoke('show').within(() => { - cy.findAllByRole('button').eq(1).click(); - }); - }); - - cy.findByTestId('dropdownmenu').within(() => { - cy.get('span').should('have.length', 3); - cy.findByText('Edit run summary').click(); - }); - - // # type text in textarea - cy.focused().should('be.visible').type('new summary{ctrl+enter}'); - - // * make sure the updated summary is here - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').contains('new summary'); - }); - }); - - describe('edit summary of finished run', () => { - let playbookRunChannelName; - let finishedPlaybookRun; - - beforeEach(() => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - finishedPlaybookRun = playbookRun; - }); - }); - - it('by clicking on placeholder', () => { - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Wait for the RHS to open - cy.get('#rhsContainer').should('be.visible'); - - // # Mark the run as finished - cy.apiFinishRun(finishedPlaybookRun.id); - - // # click on the field - cy.get('#rhsContainer').findByTestId('rendered-description').should('be.visible').click(); - - // * Verify textarea does not appear - cy.get('#rhsContainer').findByTestId('textarea-description').should('not.exist'); - - // * Verify no prompt to join appears (timeout ensures it fails right away before toast disappears) - cy.findByText('Become a participant to interact with this run', {timeout: 500}).should('not.exist'); - }); - - it('by clicking on dot menu item', () => { - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Wait for the RHS to open - cy.get('#rhsContainer').should('be.visible'); - - // # Mark the run as finished - cy.apiFinishRun(finishedPlaybookRun.id); - - // # click on the field - cy.get('#rhsContainer').within(() => { - cy.findByTestId('buttons-row').invoke('show').within(() => { - cy.findAllByRole('button').eq(1).click(); - }); - }); - - // * Verify the menu items - cy.findByTestId('dropdownmenu').within(() => { - cy.get('span').should('have.length', 2); - cy.findByText('Edit run summary').should('not.exist'); - }); - - // * Verify no prompt to join appears (timeout ensures it fails right away before toast disappears) - cy.findByText('Become a participant to interact with this run', {timeout: 500}).should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/home_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/home_spec.js deleted file mode 100644 index 3c90348c32..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/home_spec.js +++ /dev/null @@ -1,159 +0,0 @@ -// 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 > rhs > home', {testIsolation: true}, () => { - let testSysadmin; - let testTeam; - let testUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateCustomAdmin().then(({sysadmin}) => { - testSysadmin = sysadmin; - }); - }); - }); - - describe('default permission settings', () => { - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Navigate to the application, starting in a non-run channel. - cy.visit(`/${testTeam.name}/`); - - // * Check time bar in the channel section - // * as an indicator of page stability / end of rendering - cy.findByText('Today').should('be.visible'); - }); - - describe('telemetry', () => { - it('track page view', () => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Click the icon - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // * Assert telemetry data - cy.expectTelemetryToContain([{name: 'channels_rhs_home', type: 'page'}]); - }); - }); - - describe('shows available', () => { - it('starter templates', () => { - // templates are defined in webapp/src/components/templates/template_data.tsx - const templates = [ - {name: 'Blank', checklists: '1 checklist', actions: '1 action'}, - {name: 'Product Release', checklists: '4 checklists', actions: '3 actions'}, - {name: 'Incident Resolution', checklists: '4 checklists', actions: '4 actions'}, - {name: 'Customer Onboarding', checklists: '4 checklists', actions: '3 actions'}, - {name: 'Employee Onboarding', checklists: '5 checklists', actions: '2 actions'}, - {name: 'Feature Lifecycle', checklists: '5 checklists', actions: '3 actions'}, - {name: 'Bug Bash', checklists: '5 checklists', actions: '3 actions'}, - {name: 'Learn how to use playbooks', checklists: '2 checklists', actions: '2 actions'}, - ]; - - // # Click the icon - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // * Verify the templates are shown - cy.findByText('Playbook Templates'). - parent(). - next(). - within(() => { - cy.findAllByTestId('template-details').each(($templateElement, index) => { - cy.wrap($templateElement).within(() => { - cy.findByText(templates[index].name).should('exist'); - cy.findByText(templates[index].checklists).should('exist'); - cy.findByText(templates[index].actions).should('exist'); - }); - }); - }); - }); - }); - - describe('show zero case if there are playbooks', () => { - beforeEach(() => { - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Team Playbook', - memberIDs: [], - }); - - // # Click the icon - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - }); - - it('without pre-populated channel name template', () => { - // * Verify the templates are not shown - cy.findAllByTestId('template-details').should('not.exist'); - - // * Verify the zero case is shown - cy.get('#sidebar-right').findByText('There are no runs in progress linked to this channel').should('be.visible'); - }); - }); - }); - - let restrictedTestTeam; - let restrictedTestUser; - - describe('user is lacking permissions to create playbooks', () => { - before(() => { - cy.apiLogin(testSysadmin); - - cy.apiCreateUser().then(({user}) => { - restrictedTestUser = user; - }); - - cy.apiCreateTeam('restricted-team', 'Restricted Team').then(({team}) => { - restrictedTestTeam = team; - cy.apiAddUserToTeam(restrictedTestTeam.id, restrictedTestUser.id); - }); - - cy.apiCreateScheme('Restricted Team Scheme', 'team').then(({scheme}) => { - cy.apiSetTeamScheme(restrictedTestTeam.id, scheme.id); - cy.apiGetRolesByNames([scheme.default_team_user_role]).then(({roles}) => { - const role = roles[0]; - - // Remove permissions to create playbooks - const permissions = role.permissions.filter((perm) => !(/playbook_(private|public)_create/).test(perm)); - cy.apiPatchRole(role.id, {permissions}); - }); - }); - }); - - beforeEach(() => { - // # Login as user with restricted permissions - cy.apiLogin(restrictedTestUser); - - // # Navigate to the application, starting in a non-run channel. - cy.visit(`/${restrictedTestTeam.name}/`); - }); - - it('permission notice should be shown and no create button should exist', () => { - // # Click the icon - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - cy.get('#sidebar-right').within(() => { - // * Verify notice about missing permissions exists - cy.findByText('You don\'t have permission to create playbooks in this workspace.').should('be.visible'); - - // * Verify create playbook button does not exist - cy.findByText('Create playbook').should('not.exist'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/list_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/list_spec.js deleted file mode 100644 index 138f447f19..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/list_spec.js +++ /dev/null @@ -1,263 +0,0 @@ -// 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 > rhs > runlist', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - let testChannel; - const numActiveRuns = 10; - const numFinishedRuns = 4; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'The playbook name', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - - // # Create a test channel - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel').then(({channel}) => { - testChannel = channel; - - // # Run the playbook a few times in the existing channel - for (let i = 0; i < numActiveRuns; i++) { - const runName = 'playbook-run-' + i; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - ownerUserId: testUser.id, - channelId: testChannel.id, - playbookRunName: runName, - }); - } - - // # Do it again but finished - for (let i = 0; i < numFinishedRuns; i++) { - const runName = 'playbook-run-' + i; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - ownerUserId: testUser.id, - channelId: testChannel.id, - playbookRunName: runName, - }).then((run) => { - cy.apiFinishRun(run.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/${testChannel.name}`); - - // # Wait the RHS to load - cy.findByText('Runs in progress').should('be.visible'); - }); - - it('track page view', () => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${testChannel.name}`); - - // * Assert telemetry data - cy.expectTelemetryToContain([{name: 'channels_rhs_runlist', type: 'page'}]); - }); - - it('can filter', () => { - // # Click the filter menu - cy.findByTestId('rhs-runs-filter-menu').click(); - - // * Verify displayed options - cy.get('[data-testid="dropdownmenu"] > :nth-child(1) > div').should('have.text', numActiveRuns); - cy.get('[data-testid="dropdownmenu"] > :nth-child(2) > div').should('have.text', numFinishedRuns); - - // # Click the filter - cy.get('[data-testid="dropdownmenu"] > :nth-child(2)').click(); - - // * Verify displayed options - cy.get('[data-testid="rhs-runs-list"]').children().should('have.length', numFinishedRuns); - }); - - it('can show more (pagination)', () => { - // * Verify we have the first page - cy.get('[data-testid="rhs-runs-list"] > div').should('have.length', 8); - - // # CLick in the show-more button - cy.get('[data-testid="rhs-runs-list"] > button').click(); - - // * Verify we have loaded the second page - cy.get('[data-testid="rhs-runs-list"] > div').should('have.length', 10); - }); - - it('card has the basic info', () => { - // # Click the first run - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1)').within(() => { - cy.findByText('playbook-run-9').should('be.visible'); - cy.findByText('The playbook name').should('be.visible'); - cy.findByText(testUser.username).should('be.visible'); - }); - }); - - it('can click though', () => { - // # Click the first run - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1)').click(); - - // * Verify we made it to the run details at Channels RHS - cy.get('#rhsContainer').contains('playbook-run-9'); - cy.get('#rhsContainer').contains('Tasks'); - }); - - it('can see give feedback button', () => { - // * Verify give feedback button exists and has the right URL - cy.get('#rhsContainer').findByText('Give feedback'). - should('exist'). - and('have.attr', 'href'). - and('include', 'https://mattermost.com/pl/playbooks-feedback'); - }); - - describe('dotmenu', () => { - it('can navigate to RDP', () => { - // # Click the first run's dotmenu - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1)').findByRole('button').click(); - - // # Click on go to run - cy.findByText('Go to run overview').click(); - - // * Assert we are in the run details page - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=channel_rhs_dotmenu'); - }); - - it('can navigate to PBE', () => { - // # Click the first run's dotmenu - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1)').findByRole('button').click(); - - // # Click on go to polaybook - cy.findByText('Go to playbook').click(); - - // * Assert we are in the PBE page - cy.url().should('include', `/playbooks/${testPlaybook.id}`); - }); - - it('can change run name', () => { - // # Click on the kebab menu - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1) .icon-dots-vertical').click(); - - // # Click on the rename run option - cy.findByText('Rename run').click(); - - // # type new name - cy.findByTestId('run-name-input').clear().type('My cool new run name'); - - // # click save - cy.findByTestId('modal-confirm-button').click(); - - // * Verify the name has changed - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1)').contains('My cool new run name'); - }); - - it('can change linked channel', () => { - // # Click on the kebab menu - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1) .icon-dots-vertical').click(); - - // # Click on the rename run option - cy.findByText('Link run to a different channel').click(); - - // # type new name - cy.get('.modal-body').within(() => { - // # select town square - cy.findByText(testChannel.display_name).click().type('Town Square{enter}'); - }); - - // # click save - cy.findByTestId('modal-confirm-button').click(); - - // Let the listing refresh - cy.wait(1000); - - // * Verify we have the first page - cy.get('[data-testid="rhs-runs-list"] > div').should('have.length', 8); - - // # CLick in the show-more button - cy.get('[data-testid="rhs-runs-list"] > button').click(); - - // * Verify the channel has changed, now one run less - cy.get('[data-testid="rhs-runs-list"] > div').should('have.length', 9); - }); - - describe('navigation', () => { - let testChannelWith2Runs; - before(() => { - cy.apiLogin(testUser); - - // # Create a test channel - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel').then(({channel}) => { - testChannelWith2Runs = channel; - - // # Run the playbook a few times in the existing channel - for (let i = 0; i < 2; i++) { - const runName = 'playbook-run-' + i; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - ownerUserId: testUser.id, - channelId: testChannelWith2Runs.id, - playbookRunName: runName, - }); - } - }); - }); - - it('stays at list even if one only linked run after moving run', () => { - // # Visit channel with 2 runs - cy.visit(`/${testTeam.name}/channels/${testChannelWith2Runs.name}`); - - // # Click on the kebab menu - cy.get('[data-testid="rhs-runs-list"] > :nth-child(1) .icon-dots-vertical').click(); - - // # Click on the rename run option - cy.findByText('Link run to a different channel').click(); - - // # type new name - cy.get('.modal-body').within(() => { - // # select town square - cy.findByText(testChannelWith2Runs.display_name).click().type('Town Square{enter}'); - }); - - // # click save - cy.findByTestId('modal-confirm-button').click(); - - // * Verify the run is not there, but we are still in the list (not rhs details) - cy.get('[data-testid="rhs-runs-list"] > div').should('have.length', 1); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/start_run_rhs_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/start_run_rhs_spec.js deleted file mode 100644 index 29bcbbcb8f..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/start_run_rhs_spec.js +++ /dev/null @@ -1,589 +0,0 @@ -// 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) -// *************************************************************** - -// Group: @playbooks - -describe('channels rhs > start a run', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testChannel; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiCreateChannel(testTeam.id, 'existing-channel', 'Existing Channel').then(({channel}) => { - testChannel = channel; - }); - }); - - const createPlaybook = ({channelNameTemplate, runSummaryTemplate, channelId, channelMode, title}) => { - const runSummaryTemplateEnabled = Boolean(runSummaryTemplate); - - // # Create a public playbook - return cy.apiCreatePlaybook({ - title: title || 'Public Playbook', - channelNameTemplate, - runSummaryTemplate, - runSummaryTemplateEnabled, - channelMode, - channelId, - teamId: testTeam.id, - makePublic: true, - memberIDs: [testUser.id], - createPublicPlaybookRun: true, - }).then((playbook) => { - cy.wrap(playbook); - }); - }; - - describe('From RHS run list > ', () => { - beforeEach(() => { - // # intercepts telemetry - cy.interceptTelemetry(); - }); - - describe('playbook configured as create new channel', () => { - it('defaults', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'create_new_channel', - }).then((playbook) => { - // # Visit the selected playbook - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is filled - cy.findByTestId('run-name-input').should('have.value', 'Channel template'); - - // * Assert summary template is filled - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([{ - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'channels_rhs_runlist', - playbookId: playbook.id, - channelMode: 'create_new_channel', - public: true, - hasPlaybookChanged: true, - hasNameChanged: false, - hasSummaryChanged: false, - hasChannelModeChanged: false, - hasChannelIdChanged: false, - hasPublicChanged: false, - }}, - ], {waitForCalls: 2}); - - // * Verify we are on the channel just created - cy.url().should('include', `/${testTeam.name}/channels/channel-template`); - - // * Verify channel name - cy.get('h2').contains('Beginning of Channel template'); - - // * Verify run RHS - cy.get('#rhsContainer').should('exist').within(() => { - cy.contains('Channel template'); - cy.contains('run summary template'); - }); - }); - }); - - it('change title/summary', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'create_new_channel', - }).then((playbook) => { - // # Visit the selected playbook - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // * Assert template are filled (and force wait to them) - cy.findByTestId('run-name-input').should('have.value', 'Channel template'); - - // * Assert summary template is filled - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Fill run summary - cy.findByTestId('run-summary-input').clear().type('Test Run Summary'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([{ - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'channels_rhs_runlist', - playbookId: playbook.id, - channelMode: 'create_new_channel', - public: true, - hasPlaybookChanged: true, - hasNameChanged: true, - hasSummaryChanged: true, - hasChannelModeChanged: false, - hasChannelIdChanged: false, - hasPublicChanged: false, - }}, - ]); - - // * Verify we are on the channel just created - cy.url().should('include', `/${testTeam.name}/channels/test-run-name`); - - // * Verify channel name - cy.get('h2').contains('Beginning of Test Run Name'); - - // * Verify run RHS - cy.get('#rhsContainer').should('exist').within(() => { - cy.contains('Test Run Name'); - cy.contains('Test Run Summary'); - }); - }); - }); - - it('change to link to existing channel defaults to current channel', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'create_new_channel', - }).then((playbook) => { - // # Visit the town square channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // # Change to link to existing channel - cy.findByTestId('link-existing-channel-radio').click(); - - // * Assert current channel is selected - cy.findByText('Town Square').should('be.visible'); - }); - }); - }); - - it('change to link to existing channel with already selected channel', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'create_new_channel', - channelId: testChannel.id, - }).then((playbook) => { - // # Visit the town square channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // # Change to link to existing channel - cy.findByTestId('link-existing-channel-radio').click(); - - // * Assert selected channel is unchanged - cy.findByText(testChannel.display_name).should('be.visible'); - }); - }); - }); - - it('change to link to existing channel', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'create_new_channel', - }).then((playbook) => { - // # Visit the selected playbook - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // # Change to link to existing channel - cy.findByTestId('link-existing-channel-radio').click(); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Select test channel instead of current channel - cy.findByText('Town Square').click().type(`${testChannel.display_name}{enter}`); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([{ - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'channels_rhs_runlist', - playbookId: playbook.id, - channelMode: 'link_existing_channel', - hasPlaybookChanged: true, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: true, - hasChannelIdChanged: true, - hasPublicChanged: false, - }}, - ]); - - // * Verify we are on the existing channel - cy.url().should('include', `/${testTeam.name}/channels/${testChannel.name}`); - - // * Verify channel name - cy.get('h2').contains(`Beginning of ${testChannel.display_name}`); - - // * Verify run RHS - cy.get('#rhsContainer').should('exist').within(() => { - cy.contains('Test Run Name'); - cy.contains('run summary template'); - }); - }); - }); - }); - - describe('playbook configured as linked to existing channel', () => { - it('defaults', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'link_existing_channel', - channelId: testChannel.id, - }).then((playbook) => { - // # Visit the selected playbook - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is empty - cy.findByTestId('run-name-input').should('be.empty'); - - // * Assert template summary is filled - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([{ - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'channels_rhs_runlist', - playbookId: playbook.id, - channelMode: 'link_existing_channel', - hasPlaybookChanged: true, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: false, - hasChannelIdChanged: false, - hasPublicChanged: false, - }}, - ]); - - // * Verify we are on the existing channel - cy.url().should('include', `/${testTeam.name}/channels/${testChannel.name}`); - - // * Verify channel name - cy.get('h2').contains(`Beginning of ${testChannel.display_name}`); - - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify run RHS - cy.contains('Test Run Name'); - cy.contains('run summary template'); - }); - }); - }); - - it('fill initially empty channel', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'link_existing_channel', - }).then((playbook) => { - // # Visit the selected playbook - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is empty - cy.findByTestId('run-name-input').should('be.empty'); - - // * Assert template summary is filled - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Fill Town square as the channel to be linked - cy.findByText('Select a channel').click().type(`${testChannel.display_name}{enter}`); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([{ - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'channels_rhs_runlist', - playbookId: playbook.id, - channelMode: 'link_existing_channel', - hasPlaybookChanged: true, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: false, - hasChannelIdChanged: true, - hasPublicChanged: false, - }}, - ]); - - // * Verify we are on the existing channel - cy.url().should('include', `/${testTeam.name}/channels/${testChannel.name}`); - - // * Verify channel name - cy.get('h2').contains(`Beginning of ${testChannel.display_name}`); - - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify run RHS - cy.contains('Test Run Name'); - cy.contains('run summary template'); - }); - }); - }); - - it('change to create new channel', () => { - // # Fill default values - createPlaybook({ - title: 'Playbook title' + Date.now(), - channelNameTemplate: 'Channel template', - runSummaryTemplate: 'run summary template', - channelMode: 'link_existing_channel', - channelId: testChannel.id, - }).then((playbook) => { - // # Visit the selected playbook - cy.visit(`/${testTeam.name}/channels/town-square`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Click start a run button - cy.findByTestId('rhs-runlist-start-run').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert we are at playbooks tab - cy.findByText('Select a playbook').should('be.visible'); - - // # Click on the playbook - cy.findAllByText(playbook.title).eq(0).click(); - - // # Wait the modal to render - cy.wait(500); - - // # Change to create new channel - cy.findByTestId('create-channel-radio').click(); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([{ - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'channels_rhs_runlist', - playbookId: playbook.id, - channelMode: 'create_new_channel', - hasPlaybookChanged: true, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: true, - hasChannelIdChanged: false, - hasPublicChanged: false, - }}, - ]); - - // * Verify we are on the channel just created - cy.url().should('include', `/${testTeam.name}/channels/test-run-name`); - - // * Verify channel name - cy.get('h2').contains('Beginning of Test Run Name'); - - cy.get('#rhsContainer').should('exist').within(() => { - // * Verify run RHS - cy.contains('Test Run Name'); - cy.contains('run summary template'); - }); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/status_update_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/status_update_spec.js deleted file mode 100644 index 1467ab4b8c..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/status_update_spec.js +++ /dev/null @@ -1,495 +0,0 @@ -// 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) -// *************************************************************** - -// Group: @playbooks - -import * as TIMEOUTS from '../../../../fixtures/timeouts'; - -describe('channels > rhs > status update', {testIsolation: true}, () => { - const defaultReminderMessage = '# Default reminder message'; - let testTeam; - let testChannel; - let testUser; - let testPlaybook; - let testRun; - - before(() => { - cy.apiInitSetup().then(({team, channel, user}) => { - testTeam = team; - testChannel = channel; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - userId: testUser, - broadcastChannelIds: [testChannel.id], - reminderTimerDefaultSeconds: 3600, - reminderMessageTemplate: defaultReminderMessage, - retrospectiveEnabled: false, - broadcastEnabled: true, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a new playbook run - const now = Date.now(); - const name = 'Playbook Run (' + now + ')'; - const channelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: name, - ownerUserId: testUser.id, - }).then((run) => { - testRun = run; - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${channelName}`); - }); - - describe('post update dialog', () => { - it('renders description correctly', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Check description - cy.findByTestId('update_run_status_description').contains(`This update for the run ${testRun.name} will be broadcasted to one channel and one direct message.`); - }); - }); - - it('description link navigates to run overview', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # Click overview link - cy.findByTestId('run-overview-link').click(); - }); - - // * Check that we are now in run overview page - cy.url().should('include', `/playbooks/runs/${testRun.id}`); - - // * Check that the run actions modal is already opened - cy.findByRole('dialog', {name: /Run Actions/i}).should('exist'); - }); - - it('prevents posting an update message with only whitespace', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # Type the invalid data - cy.findByTestId('update_run_status_textbox').clear().type(' {enter} {enter} '); - - // * Verify submit is disabled. - cy.get('button.confirm').should('be.disabled'); - - // # 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'); - }); - - it('lets users with no access to the playbook post an update', () => { - let channelName; - const updateMessage = 'status update ' + Date.now(); - - // # Login as sysadmin and create a private playbook and a run - cy.apiAdminLogin().then(({user: sysadmin}) => { - // # Create a private playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook - Private', - memberIDs: [sysadmin.id], // Make it accesible only to sysadmin - inviteUsersEnabled: true, - invitedUserIds: [testUser.id], // Invite the test user - }).then((playbook) => { - // # Create a new playbook run - const now = Date.now(); - const name = 'Playbook Run (' + now + ')'; - channelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: name, - ownerUserId: sysadmin.id, - }).then((run) => { - cy.apiAddUsersToRun(run.id, [testUser.id]); - }); - }); - }).then(() => { - // # Login as the test user - cy.apiLogin(testUser); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${channelName}`); - - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # Enter valid data - cy.findByTestId('update_run_status_textbox').type(updateMessage); - - // # 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(updateMessage).should('exist'); - }); - }); - }); - - it('confirms finishing the run, and remembers changes and reminder when canceled', () => { - const updateMessage = 'This is the update text to test with.'; - const reminderTime = '1 day'; - - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Verify the first message is there. - cy.findByTestId('update_run_status_textbox').within(() => { - cy.findByText(defaultReminderMessage).should('exist'); - }); - - // # Type text to test for later - cy.findByTestId('update_run_status_textbox').clear().type(updateMessage); - - // # Set a new reminder to test for later - cy.openReminderSelector(); - cy.selectReminderTime(reminderTime); - - // # Mark the run as finished - cy.findByTestId('mark-run-as-finished').click({force: true}); - - // # Submit the dialog. - cy.get('button.confirm').click(); - }); - - // * Confirmation should appear - cy.get('.modal-header').should('be.visible').contains('Confirm finish run'); - - // # Cancel - cy.get('#cancelModalButton').click({force: true}); - - // * Verify post update has the same information - cy.getStatusUpdateDialog().within(() => { - // * Verify the message was remembered - cy.findByTestId('update_run_status_textbox').within(() => { - cy.findByText(updateMessage).should('exist'); - }); - - // * Verify the reminder was remembered - cy.get('#reminder_timer_datetime').contains(reminderTime); - - // * Marked run is still checked - cy.findByTestId('mark-run-as-finished').within(() => { - cy.get('[type="checkbox"]').should('be.checked'); - }); - - // # Submit the dialog. - cy.get('button.confirm').click(); - }); - - // * Confirmation should appear - cy.get('.modal-header').should('be.visible').contains('Confirm finish run'); - - // # Submit - cy.get('#confirmModalButton').click({force: true}); - - // * Verify the status update was posted. - cy.getStyledComponent('CustomPostContent').within(() => { - cy.findByText(updateMessage).should('exist'); - }); - - // * Verify the run was finished. - cy.getLastPost().contains(`@${testUser.username} marked ${testRun.name} as finished.`); - }); - - describe('prevents user from losing changes', () => { - it('cancel, go back and save', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # Type the invalid data - cy.findByTestId('update_run_status_textbox').clear().type('My valid and important changes that I don\'t want to lose'); - - // * Click cancel - cy.findByTestId('modal-cancel-button').click(); - }); - - // * Go back from unsaved changes modal - cy.get('#confirm-modal-light').within(() => { - cy.findByTestId('modal-cancel-button').click(); - }); - - // # Delay in between the modal switch to ensure the - // # animation has fully happened - cy.wait(TIMEOUTS.TWO_SEC); - - // # Submit the dialog. - cy.get('button.confirm').click(); - - // * Verify that the Post update and unsaved changes modals have gone. - cy.getStatusUpdateDialog().should('not.exist'); - cy.get('#confirm-modal-light').should('not.exist'); - }); - - it('click overview link, go back and save', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # Type the invalid data - cy.findByTestId('update_run_status_textbox').clear().type('My valid and important changes that I don\'t want to lose'); - - // # Click overview link - cy.findByTestId('run-overview-link').click(); - }); - - // Verify that the confirmation modal is shown - cy.get('#confirm-modal-light').within(() => { - // * Go back from unsaved changes modal - cy.findByTestId('modal-cancel-button').click(); - }); - - // # Delay in between the modal switch to ensure the - // # animation has fully happened - cy.wait(TIMEOUTS.TWO_SEC); - - // # Submit the dialog. - cy.get('button.confirm').click(); - - // * Verify that the Post update and unsaved changes modals have gone. - cy.getStatusUpdateDialog().should('not.exist'); - cy.get('#confirm-modal-light').should('not.exist'); - }); - - it('cancel and discard explicitly', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # Type the invalid data - cy.findByTestId('update_run_status_textbox').clear().type('My valid and important changes that I don\'t want to lose'); - - // * Click cancel - cy.findByTestId('modal-cancel-button').click(); - }); - - // * Discard explicitly from unsaved changes - cy.get('#confirm-modal-light').within(() => { - cy.get('button.confirm').click(); - }); - - // * Verify that the Post update and unsaved changes modals have gone. - cy.getStatusUpdateDialog().should('not.exist'); - cy.get('#confirm-modal-light').should('not.exist'); - }); - - it('click overview link and discard explicitly', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # Type the invalid data - cy.findByTestId('update_run_status_textbox').clear().type('My valid and important changes that I don\'t want to lose'); - - // # Click overview link - cy.findByTestId('run-overview-link').click(); - }); - - // * Discard explicitly from unsaved changes - cy.get('#confirm-modal-light').within(() => { - cy.get('button.confirm').click(); - }); - - // * Assert that we are at run overview page. - cy.url().should('include', `/playbooks/runs/${testRun.id}`); - - // * Verify that the Post update and unsaved changes modals have gone. - cy.getStatusUpdateDialog().should('not.exist'); - cy.get('#confirm-modal-light').should('not.exist'); - - // * Verify that the run actions modal is opened. - cy.findByRole('dialog', {name: /Run Actions/i}).should('exist'); - }); - }); - - describe('shows the last update in update message', () => { - it('shows the default when we have not made an update before', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Verify the first message is there. - cy.findByTestId('update_run_status_textbox').within(() => { - cy.findByText(defaultReminderMessage).should('exist'); - }); - }); - }); - - it('when we have made a previous update', () => { - const now = Date.now(); - const firstMessage = 'Update - ' + now; - - // # Create a first status update - cy.updateStatus(firstMessage); - - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Verify the first message is there. - cy.findByTestId('update_run_status_textbox').within(() => { - cy.findByText(firstMessage).should('exist'); - }); - }); - }); - }); - }); - - describe('the default reminder', () => { - it('shows the configured default when we have not made a previous update', () => { - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Verify the default is as expected - cy.get('#reminder_timer_datetime').within(() => { - cy.get('[class$=singleValue]').should('have.text', '1 hour'); - }); - }); - }); - - it('shows the last reminder we typed in: 15 minutes', () => { - const now = Date.now(); - const firstMessage = 'Update - ' + now; - - // # Create a first status update - cy.updateStatus(firstMessage, '15 minutes'); - - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Verify the default is as expected - cy.get('#reminder_timer_datetime').within(() => { - cy.get('[class$=singleValue]').should('have.text', '15 minutes'); - }); - }); - }); - - it('shows the last reminder we typed in: 90 minutes', () => { - const now = Date.now(); - const firstMessage = 'Update - ' + now; - - // # Create a first status update - cy.updateStatus(firstMessage, '90 minutes'); - - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Verify the default is as expected - cy.get('#reminder_timer_datetime').within(() => { - cy.get('[class$=singleValue]').should('have.text', '1 hour, 30 minutes'); - }); - }); - }); - - it('shows the last reminder we typed in: 7 days', () => { - const now = Date.now(); - const firstMessage = 'Update - ' + now; - - // # Create a first status update - cy.updateStatus(firstMessage, '7 days'); - - // # Run the `/playbook update` slash command. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the dialog modal. - cy.getStatusUpdateDialog().within(() => { - // * Verify the default is as expected - cy.get('#reminder_timer_datetime').within(() => { - cy.get('[class$=singleValue]').should('have.text', '7 days'); - }); - }); - }); - }); - - describe('playbook with disabled status updates', () => { - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - userId: testUser, - broadcastChannelId: testChannel.id, - statusUpdateEnabled: false, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - describe('omit status update dialog when status updates are disabled', () => { - it('shows the default when we have not made an update before', () => { - // * Check if RHS section is loaded - cy.get('#rhs-about').should('exist'); - - // * Check if Post Update section is omitted - cy.get('#rhs-post-update').should('not.exist'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/template_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/template_spec.js deleted file mode 100644 index 40c5c0c6a4..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/template_spec.js +++ /dev/null @@ -1,74 +0,0 @@ -// 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 > rhs > template', {testIsolation: true}, () => { - let team1; - let testUser; - - beforeEach(() => { - cy.apiAdminLogin().then(() => { - cy.apiInitSetup().then(({team, user}) => { - team1 = team; - testUser = user; - - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - }); - }); - }); - - describe('create playbook', () => { - describe('open new playbook creation modal and navigates to playbooks', () => { - it('after clicking on Use', () => { - // # Switch to playbooks DM channel - cy.visit(`/${team1.name}/messages/@playbooks`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Return first template (Blank) - cy.contains('Blank').click(); - - // * Assert playbooks creation modal is shown. - cy.get('#playbooks_create').should('exist'); - - // # Click create playbook button. - cy.get('button[data-testid=modal-confirm-button]').click(); - - // * Assert expected playbook template title in outline. - cy.findByTestId('playbook-editor-title').contains('Blank'); - }); - - it('after clicking on title', () => { - // # Switch to playbooks DM channel - cy.visit(`/${team1.name}/messages/@playbooks`); - - // # Open playbooks RHS. - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // # Return first template (Blank) - cy.contains('Use').click(); - - // * Assert playbooks creation modal is shown. - cy.get('#playbooks_create').should('exist'); - - // # Click create playbook button. - cy.get('button[data-testid=modal-confirm-button]').click(); - - // * Assert expected playbook template title in outline. - cy.findByTestId('playbook-editor-title').contains('Blank'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/title_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/title_spec.js deleted file mode 100644 index 8300d90fb9..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs/title_spec.js +++ /dev/null @@ -1,94 +0,0 @@ -// 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 > rhs > title', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - let playbookRunChannelName; - let testPlaybookRun; - - const getHeaderTitle = () => cy.get('#rhsContainer').find('.sidebar--right__title'); - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((run) => { - testPlaybookRun = run; - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - }); - - it('has title', () => { - // * Verify the title is displayed - getHeaderTitle().contains('Run details'); - }); - - it('has following button', () => { - // * Verify the following button is displayed - getHeaderTitle().find('button.unfollowButton').contains('Following'); - - // * Verify the follow button is not displayed - getHeaderTitle().find('button.followButton').should('not.exist'); - }); - - it('can stop following', () => { - // # Click the following button - getHeaderTitle().find('button.unfollowButton').click(); - - // * Verify the following button is not displayed - getHeaderTitle().find('button.unfollowButton').should('not.exist'); - - // * Verify the follow button is displayed - getHeaderTitle().find('button.followButton').contains('Follow'); - }); - - it('can navigate to RDP', () => { - // # Click the title - getHeaderTitle().findByTestId('rhs-title').click(); - - // * assert url is RDP - cy.url().should('include', `/playbooks/runs/${testPlaybookRun.id}`); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/rhs_spec.js deleted file mode 100644 index 2ab882c9d0..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/rhs_spec.js +++ /dev/null @@ -1,417 +0,0 @@ -// 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 * as TIMEOUTS from '../../../fixtures/timeouts'; - -describe('channels > rhs', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('does not open', () => { - it('when navigating to a non-playbook run channel', () => { - // # Navigate to the application - cy.visit(`/${testTeam.name}/`); - - // # Select a channel without a playbook run. - cy.get('#sidebarItem_off-topic').click({force: true}); - - // # Wait until the channel loads enough to show the post textbox. - cy.get('#post-create').should('exist'); - - // # Wait a bit longer to be confident. - cy.wait(TIMEOUTS.TWO_SEC); - - // * Verify the playbook run RHS is not open. - cy.get('#rhsContainer').should('not.exist'); - }); - - it('when navigating to a playbook run channel with the RHS already open', () => { - // # Navigate to the application. - cy.visit(`/${testTeam.name}/`); - - // # Select a channel without a playbook run. - cy.get('#sidebarItem_off-topic').click({force: true}); - - // # Run the playbook after loading the application - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Open the flagged posts RHS - cy.get('body').then(($body) => { - if ($body.find('#channelHeaderFlagButton').length > 0) { - cy.get('#channelHeaderFlagButton').click({force: true}); - } else { - cy.findByRole('button', {name: 'Saved messages'}). - click({force: true}); - } - }); - - // # Open the playbook run channel from the LHS. - cy.get(`#sidebarItem_${playbookRunChannelName}`).click({force: true}); - - // # Wait until the channel loads enough to show the post textbox. - cy.get('#post-create').should('exist'); - - // # Wait a bit longer to be confident. - cy.wait(TIMEOUTS.TWO_SEC); - - // * Verify the playbook run RHS is not open. - cy.get('#rhsContainer').should('not.exist'); - }); - - it('when navigating directly to a finished playbook run channel', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # End the playbook run - cy.apiFinishRun(playbookRun.id); - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Wait a bit longer to be confident. - cy.wait(TIMEOUTS.TWO_SEC); - - // * Verify the playbook run RHS is not open. - cy.get('#rhsContainer').should('not.exist'); - }); - - it('for an existing, finished playbook run channel opened from the lhs', () => { - // # Run the playbook before loading the application - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # End the playbook run - cy.apiFinishRun(playbookRun.id); - }); - - // # Navigate to a channel without a playbook run. - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // # Ensure the channel is loaded before continuing (allows redux to sync). - cy.findByTestId('post_textbox').should('exist'); - - // # Open the playbook run channel from the LHS. - cy.get(`#sidebarItem_${playbookRunChannelName}`).click({force: true}); - - // # Wait a bit longer to be confident. - cy.wait(TIMEOUTS.TWO_SEC); - - // * Verify the playbook run RHS is not open. - cy.get('#rhsContainer').should('not.exist'); - }); - - it('for a new, finished playbook run channel opened from the lhs', () => { - // # Navigate to the application. - cy.visit(`/${testTeam.name}/`); - - // # Ensure the channel is loaded before continuing (allows redux to sync). - cy.findByTestId('post_textbox').should('exist'); - - // # Select a channel without a playbook run. - cy.get('#sidebarItem_off-topic').click({force: true}); - - // * Verify the playbook run RHS is not open. - cy.get('#rhsContainer').should('not.exist'); - - // # Run the playbook after loading the application - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # Wait a bit longer to avoid websocket events potentially being out-of-order. - cy.wait(TIMEOUTS.TWO_SEC); - - // # End the playbook run - cy.apiFinishRun(playbookRun.id); - }); - - // # Wait because this test is flaky if we move too quickly - cy.wait(TIMEOUTS.FIVE_SEC); - - // # Open the playbook run channel from the LHS. - cy.get(`#sidebarItem_${playbookRunChannelName}`).click({force: true}); - - // # Wait a bit longer to be confident. - cy.wait(TIMEOUTS.FIVE_SEC); - - // * Verify the playbook run RHS is not open. - cy.get('#rhsContainer').should('not.exist'); - }); - - it('when starting a new run of a newly-created playbook created from RHS in a newly-created channel', () => { - // # Create a new channel - const channelName = 'playbook-test-' + Date.now(); - cy.apiCreateChannel(testTeam.id, channelName, channelName, 'O').then(({channel}) => { - // # Navigate to the new channel - cy.visit(`/${testTeam.name}/channels/${channel.name}`); - - // # Open RHS - cy.getPlaybooksAppBarIcon().click(); - - // # Wait a bit - cy.wait(TIMEOUTS.TWO_SEC); - - // # open start run dialog - cy.findByTestId('rhs-runlist-start-run').click(); - - // # Create a new playbook - cy.findByText('Create new playbook').click(); - - // # confirm new playbook creation (with defaults) - cy.findByTestId('modal-confirm-button').click(); - - // * Verify we're in the playbook edit screen - cy.findByTestId('playbook-members'); - - // # Run the playbook - cy.findByTestId('run-playbook').click(); - cy.findByTestId('run-name-input').type('Playbook Run'); - - // # Link to the new channel - cy.findByTestId('link-existing-channel-radio').click(); - cy.get('#link-existing-channel-selector input').type(`${channel.name}{enter}`, {force: true}); - - cy.findByTestId('modal-confirm-button').click(); - - // # Wait a bit - cy.wait(TIMEOUTS.FIVE_SEC); - - // * Verify the playbook run RHS is not open. - cy.get('#rhsContainer').should('not.exist'); - }); - }); - }); - - describe('opens', () => { - it('when navigating directly to an ongoing playbook run channel', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify the playbook run RHS is open. - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText(playbookRunName).should('exist'); - }); - }); - - it('for a new, ongoing playbook run channel opened from the lhs', () => { - // # Navigate to the application. - cy.visit(`/${testTeam.name}/`); - - // # Ensure the channel is loaded before continuing (allows redux to sync). - cy.findByTestId('post_textbox').should('exist'); - - // # Select a channel without a playbook run. - cy.get('#sidebarItem_off-topic').click({force: true}); - - // # Run the playbook after loading the application - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Open the playbook run channel from the LHS. - cy.get(`#sidebarItem_${playbookRunChannelName}`).click({force: true}); - - // * Verify the playbook run RHS is open. - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText(playbookRunName).should('exist'); - }); - }); - - it('for an existing, ongoing playbook run channel opened from the lhs', () => { - // # Run the playbook before loading the application - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate to a channel without a playbook run. - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // # Ensure the channel is loaded before continuing (allows redux to sync). - cy.findByTestId('post_textbox').should('exist'); - - // # Open the playbook run channel from the LHS. - cy.get(`#sidebarItem_${playbookRunChannelName}`).click({force: true}); - - // * Verify the playbook run RHS is open. - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText(playbookRunName).should('exist'); - }); - }); - - it('when starting a playbook run', () => { - // # Navigate to the application and a channel without a playbook run - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // # Start a playbook run with a slash command - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - - cy.startPlaybookRunWithSlashCommand('Playbook', playbookRunName); - - // * Verify the playbook run RHS is open. - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText(playbookRunName).should('exist'); - }); - }); - - it('when starting a playbook run when rhs is already open', () => { - // # Navigate to the application and a channel without a playbook run - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // # Wait until the channel loads enough to show the post textbox. - cy.get('#post-create').should('exist'); - - // # Open the saved posts RHS - cy.findByRole('button', {name: 'Saved messages'}). - click({force: true}); - - // * Verify Saved Posts is open - cy.get('.sidebar--right__title').should('contain.text', 'Saved messages'); - - // # Start a playbook run with a slash command - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - cy.startPlaybookRunWithSlashCommand('Playbook', playbookRunName); - - // * Verify the playbook run RHS is open. - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText(playbookRunName).should('exist'); - }); - }); - - it('when navigating directly to a finished playbook run channel and clicking on the button', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # End the playbook run - cy.apiFinishRun(playbookRun.id); - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Click the icon - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // * Verify no active runs screen shows - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByTestId('no-active-runs').should('exist'); - }); - }); - }); - - describe('is toggled', () => { - it('by icon in channel header', () => { - // # Size the viewport to show plugin icons even when RHS is open - cy.viewport('macbook-13'); - - // # Navigate to the application and a channel without a playbook run - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // # Click the icon - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // * Verify RHS Home is open. - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText('Playbooks').should('exist'); - }); - - // # Click the icon - cy.getPlaybooksAppBarIcon().should('be.visible').click(); - - // * Verify the playbook run RHS is no longer open. - cy.get('#rhsContainer').should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/run_dialog_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/run_dialog_spec.js deleted file mode 100644 index c13d524efe..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/run_dialog_spec.js +++ /dev/null @@ -1,132 +0,0 @@ -// 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 > run dialog', {testIsolation: true}, () => { - let testTeam; - let testUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - }); - - // # Create a second playbook, so as to force dropdown. - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Second Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Navigate to the application - cy.visit(`${testTeam.name}`); - - // # Trigger the playbook run creation dialog - cy.openPlaybookRunDialogFromSlashCommand(); - - // * Verify the playbook run creation dialog has opened - cy.get('#interactiveDialogModal').should('exist').within(() => { - cy.findByText('Start run').should('exist'); - }); - }); - - it('cannot create a playbook run without filling required fields', () => { - cy.get('#interactiveDialogModal').within(() => { - cy.findByText('Start run').should('exist'); - - // # Attempt to submit - cy.get('#interactiveDialogSubmit').click(); - }); - - // * Verify it didn't submit - cy.get('#interactiveDialogModal').should('exist'); - - // * Verify required fields - cy.findByTestId('autoCompleteSelector').contains('Playbook'); - cy.findByTestId('autoCompleteSelector').contains('This field is required.'); - cy.findByTestId('playbookRunName').contains('This field is required.'); - }); - - it('rejects invalid channel names', () => { - cy.selectPlaybookFromDropdown('Playbook'); - - const invalidPlaybookRunName = ' '; - cy.get('#interactiveDialogModal').within(() => { - cy.findByTestId('playbookRunNameinput').type(invalidPlaybookRunName, {force: true}); - }); - - cy.get('#interactiveDialogModal').within(() => { - cy.findByText('Start run').should('exist'); - - // # Attempt to submit - cy.get('#interactiveDialogSubmit').click(); - }); - - // * Verify it didn't submit - cy.get('#interactiveDialogModal').should('exist'); - - // * Verify error message - cy.get('#interactiveDialogModal').within(() => { - cy.get('div.error-text').contains('unable to create playbook run'); - }); - }); - - it('shows expected metadata', () => { - cy.get('#interactiveDialogModal').within(() => { - // * Shows current user as owner. - cy.findByText(`${testUser.first_name} ${testUser.last_name}`).should('exist'); - - // * Verify playbook dropdown prompt - cy.findByText('Playbook').should('exist'); - - // * Verify playbook run name prompt - cy.findByText('Run name').should('exist'); - }); - }); - - it('is canceled when cancel is clicked', () => { - // # Populate the interactive dialog - const playbookRunName = 'New Run' + Date.now(); - cy.get('#interactiveDialogModal').within(() => { - cy.findByTestId('playbookRunNameinput').type('Playbook', {force: true}); - }); - - // # Cancel the interactive dialog - cy.get('#interactiveDialogCancel').click(); - - // * Verify the modal is no longer displayed - cy.get('#interactiveDialogModal').should('not.exist'); - - // * Verify the playbook run did not get created - cy.apiGetAllPlaybookRuns(testTeam.id).then((response) => { - const allPlaybookRuns = response.body; - const playbookRun = allPlaybookRuns.items.find((inc) => inc.name === playbookRunName); - expect(playbookRun).to.be.undefined; - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/run_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/run_spec.js deleted file mode 100644 index 2c4970095d..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/run_spec.js +++ /dev/null @@ -1,120 +0,0 @@ -// 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 > run', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPrivateChannel; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreatePlaybook({ - teamId: team.id, - title: 'Playbook', - memberIDs: [user.id], - }); - - // # Create a private channel - cy.apiCreateChannel( - testTeam.id, - 'private-channel', - 'Private Channel', - 'P', - ).then(({channel}) => { - testPrivateChannel = channel; - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Size the viewport to show plugin icons even when RHS is open - cy.viewport('macbook-13'); - }); - - describe('via slash command', () => { - it('while viewing a public channel', () => { - // # Visit a public channel - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // * Verify that playbook run can be started with slash command - const playbookRunName = 'Public ' + Date.now(); - cy.startPlaybookRunWithSlashCommand('Playbook', playbookRunName); - cy.verifyPlaybookRunActive(testTeam.id, playbookRunName); - }); - - it('while viewing a private channel', () => { - // # Visit a private channel - cy.visit(`/${testTeam.name}/channels/${testPrivateChannel.name}`); - - // * Verify that playbook run can be started with slash command - const playbookRunName = 'Private ' + Date.now(); - cy.startPlaybookRunWithSlashCommand('Playbook', playbookRunName); - cy.verifyPlaybookRunActive(testTeam.id, playbookRunName); - }); - }); - - describe('via post menu', () => { - it('while viewing a public channel', () => { - // # Visit a public channel - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // * Verify that playbook run can be started from post menu - const playbookRunName = 'Public - ' + Date.now(); - cy.startPlaybookRunFromPostMenu('Playbook', playbookRunName); - cy.verifyPlaybookRunActive(testTeam.id, playbookRunName); - }); - - it('while viewing a private channel', () => { - // # Visit a private channel - cy.visit(`/${testTeam.name}/channels/${testPrivateChannel.name}`); - - // * Verify that playbook run can be started from post menu - const playbookRunName = 'Private - ' + Date.now(); - cy.startPlaybookRunFromPostMenu('Playbook', playbookRunName); - cy.verifyPlaybookRunActive(testTeam.id, playbookRunName); - }); - }); - - it('always as channel admin', () => { - // # Visit a public channel - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // # Start a playbook run with a slash command - const playbookRunName = 'Public ' + Date.now(); - cy.startPlaybookRunWithSlashCommand('Playbook', playbookRunName); - cy.verifyPlaybookRunActive(testTeam.id, playbookRunName); - - // # Open channel header dropdown - cy.get('#channelHeaderDropdownButton').click(); - - // # Click on Channel Settings - cy.findByText('Channel Settings').should('be.visible').click(); - - // * Verify Channel Settings modal opens - cy.get('.ChannelSettingsModal').should('be.visible'); - - // * Verify the ability to edit the channel header exists - cy.get('#channel_settings_header_textbox').should('be.visible').and('not.be.disabled'); - - // # Close the modal - cy.get('.GenericModal .modal-header button[aria-label="Close"]').click(); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/commands_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/commands_spec.js deleted file mode 100644 index 20b6baf2e3..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/commands_spec.js +++ /dev/null @@ -1,557 +0,0 @@ -// 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) -// *************************************************************** - -// Group: @playbooks - -import {switchToChannel} from '../../../channels/mark_as_unread/helpers'; - -describe('channels > slash command > owner', {testIsolation: true}, () => { - 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__info').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__info').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__info').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__info').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__info').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__info').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__info').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'); - }); - }); - }); -}); - diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/info_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/info_spec.js deleted file mode 100644 index fb1266d25c..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/info_spec.js +++ /dev/null @@ -1,120 +0,0 @@ -// 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', {testIsolation: true}, () => { - 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.'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/owner_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/owner_spec.js deleted file mode 100644 index 212bcf237e..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/owner_spec.js +++ /dev/null @@ -1,222 +0,0 @@ -// 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', {testIsolation: true}, () => { - 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.'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/test_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/test_spec.js deleted file mode 100644 index 45aa54dcec..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/test_spec.js +++ /dev/null @@ -1,257 +0,0 @@ -// 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) -// *************************************************************** - -// Group: @playbooks - -describe('channels > slash command > test', {testIsolation: true}, () => { - 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, - }, - }); - cy.apiReloadConfig(); - }); - - 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, - }, - }); - cy.apiReloadConfig(); - }); - - 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, - }, - }); - cy.apiReloadConfig(); - }); - - 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: '); - }); - - 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: '); - }); - - 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: '); - }); - - 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, , 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\'.'); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/todo_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/todo_spec.js deleted file mode 100644 index e0995522f0..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/slash_command/todo_spec.js +++ /dev/null @@ -1,321 +0,0 @@ -// 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) -// *************************************************************** - -// Group: @playbooks - -describe('channels > slash command > todo', {testIsolation: true}, () => { - 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); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/channels/update_request_post_spec.js b/e2e-tests/cypress/tests/integration/playbooks/channels/update_request_post_spec.js deleted file mode 100644 index 6a180c8151..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/channels/update_request_post_spec.js +++ /dev/null @@ -1,199 +0,0 @@ -// 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 * as TIMEOUTS from '../../../fixtures/timeouts'; - -describe('channels > update request post', {testIsolation: true}, () => { - let testTeam; - let testParticipant; - let testChannelMemberOnly; - let testPlaybookRun; - let testPlaybookRun2; - - before(() => { - cy.apiUpdateConfig({ - ServiceSettings: { - ThreadAutoFollow: true, - CollapsedThreads: 'default_on', - }, - }); - - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testParticipant = user; - - cy.apiCreateUser().then(({user: channelMemberOnly}) => { - testChannelMemberOnly = channelMemberOnly; - - // # Add testChannelMemberOnly to the testTeam - cy.apiAddUserToTeam(testTeam.id, testChannelMemberOnly.id); - - // # Login as testChannelMemberOnly - cy.apiLogin(testChannelMemberOnly); - - // # Enable threads view - cy.apiSaveCRTPreference(testChannelMemberOnly.id, 'on'); - }); - - // # Login as testParticipant - cy.apiLogin(testParticipant); - - // # Enable threads view - cy.apiSaveCRTPreference(testParticipant.id, 'on'); - - // # Create a public playbook with 2 runs in the same channel - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - }).then((playbook) => { - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: 'Test Run', - ownerUserId: testParticipant.id, - }).then((playbookRun) => { - testPlaybookRun = playbookRun; - - // # Add testChannelMemberOnly to the channel, but not the run. - cy.apiAddUserToChannel(playbookRun.channel_id, testChannelMemberOnly.id); - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: 'Test Run 2', - ownerUserId: testParticipant.id, - channelId: testPlaybookRun.channel_id, - }).then((playbookRun2) => { - testPlaybookRun2 = playbookRun2; - }); - }); - }); - }); - }); - - describe('displays interactive post', () => { - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testParticipant); - - // # Post a status update, with a reminder in 1 second. - cy.apiUpdateStatus({ - playbookRunId: testPlaybookRun2.id, - message: 'status update 2', - reminder: 1, - }); - - // # Post a status update, with a reminder in 2 second. - cy.apiUpdateStatus({ - playbookRunId: testPlaybookRun.id, - message: 'status update', - reminder: 2, - }); - - // Ensure the status update reminder gets posted - cy.wait(TIMEOUTS.TWO_SEC); - }); - - describe('as a participant', () => { - beforeEach(() => { - // # Navigate to the application - cy.visit(`${testTeam.name}/channels/test-run`); - }); - - it('in the run channel', () => { - cy.getLastPost().then((element) => { - // # Verify the expected message text - cy.get(element).contains(`@${testParticipant.username}, please provide a status update for ${testPlaybookRun.name}.`); - - // # Verify interactive message button to post an update - cy.get(element).find('button').contains('Post update'); - }); - }); - - it('reset reminder', () => { - cy.getLastPost().within(() => { - // * Snooze reminder - cy.getStyledComponent('StyledSelect').click().type('{downArrow}{downArrow}{enter}'); - - // # Verify interactive message button to post an update has dissapeared - cy.findByText('(message deleted)').should('be.visible'); - }); - }); - - it('in threads view', () => { - // # Find the update request post and post a reply to make it show up in threads view - cy.getLastPostId().then((lastPostId) => { - // Open RHS - cy.clickPostCommentIcon(lastPostId); - - // Post a reply message - cy.postMessageReplyInRHS('test reply'); - - // # Navigate to the threads view - cy.get('#sidebarItem_threads').click(); - - // # Verify the expected text in the list view - cy.get('.ThreadItem').first().contains(`@${testParticipant.username}, please provide a status update for ${testPlaybookRun.name}.`); - - // # Click to open details - cy.get('.ThreadItem').first().click(); - - // # Verify post still rendered - cy.get(`#rhsPost_${lastPostId}`).contains(`@${testParticipant.username}, please provide a status update for ${testPlaybookRun.name}.`); - - // # Verify interactive message button to post an update - cy.get(`#rhsPost_${lastPostId}`).find('button').contains('Post update'); - }); - }); - }); - - describe('as a channel member only', () => { - beforeEach(() => { - // # Login as testChannelMemberOnly - cy.apiLogin(testChannelMemberOnly); - - // # Navigate to the application - cy.visit(`${testTeam.name}/channels/test-run`); - }); - - it('in the run channel', () => { - cy.getLastPost().then((element) => { - // # Verify the expected message text - cy.get(element).contains(`@${testParticipant.username}, please provide a status update for ${testPlaybookRun.name}.`); - }); - }); - - it('in threads view', () => { - // # Find the update request post and post a reply to make it show up in threads view - cy.getLastPostId().then((lastPostId) => { - // Open RHS - cy.clickPostCommentIcon(lastPostId); - - // Post a reply message - cy.postMessageReplyInRHS('test reply'); - - // # Navigate to the threads view - cy.get('#sidebarItem_threads').click(); - - // # Verify the expected text in the list view - cy.get('.ThreadItem').first().contains(`@${testParticipant.username}, please provide a status update for ${testPlaybookRun.name}.`); - - // # Click to open details - cy.get('.ThreadItem').first().click(); - - // # Verify post still rendered - cy.get(`#rhsPost_${lastPostId}`).contains(`@${testParticipant.username}, please provide a status update for ${testPlaybookRun.name}.`); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/digest_spec.js b/e2e-tests/cypress/tests/integration/playbooks/digest_spec.js deleted file mode 100644 index c12caa8992..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/digest_spec.js +++ /dev/null @@ -1,178 +0,0 @@ -// 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('digest messages', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - checklists: [ - { - title: 'Stage 1', - items: [ - {title: 'Step 1', command: '/invalid'}, - {title: 'Step 2', command: '/echo VALID'}, - {title: 'Step 3', command: '/playbook check 0 0'}, - {title: 'Step 4'}, - ], - }, - ], - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('digest message >', () => { - let testRun; - before(() => { - const runName = 'Playbook Run (' + Date.now() + ')'; - - // # Start a run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: runName, - ownerUserId: testUser.id, - }).then((run) => { - testRun = run; - - // # Set a timer that will expire. - cy.apiUpdateStatus({ - playbookRunId: run.id, - message: 'no message 1', - reminder: 1, - }); - cy.apiChangeChecklistItemAssignee(run.id, 0, 0, testUser.id); - }); - }); - - it('has one run overdue and links to RDP', () => { - // # Switch to playbooks DM channel - cy.visit(`/${testTeam.name}/messages/@playbooks`); - - // # Wait until the channel loads enough to show the post textbox. - cy.get('#post-create').should('exist'); - - // # Run a slash command to show the to-do list. - cy.uiPostMessageQuickly('/playbook todo'); - - cy.getLastPost().within(() => { - // # assert two blocks: inprogress+overdue - cy.get('ul').should('have.length', 3); - - // * CLick the first link - overdue status - cy.get('ul a').eq(0).click(); - }); - - // # assert url is RDP - cy.url().should('contain', '/playbooks/runs/' + testRun.id + '?from=digest_overduestatus'); - - // # assert telemetry tracks correctly the origin - cy.expectTelemetryToContain([ - { - name: 'run_details', - type: 'page', - properties: { - from: 'digest_overduestatus', - }, - }, - ]); - }); - - it('has one run in progress and links to RDP', () => { - // # Switch to playbooks DM channel - cy.visit(`/${testTeam.name}/messages/@playbooks`); - - // # Wait until the channel loads enough to show the post textbox. - cy.get('#post-create').should('exist'); - - // # Run a slash command to show the to-do list. - cy.uiPostMessageQuickly('/playbook todo'); - - cy.getLastPost().within(() => { - // # assert two blocks: inprogress+overdue - cy.get('ul').should('have.length', 3); - - // * CLick the second link - inprogress - cy.get('ul a').eq(1).click(); - }); - - // # assert url is RDP - cy.url().should('contain', '/playbooks/runs/' + testRun.id + '?from=digest_runsinprogress'); - - // # assert telemetry tracks correctly the origin - cy.expectTelemetryToContain([ - { - name: 'run_details', - type: 'page', - properties: { - from: 'digest_runsinprogress', - }, - }, - ]); - }); - - it('has one run with one assigned task and links to RDP', () => { - // # Switch to playbooks DM channel - cy.visit(`/${testTeam.name}/messages/@playbooks`); - - // # Wait until the channel loads enough to show the post textbox. - cy.get('#post-create').should('exist'); - - // # Run a slash command to show the to-do list. - cy.uiPostMessageQuickly('/playbook todo'); - - cy.getLastPost().within(() => { - // # assert two blocks: inprogress+overdue - cy.get('ul').should('have.length', 3); - - // * CLick link - assigned task - cy.get('p a').click(); - }); - - // # assert url is RDP - cy.url().should('contain', '/playbooks/runs/' + testRun.id + '?from=digest_assignedtask'); - - // # assert telemetry tracks correctly the origin - cy.expectTelemetryToContain([ - { - name: 'run_details', - type: 'page', - properties: { - from: 'digest_assignedtask', - }, - }, - ]); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/lhs_spec.js b/e2e-tests/cypress/tests/integration/playbooks/lhs_spec.js deleted file mode 100644 index b3a8879946..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/lhs_spec.js +++ /dev/null @@ -1,394 +0,0 @@ -// 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 {HALF_SEC} from '../../fixtures/timeouts'; -import {stubClipboard} from '../../utils'; - -describe('lhs', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPublicPlaybook; - let testPrivatePlaybook; - let playbookRun; - let testViewerUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - - // # Create a private playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Private Playbook', - memberIDs: [], - public: false, - }).then((playbook) => { - testPrivatePlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Intercepts telemetry - cy.interceptTelemetry(); - }); - - const getRunDropdownItemByText = (groupName, runName, itemName) => { - // # Click on run at LHS - cy.findByTestId(groupName).findByTestId(runName).click(); - - // # Click dot menu - cy.findByTestId(groupName). - findByTestId(runName). - findByTestId('menuButton'). - click({force: true}); - - cy.findByTestId('dropdownmenu').should('be.visible'); - - return cy.findByTestId('dropdownmenu').findByText(itemName).should('be.visible'); - }; - - describe('navigate', () => { - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name(' + Date.now() + ')', - ownerUserId: testUser.id, - }).then((run) => { - playbookRun = run; - - // # Visit the playbook run - cy.visit('/playbooks/runs'); - cy.findByTestId('lhs-navigation').findByText(playbookRun.name).should('be.visible'); - }); - - cy.wait; - }); - - it('click run', () => { - // # Click on run at LHS - cy.findByTestId('Runs').findByTestId(playbookRun.name).click(); - - // * assert telemetry - cy.expectTelemetryToContain([ - { - type: 'page', - name: 'run_details', - properties: { - from: 'playbooks_lhs', - role: 'participant', - playbookrun_id: playbookRun.id, - playbook_id: testPublicPlaybook.id, - }, - }, - ]); - }); - }); - - describe('run dot menu', () => { - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name(' + Date.now() + ')', - ownerUserId: testUser.id, - }).then((run) => { - playbookRun = run; - }); - }); - - it('shows on click', () => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - - // # Click dot menu - cy.findByTestId('Runs'). - findByTestId(playbookRun.name). - findByTestId('menuButton'). - click({force: true}); - - // * Assert context menu is opened - cy.findByTestId('dropdownmenu').should('be.visible'); - }); - - it('can copy link', () => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - stubClipboard().as('clipboard'); - - // # Click on Copy link menu item - getRunDropdownItemByText('Runs', playbookRun.name, 'Copy link').click(); - - // * Verify clipboard content - cy.get('@clipboard').its('contents').should('contain', `/playbooks/runs/${playbookRun.id}`); - }); - - it('can favorite / unfavorite', () => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - - // # Click on favorite menu item - getRunDropdownItemByText('Runs', playbookRun.name, 'Favorite').click(); - - // * Verify the run is added to favorites - cy.findByTestId('Favorite').findByTestId(playbookRun.name).should('exist'); - - // # Click on unfavorite menu item - getRunDropdownItemByText('Favorite', playbookRun.name, 'Unfavorite').click(); - - // * Verify the run is removed from favorites - cy.findByTestId('Favorite').should('not.exist'); - }); - - it('lhs refresh on follow/unfollow', () => { - cy.apiLogin(testViewerUser); - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - - // # The assertions here guard against the click() on 194 - // # happening on a detached element. - cy.assertRunDetailsPageRenderComplete(testUser.username); - cy.findByTestId('runinfo-following').should('be.visible').within(() => { - // # Verify follower icon - cy.findAllByTestId('profile-option', {exact: false}).should('have.length', 1); - cy.findByText('Follow').should('be.visible').click(); - - // # Verify icons update - cy.findAllByTestId('profile-option', {exact: false}).should('have.length', 2); - }); - - // * Verify that the run was added to the lhs - cy.findByTestId('lhs-navigation').findByText(playbookRun.name).should('exist'); - - // # Click on unfollow menu item - getRunDropdownItemByText('Runs', playbookRun.name, 'Unfollow').click(); - - // * Verify that the run is removed lhs - cy.findByTestId('Runs').findByTestId(playbookRun.name).should('not.exist'); - - // # assert telemetry data - cy.expectTelemetryToContain([ - { - type: 'track', - name: 'playbookrun_follow', - properties: { - from: 'run_details', - playbookrun_id: playbookRun.id, - }, - }, - { - type: 'track', - name: 'playbookrun_unfollow', - properties: { - from: 'playbooks_lhs', - playbookrun_id: playbookRun.id, - }, - }, - ]); - }); - - it('leave run', () => { - // # Add viewer user to the channel - cy.apiAddUsersToRun(playbookRun.id, [testViewerUser.id]); - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - - // # Click on leave menu item - getRunDropdownItemByText('Runs', playbookRun.name, 'Leave and unfollow run').click(); - - // * Verify that owner can't leave. - cy.get('#confirmModal').should('not.exist'); - - // # Change the owner to testViewerUser - cy.findByTestId('runinfo-owner').findByTestId('assignee-profile-selector').click(); - cy.get('.playbook-react-select').findByText('@' + testViewerUser.username).click(); - - // # Wait for owner to change - cy.wait(HALF_SEC); - - // # Click on leave menu item - getRunDropdownItemByText('Runs', playbookRun.name, 'Leave and unfollow run').click(); - - // * Click leave confirmation - cy.get('#confirmModalButton').click(); - - // # assert telemetry data - cy.expectTelemetryToContain([ - { - type: 'track', - name: 'playbookrun_leave', - properties: { - from: 'playbooks_lhs', - playbookrun_id: playbookRun.id, - }, - }, - ]); - }); - }); - - describe('leave run - no permanent access', () => { - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPrivatePlaybook.id, - playbookRunName: 'the run name(' + Date.now() + ')', - ownerUserId: testUser.id, - }).then((run) => { - playbookRun = run; - - cy.apiAddUsersToRun(playbookRun.id, [testViewerUser.id]); - - cy.apiLogin(testViewerUser).then(() => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - }); - - it('leave run, when on rdp of the same run', () => { - // # Click on leave menu item - getRunDropdownItemByText('Runs', playbookRun.name, 'Leave and unfollow run').click(); - - // # confirm modal - cy.get('#confirmModal').should('be.visible').within(() => { - cy.get('#confirmModalButton').click(); - }); - - // * Verify that user was redirected to the run list page - cy.url().should('include', 'playbooks/runs?sort='); - }); - - it('leave run, when not on rdp of the same run', () => { - // # Visit playbooks list page - cy.visit('/playbooks/playbooks'); - - // # Click on leave menu item - getRunDropdownItemByText('Runs', playbookRun.name, 'Leave and unfollow run').click(); - - // # confirm modal - cy.get('#confirmModal').should('be.visible').within(() => { - cy.get('#confirmModalButton').click(); - }); - - // * Verify that user was not redirected to the run list page - cy.url().should('not.include', 'playbooks/runs?sort='); - }); - }); - - describe('playbook dot menu', () => { - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'the run name(' + Date.now() + ')', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - - // # Visit the playbooks page - cy.visit('/playbooks/playbooks'); - }); - }); - - it('shows on click', () => { - // # Click dot menu - cy.findByTestId('Playbooks'). - findByTestId(testPublicPlaybook.title). - findByTestId('menuButton'). - click({force: true}); - - // * Assert context menu is opened - cy.findByTestId('dropdownmenu').should('be.visible'); - }); - - it('can copy link', () => { - stubClipboard().as('clipboard'); - - // # Click on Copy link menu item - getRunDropdownItemByText('Playbooks', testPublicPlaybook.title, 'Copy link').click(); - - // * Verify clipboard content - cy.get('@clipboard'). - its('contents'). - should('contain', `/playbooks/playbooks/${testPublicPlaybook.id}`); - }); - - it('can favorite / unfavorite', () => { - // # Click on favorite menu item - getRunDropdownItemByText('Playbooks', testPublicPlaybook.title, 'Favorite').click(); - - // * Verify the playbook is added to favorites - cy.findByTestId('Favorite').findByTestId(testPublicPlaybook.title).should('exist'); - - // # Click on unfavorite menu item - getRunDropdownItemByText('Favorite', testPublicPlaybook.title, 'Unfavorite').click(); - - // * Verify the playbook is removed from favorites - cy.findByTestId('Playbooks').findByTestId(testPublicPlaybook.title).should('exist'); - }); - - it('can leave', () => { - stubClipboard().as('clipboard'); - - // # Click on Leave menu item - getRunDropdownItemByText('Playbooks', testPublicPlaybook.title, 'Leave').click(); - - // * Verify the playbook is removed from the list - cy.findByTestId('Playbooks').findByTestId(testPublicPlaybook.title).should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/navigation_spec.js b/e2e-tests/cypress/tests/integration/playbooks/navigation_spec.js deleted file mode 100644 index 056a71e216..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/navigation_spec.js +++ /dev/null @@ -1,72 +0,0 @@ -// 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('navigation', {testIsolation: true}, () => { - let testTeam; - let testUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as user-1 - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - }).then((playbook) => { - cy.apiRunPlaybook({ - teamId: team.id, - playbookId: playbook.id, - playbookRunName: 'Playbook Run', - ownerUserId: user.id, - }); - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Navigate to the application - cy.visit(`/${testTeam.name}/`); - }); - - it('switches to playbooks list view via sidebar view all button', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // * Verify that playbooks are shown - cy.findByTestId('titlePlaybook').should('exist').contains('Playbooks'); - }); - - it('switches to playbook runs list view via sidebar view all button', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Switch to playbook runs - cy.findByTestId('playbookRunsLHSButton').click(); - - // * Verify that playbook runs are shown - cy.findByTestId('titlePlaybookRun').should('exist').contains('Runs'); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/access_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/access_spec.js deleted file mode 100644 index 958c0118fc..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/access_spec.js +++ /dev/null @@ -1,114 +0,0 @@ -// 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('playbooks > edit', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testUser2; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Create a second test user in this team - cy.apiCreateUser().then((payload) => { - testUser2 = payload.user; - cy.apiAddUserToTeam(testTeam.id, payload.user.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('rdp information refresh', () => { - let testPlaybook; - - beforeEach(() => { - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - public: true, - }).then((playbook) => { - testPlaybook = playbook; - - // Navigate to the playbook page - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - }); - }); - - it('add / remove a member', () => { - // # Open playbook access modal - cy.findByTestId('playbook-members').click(); - - // # Add a new member - cy.findByTestId('add-people-input').type(testUser2.username); - cy.wait(500); - cy.findByTestId('profile-option-' + testUser2.username).click({force: true}); - - // * Verify that user was added - cy.findByTestId('members-list').findByText(testUser2.username).should('exist'); - - // # Close playbook access modal - cy.get('.close > [aria-hidden="true"]').click(); - - // * Verify members number - cy.findByTestId('playbook-members').findByText('2').should('exist'); - - // # Open playbook access modal - cy.findByTestId('playbook-members').click(); - - // # Open dropdown and remove user - cy.findByText('Playbook Member').click(); - cy.findByTestId('dropdownmenu').findByText('Remove').click(); - - // * Verify that user was removed - cy.findByTestId('members-list').findByText(testUser2.username).should('not.exist'); - - // # Close playbook access modal - cy.get('.close > [aria-hidden="true"]').click(); - - // * Verify members number - cy.findByTestId('playbook-members').findByText('1').should('exist'); - }); - - it('change to private', () => { - // # Open playbook access modal - cy.findByTestId('playbook-members').click(); - - // # Click on convert to private - cy.findByText('Convert to private playbook').click(); - - // * Check that confirm modal is open - cy.get('#confirmModal').should('be.visible'); - - // # Confirm convert to private - cy.get('#confirmModal').get('#confirmModalButton').click(); - - // * Verify that playbook is private - cy.findByText('Convert to private playbook').should('not.exist'); - - // # Close playbook access modal - cy.get('.close > [aria-hidden="true"]').click(); - - // * Verify lock icon is visible - cy.findByTestId('playbook-editor-header').get('.icon-lock-outline').should('be.visible'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/creation_button_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/creation_button_spec.js deleted file mode 100644 index 9ba500c5b3..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/creation_button_spec.js +++ /dev/null @@ -1,201 +0,0 @@ -// 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('playbooks > creation button', {testIsolation: true}, () => { - let testSysadmin; - let testTeam; - let testUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateCustomAdmin().then(({sysadmin}) => { - testSysadmin = sysadmin; - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - // # Creating this playbook ensures the list view - // # specifically is shown in the backstage content section. - // # Without it there is a brief flicker from the list view - // # to the no content view, which causes some flake - // # on clicking the 'Create playbook' button - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - }); - }); - }); - - beforeEach(() => { - // # Login as user-1 - cy.apiLogin(testUser); - - // # Size the viewport to show playbooks without weird scrolling issues - cy.viewport('macbook-13'); - }); - - it('opens playbook creation page with New Playbook button', () => { - const playbookName = 'Untitled Playbook'; - - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Click 'New Playbook' button - cy.findByTestId('titlePlaybook').findByText('Create playbook').click(); - cy.get('#playbooks_create').findByText('Create playbook').click(); - - // * Verify playbook outline page opened - verifyPlaybookOutlineOpened(playbookName); - - // * Verify playbook was added to the LHS - cy.findByTestId('lhs-navigation').findByText(playbookName).should('exist'); - }); - - it('auto creates a playbook with "Blank" template option', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Click 'Blank' - cy.findByText('Blank').click(); - - const playbookName = `@${testUser.username}'s Blank`; - - // * Verify playbook outline opened - verifyPlaybookOutlineOpened(playbookName); - - // * Verify playbook was added to the LHS - cy.findByTestId('lhs-navigation').findByText(playbookName).should('exist'); - }); - - it('opens Service Outage Incident page from its template option (multiple teams)', () => { - cy.apiCreateTeam('second-team', 'Second Team').then(() => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Click 'Incident Resolution' - cy.findByText('Incident Resolution').click(); - - const playbookName = `@${testUser.username}'s Incident Resolution`; - - // * Verify playbook outline opened - verifyPlaybookOutlineOpened(playbookName); - - // * Verify the playbook was added to the lhs of current team - cy.findByTestId('lhs-navigation').findByText(playbookName).should('exist'); - }); - }); - - let restrictedTestTeam; - let restrictedTestUser; - - describe('user is lacking permissions to create playbooks', () => { - before(() => { - cy.apiLogin(testSysadmin); - - cy.apiCreateUser().then(({user: createdUser}) => { - restrictedTestUser = createdUser; - }); - - cy.apiCreateTeam('restricted-team', 'Restricted Team').then(({team: createdTeam}) => { - restrictedTestTeam = createdTeam; - cy.apiAddUserToTeam(restrictedTestTeam.id, restrictedTestUser.id); - }); - - cy.apiCreateScheme('Restricted Team Scheme', 'team').then(({scheme}) => { - cy.apiSetTeamScheme(restrictedTestTeam.id, scheme.id); - cy.apiGetRolesByNames([scheme.default_team_user_role]).then(({roles}) => { - const role = roles[0]; - - // Remove permissions to create playbooks - const permissions = role.permissions.filter((perm) => !(/playbook_(private|public)_create/).test(perm)); - cy.apiPatchRole(role.id, {permissions}); - }); - }); - }); - - beforeEach(() => { - // # Login as user with restricted permissions - cy.apiLogin(restrictedTestUser); - }); - - it('create playbook entry in LHS dropdown should not exist', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Open menu dropdown - cy.findByTestId('create-playbook-dropdown-toggle').click(); - - cy.get('#CreatePlaybookDropdown').within(() => { - // * Verify create playbook entry is missing - cy.findByText('Create New Playbook').should('not.exist'); - }); - }); - - it('permission notice should be shown if no playbooks exist', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // * Verify notice about missing permissions and no playbooks is shown - cy.findByText('There are no playbooks to view. You don\'t have permission to create playbooks in this workspace.').should('exist'); - }); - - it('create playbook button should not exist if playbooks exist', () => { - // # Create a playbook for the team - cy.apiLogin(testSysadmin).then(() => { - cy.apiCreatePlaybook({ - teamId: restrictedTestTeam.id, - title: 'Playbook', - memberIDs: [], - }); - }); - - // # Login as user with restricted permissions - cy.apiLogin(restrictedTestUser); - - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // * Verify create playbook button is missing - cy.findByTestId('titlePlaybook').findByText('Create playbook').should('not.exist'); - }); - }); -}); - -function verifyPlaybookOutlineOpened(playbookName) { - // * Verify the page url contains 'playbooks/playbooks/new' - cy.url().should('contain', '/outline'); - - // * Verify the playbook name matches the one provided - cy.findByTestId('playbook-editor-title').within(() => { - cy.findByText(playbookName).should('be.visible'); - }); -} diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/actions_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/actions_spec.js deleted file mode 100644 index 8f75ce0b0c..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/actions_spec.js +++ /dev/null @@ -1,1058 +0,0 @@ -// 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 * as TIMEOUTS from '../../../../fixtures/timeouts'; - -// assumes that E20 license is uploaded -describe('playbooks > edit', {testIsolation: true}, () => { - let testTeam; - let testSysadmin; - let testUser; - let testUser2; - let testUser3; - - const openCategorySelector = () => { - cy.get('.channel-selector__control input').click({force: true}); - }; - const selectCategory = (name) => { - cy.get('.channel-selector__menu').findByText(name).click({force: true}); - }; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateCustomAdmin().then(({sysadmin}) => { - testSysadmin = sysadmin; - }); - - // # Create a second test user in this team - cy.apiCreateUser().then((payload) => { - testUser2 = payload.user; - cy.apiAddUserToTeam(testTeam.id, payload.user.id); - }); - - // # Create a third test user in this team - cy.apiCreateUser().then((payload) => { - testUser3 = payload.user; - cy.apiAddUserToTeam(testTeam.id, payload.user.id); - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - const commonActionTests = () => { - describe('when a playbook run starts', () => { - let testPlaybook; - beforeEach(() => { - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - describe('create channel setting', () => { - it('is enabled by default in a new playbook', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section. - cy.get('#actions').within(() => { - // * Verify that the toggle is checked - cy.get('#create-new-channel label input').should('be.checked'); - }); - }); - }); - - describe('invite members setting', () => { - it('is disabled in a new playbook', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - // * Verify that the toggle is unchecked - cy.get('#invite-users label input').should('not.be.checked'); - }); - }); - - it('can be enabled', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is unchecked - cy.get('label input').should('be.checked'); - }); - }); - }); - - it('does not let add users when disabled', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - // * Verify that the toggle is unchecked - cy.get('#invite-users label input').should('not.be.checked'); - - // * Verify that the menu is disabled - cy.get('#invite-users').within(() => { - cy.getStyledComponent('StyledReactSelect').should( - 'have.class', - 'invite-users-selector--is-disabled', - ); - }); - }); - }); - - it('allows adding users when enabled', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Open the invited users selector - cy.openSelector(); - - // # Add one user - cy.addInvitedUser(testUser2.username); - cy.wait(TIMEOUTS.ONE_SEC); - - // * Verify that the badge in the selector shows the correct number of members - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '1 SELECTED'); - - // * Verify that the user shows in the group of invited members - cy.findByText('SELECTED'). - parent(). - within(() => { - cy.findByText(testUser2.username); - }); - }); - }); - }); - - it('allows adding new users to an already populated list', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Open the invited users selector - cy.openSelector(); - - // # Add one user - cy.addInvitedUser(testUser2.username); - - // * Verify that the user shows in the group of invited members - cy.findByText('SELECTED'). - parent(). - within(() => { - cy.findByText(testUser2.username); - }); - - // # Add a new user - cy.addInvitedUser(testUser3.username); - cy.wait(TIMEOUTS.ONE_SEC); - - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '2 SELECTED'); - - // * Verify that the user shows in the group of invited members - cy.findByText('SELECTED'). - parent(). - within(() => { - cy.findByText(testUser2.username); - cy.findByText(testUser3.username); - }); - }); - }); - }); - - it('allows removing users', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Open the invited users selector - cy.openSelector(); - - // # Add a couple of users - cy.addInvitedUser(testUser2.username); - cy.wait(TIMEOUTS.ONE_SEC); - cy.addInvitedUser(testUser3.username); - cy.wait(TIMEOUTS.ONE_SEC); - - // * Verify that the badge in the selector shows the correct number of members - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '2 SELECTED'); - - // # Remove the first users added - cy.get('.invite-users-selector__option'). - eq(0). - within(() => { - cy.findByText('Remove').click(); - }); - cy.wait(TIMEOUTS.ONE_SEC); - - // * Verify that there is only one user, the one not removed - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '1 SELECTED'); - - cy.findByText('SELECTED'). - parent(). - within(() => { - cy.get('.invite-users-selector__option'). - should('have.length', 1). - contains(testUser3.username); - }); - }); - }); - }); - - it('persists the list of users even if the toggle is off', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Open the invited users selector - cy.openSelector(); - - // # Add a couple of users - cy.addInvitedUser(testUser2.username); - cy.wait(TIMEOUTS.ONE_SEC); - cy.addInvitedUser(testUser3.username); - cy.wait(TIMEOUTS.ONE_SEC); - - // * Verify that the badge in the selector shows the correct number of members - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '2 SELECTED'); - - // # Click on the toggle to disable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - }); - }); - - cy.reload(); - - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // * Verify that the badge in the selector shows the correct number of members - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '2 SELECTED'); - - // # Open the invited users selector - cy.openSelector(); - - // * Verify that the user shows in the group of invited members - cy.findByText('SELECTED'). - parent(). - within(() => { - cy.findByText(testUser2.username); - cy.findByText(testUser2.username); - }); - }); - }); - }); - - describe('allow removing pre-assigned users with confirmation', () => { - beforeEach(() => { - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - checklists: [{ - title: 'Example', - items: [ - { - title: 'Untitled task', - assignee_id: testUser.id, - }, - ], - }], - invitedUserIds: [testUser.id], - inviteUsersEnabled: true, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - it('when removing an invited user', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - cy.get('#checklists').within(() => { - // * Verify user is pre-assigned - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText(`@${testUser.username}`).should('exist'); - }); - - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify invitations enabled and user is invited - cy.get('label input').should('be.checked'); - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '1 SELECTED'); - - cy.openSelector(); - - cy.get('.invite-users-selector__menu').within(() => { - // # Trigger remove for pre-assigned user - cy.findByText('Remove').click({force: true}); - }); - }); - }); - - // * Verify that confirmation dialog is open - cy.get('#confirmModal').should('be.visible'); - - // * Verify that confirmation dialog contains correct text - cy.get('#confirmModal').should('contain', 'Are you sure you want to stop inviting this user as a member of the run?'); - - // * Verify that the confirmation button is focused and click - cy.focused(). - should('have.id', 'confirmModalButton'). - click({force: true}); - - // * Verify that the confirmation dialog is closed - cy.get('#confirmModal').should('not.exist'); - - cy.reload(); - - cy.get('#checklists').within(() => { - // * Verify that user is not pre-assigned anymore - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText('Assignee...').should('exist'); - }); - - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that user is not invited anymore - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', ''); - }); - }); - }); - - it('when disabling invitations', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - cy.get('#checklists').within(() => { - // * Verify user is pre-assigned - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText(`@${testUser.username}`).should('exist'); - }); - - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify invitations are enabled and user is invited - cy.get('label input').should('be.checked'); - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '1 SELECTED'); - - // # Disable invitations - cy.get('label input').click({force: true}); - }); - }); - - // * Verify that confirmation dialog is open - cy.get('#confirmModal').should('be.visible'); - - // * Verify that confirmation dialog contains correct text - cy.get('#confirmModal').should('contain', 'Are you sure you want to disable invitations?'); - - // * Verify that the confirmation button is focused and click - cy.focused(). - should('have.id', 'confirmModalButton'). - click({force: true}); - - // * Verify that confirmation dialog is closed - cy.get('#confirmModal').should('not.exist'); - - cy.reload(); - - cy.get('#checklists').within(() => { - // * Verify that user is not pre-assigned - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText('Assignee...').should('exist'); - }); - - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify that invitations are disabled and no user is invited - cy.get('label input').should('not.be.checked'); - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', ''); - }); - }); - }); - }); - }); - - describe('assign owner setting', () => { - it('is disabled in a new playbook', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - // * Verify that the toggle is unchecked - cy.get('#assign-owner label input').should( - 'not.be.checked', - ); - }); - }); - - it('can be enabled', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#assign-owner').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - }); - }); - }); - - it('does not allow adding an owner when disabled', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#assign-owner').within(() => { - // * Verify that the toggle is unchecked - cy.get('input').should( - 'not.be.checked', - ); - - // * Verify that the menu is disabled - cy.getStyledComponent('StyledReactSelect').should( - 'have.class', - 'assign-owner-selector--is-disabled', - ); - }); - }); - }); - - it('allows adding users when enabled', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#assign-owner').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Open the owner selector - cy.openSelector(); - - // # Select a owner - cy.selectOwner(testUser2.username); - - // * Verify that the control shows the selected owner - cy.get('.assign-owner-selector__control').contains( - testUser2.username, - ); - }); - }); - }); - - it('allows changing the owner', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # select the actions section - cy.get('#actions').within(() => { - cy.get('#assign-owner').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Open the owner selector - cy.openSelector(); - - // # Select a owner - cy.selectOwner(testUser2.username); - - // * Verify that the control shows the selected owner - cy.get('.assign-owner-selector__control').contains( - testUser2.username, - ); - - // # Open the owner selector - cy.get('.assign-owner-selector__control').click({ - force: true, - }); - - // # Select a new owner - cy.selectOwner(testUser3.username); - - // * Verify that the control shows the selected owner - cy.get('.assign-owner-selector__control').contains( - testUser3.username, - ); - }); - }); - }); - }); - }); - }; - - describe('actions toggled', () => { - let testPlaybook; - - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - commonActionTests(); - - describe('link to an existing channel setting', () => { - beforeEach(() => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - }); - - it('can be checked', () => { - // # select the action section. - cy.get('#actions #link-existing-channel').within(() => { - // * Verify that the toggle is unchecked and input is disabled - cy.get('input[type=radio]').should('not.be.checked'); - cy.get('input[type=text]').should('be.disabled'); - - // # click radio - cy.get('input[type=radio]').click(); - - // * Verify that the toggle is checked and input is enabled - cy.get('input[type=radio]').should('be.checked'); - cy.get('input[type=text]').should('not.be.disabled'); - }); - }); - - it('create channel choices are disabled when is checked', () => { - // # select the action section. - cy.get('#actions #link-existing-channel').within(() => { - // # click radio - cy.get('input[type=radio]').click(); - }); - - // # select the action section. - cy.get('#actions #create-new-channel').within(() => { - // * Verify that the toggle is unchecked and inputs are disabled - cy.get('input[type=radio]').eq(0).should('not.be.checked'); - cy.get('label input[type=radio]').should('be.disabled'); - cy.get('button').should('be.disabled'); - }); - }); - }); - }); - - describe('actions', () => { - let testPrivateChannel; - let testPlaybook; - - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public channel - cy.apiCreateChannel( - testTeam.id, - 'public-channel', - 'Public Channel', - 'O', - ); - - // # Create a private channel - cy.apiCreateChannel( - testTeam.id, - 'private-channel', - 'Private Channel', - 'P', - ).then(({channel}) => { - testPrivateChannel = channel; - }); - }); - - beforeEach(() => { - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - describe('when an update is posted', () => { - describe('broadcast channel setting', () => { - it('none configured in a new playbook', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - cy.get('#status-updates').within(() => { - cy.findByText('no channels').should('be.visible'); - }); - }); - - it('can change channel and edit is saved immediately', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - cy.get('#status-updates').within(() => { - cy.findByText('no channels').click(); - }); - cy.findByText(/off-topic/i).click(); - - cy.reload(); - - cy.get('#status-updates').within(() => { - cy.findByText('1 channel').should('be.visible'); - }); - }); - - it('persists selected channels when status update toggle is off', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Add a channel and turn off the - // # status updates toggle - cy.get('#status-updates').within(() => { - cy.findByText('no channels').click(); - }); - cy.findByText(/off-topic/i).click(); - - // # Close the channel selector - cy.findByText(/search for a channel/i).type('{esc}'); - - cy.get('#status-updates').trigger('mouseenter').within(() => { - // # Click on the toggle to disable the setting - cy.get('label').click(); - - // * Verify that the toggle off - cy.get('label input').should('not.be.checked'); - }); - - // * Verify disabled status updates text - cy.findByText(/status updates are not expected/i).should('exist'); - cy.reload(); - - // # Turn the status update toggle back on - // * Verify there's still 1 channel selected - cy.get('#status-updates').trigger('mouseenter').within(() => { - cy.get('label').click(); - cy.findByText('1 channel').should('be.visible'); - }); - }); - - it('removes the channel and disables the setting if the channel no longer exists', () => { - // # Create a playbook with a user that is later removed from the team - cy.apiLogin(testSysadmin). - then(() => { - const channelDisplayName = String( - 'Channel to delete ' + Date.now(), - ); - const channelName = channelDisplayName. - replace(/ /g, '-'). - toLowerCase(); - cy.apiCreateChannel( - testTeam.id, - channelName, - channelDisplayName, - ).then(({channel}) => { - // # Create a playbook with the channel to be deleted as the announcement channel - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - createPublicPlaybookRun: true, - memberIDs: [testUser.id, testSysadmin.id], - announcementChannelId: channel.id, - announcementChannelEnabled: true, - }); - - // # Delete channel - cy.apiDeleteChannel(channel.id); - }); - }). - then(() => { - cy.apiLogin(testUser); - - // # Navigate again to the playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - cy.get('#status-updates').within(() => { - cy.findByText('no channels').should('be.visible'); - }); - }); - }); - - it('shows channel name when private broadcast channel configured and user is a member', () => { - // # Visit the selected playbook - cy.visit('/playbooks/playbooks/' + testPlaybook.id + '/outline'); - - // * Verify no channel is selected - cy.findByTestId('status-update-broadcast-channels').should( - 'have.text', - 'no channels', - ); - - // # Open the broadcast channel widget - cy.findByTestId('status-update-broadcast-channels').click(); - - // # select a private channel - cy.get('#floating-ui-root').within(() => { - cy.get('input').type(`${testPrivateChannel.display_name}{enter}{esc}`); - }); - - // * Verify placeholder text is present - cy.findByTestId('status-update-broadcast-channels').should( - 'have.text', - '1 channel', - ); - - // # Visit the selected playbook - cy.visit('/playbooks/playbooks/' + testPlaybook.id + '/outline'); - - // * Verify placeholder text is present - cy.findByTestId('status-update-broadcast-channels').should( - 'have.text', - '1 channel', - ); - - // # Open the broadcast channel widget - cy.findByTestId('status-update-broadcast-channels').click(); - - // * Verify channel name displayed - cy.get('#floating-ui-root').within(() => { - cy.findByText(testPrivateChannel.display_name).should('be.visible'); - }); - }); - }); - }); - - describe('when a new member joins the channel', () => { - beforeEach(() => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - cy.findByTestId('playbook-channel-actions-button').click(); - }); - - describe('add the channel to a sidebar category', () => { - it('is disabled in a new playbook', () => { - cy.findByTestId('user-joins-channel-categorize').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - }); - }); - - it('can be enabled', () => { - cy.findByTestId('user-joins-channel-categorize').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label').eq(1).click(); - - // * Verify that the toggle is unchecked - cy.get('label input').should('be.checked'); - }); - }); - - it('prevents category selection when disabled', () => { - // * Verify that the toggle is unchecked - cy.findByTestId('user-joins-channel-categorize').within(() => { - cy.get('label input').should('not.be.checked'); - cy.getStyledComponent('StyledCreatable').should('not.exist'); - }); - }); - - it('persists the category even if the toggle is off', () => { - cy.findByTestId('user-joins-channel-categorize').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.getStyledComponent('Container').click(); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Open the channel selector - openCategorySelector(); - - // # Select a channel - selectCategory('Favorites'); - - // * Verify that the control shows the selected category - cy.get('.channel-selector__control').contains('Favorites'); - - // # Click on the toggle to disable the setting - cy.getStyledComponent('Container').click(); - - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - }); - cy.findByTestId('modal-confirm-button').click(); - cy.reload(); - - cy.findByTestId('playbook-channel-actions-button').click(); - - cy.findByTestId('user-joins-channel-categorize').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.getStyledComponent('Container').click(); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // * Verify that the control still shows the selected category - cy.get('.channel-selector__control').contains('Favorites'); - }); - }); - - it('shows new category name when category was created', () => { - cy.findByTestId('user-joins-channel-categorize').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label').eq(1).click(); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - }); - - // # Type name to use new custom category - cy.get('.channel-selector__control').click().type('Custom category{enter}', {delay: 200}); - - // # click save modal - cy.findByTestId('modal-confirm-button').click(); - - // # reload to check that changes aren't local - cy.reload(); - - // # Open the channel modal - cy.findByTestId('playbook-channel-actions-button').click(); - - cy.findByTestId('user-joins-channel-categorize').within(() => { - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // * Verify that the control still shows the new category - cy.get('.channel-selector__control').should( - 'have.text', - 'Custom category', - ); - }); - }); - }); - }); - - describe('status updates enable / disabled', () => { - beforeEach(() => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - }); - - it('is enabled in a new playbook', () => { - // * Verify that the toggle is checked - cy.get('#status-updates label input').should('be.checked'); - }); - - it('can be disabled', () => { - // * Verify that toggle can be disabled - cy.get('#status-updates').within(() => { - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - }); - - // * Verify disabled status updates text - cy.findByText(/status updates are not expected/i).should('be.visible'); - cy.reload(); - cy.findByText(/status updates are not expected/i).should('be.visible'); - }); - }); - - describe('retrospective enable / disable', () => { - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - }); - - it('is enabled in a new playbook', () => { - cy.get('#retrospective').within(() => { - // * Verify that the toggle is checked - cy.get('input[type=checkbox]').should('be.checked'); - }); - }); - - it('can be disabled', () => { - cy.get('#retrospective').within(() => { - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - - // # Click on the toggle to disable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - cy.findByText(/a retrospective is not expected/i).should('exist'); - }); - }); - - it('saves on toggle', () => { - cy.get('#retrospective').within(() => { - // # Uncheck toggle - cy.get('label input').click({force: true}); - }); - - cy.reload(); - - cy.get('#retrospective').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/checklists_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/checklists_spec.js deleted file mode 100644 index 06b1d8cb85..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/checklists_spec.js +++ /dev/null @@ -1,185 +0,0 @@ -// 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('playbooks > edit', {testIsolation: true}, () => { - let testUser; - - before(() => { - cy.apiInitSetup().then(({user}) => { - testUser = user; - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('checklists', () => { - describe('pre-assignee', () => { - it('user gets pre-assigned, added to invite user list, and invitations become enabled', () => { - // # Open Playbooks - cy.visit('/playbooks/playbooks'); - - // # Start a blank playbook - cy.findByText('Blank').click(); - cy.findByText('Outline').click(); - - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify invitations are disabled and no invited user exists - cy.get('label input').should('not.be.checked'); - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', ''); - }); - }); - - // # Pre-assign the user - cy.get('#checklists').within(() => { - // # Trigger assignee select menu - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText('Assignee...').click(); - - // * Verify that the assignee input is focused now - cy.focused(). - should('have.attr', 'type', 'text'). - should('have.attr', 'id'); - - // * Verify that the root of the assignee select menu exists - cy.focused().parents('.playbook-react-select'). - should('exist'). - within(() => { - // # Select the test user - cy.findByText('@' + testUser.username).click(); - }); - }); - - cy.reload(); - - cy.get('#checklists').within(() => { - // # Trigger assignee select menu - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText('@' + testUser.username).click(); - - // * Verify that the assignee input is focused now - cy.focused(). - should('have.attr', 'type', 'text'). - should('have.attr', 'id'); - - // * Verify that the root of the assignee select menu exists - cy.focused(). - parents('.playbook-react-select'). - should('exist'); - }); - - cy.get('#actions').within(() => { - cy.get('#invite-users').within(() => { - // * Verify invitations are enabled and a single user is invited - cy.get('label input').should('be.checked'); - cy.get('.invite-users-selector__control'). - after('content'). - should('eq', '1 SELECTED'); - }); - }); - }); - }); - - describe('slash command', () => { - it('autocompletes after clicking Command...', () => { - // # Open Playbooks - cy.visit('/playbooks/playbooks'); - - // # Start a blank playbook - cy.findByText('Blank').click(); - cy.findByText('Outline').click(); - - cy.get('#checklists').within(() => { - // # Open the slash command input on a step - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText('Command...').click(); - - // * Verify the slash command input field now has focus - // * and starts with a slash prefix. - cy.focused(). - should('have.attr', 'placeholder', 'Slash Command'). - should('have.value', '/'); - }); - - // * Verify the autocomplete prompt is open - cy.get('#suggestionList').should('exist'); - }); - - it('resets when saving with an empty slash command', () => { - // # Open Playbooks - cy.visit('/playbooks/playbooks'); - - // # Start a blank playbook - cy.findByText('Blank').click(); - cy.findByText('Outline').click(); - - cy.get('#checklists').within(() => { - // # Open the slash command input on a step - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText('Command...').click(); - }); - - cy.get('#floating-ui-root').within(() => { - // * Verify the slash command input field now has focus - // * and starts with a slash prefix. - cy.findByPlaceholderText('Slash Command').should('have.focus'); - cy.findByPlaceholderText('Slash Command').should('have.value', '/'); - - cy.findByPlaceholderText('Slash Command').type('{backspace}'); - - // # Click the save button - cy.findByText('Save').click(); - }); - - // * Verify no slash command was saved - cy.findByText('Command...').should('be.visible'); - }); - - it('removes the input prompt when blurring with an invalid slash command', () => { - // # Open Playbooks - cy.visit('/playbooks/playbooks'); - - // # Start a blank playbook - cy.findByText('Blank').click(); - cy.findByText('Outline').click(); - - cy.get('#checklists').within(() => { - // # Open the slash command input on a step - cy.findByText('Untitled task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - cy.findByText('Command...').click(); - }); - - cy.get('#floating-ui-root').within(() => { - // * Verify the slash command input field now has focus - // * and starts with a slash prefix. - cy.findByPlaceholderText('Slash Command').should('have.focus'); - cy.findByPlaceholderText('Slash Command').should('have.value', '/'); - - // # Click the save button - cy.findByText('Save').click(); - }); - - // * Verify no slash command was saved - cy.findByText('Command...').should('be.visible'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/header_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/header_spec.js deleted file mode 100644 index 22d4342b56..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/header_spec.js +++ /dev/null @@ -1,99 +0,0 @@ -// 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('playbooks > edit', {testIsolation: true}, () => { - let testTeam; - let testUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('Edit playbook name', () => { - it('can be updated', () => { - // # Open Playbooks - cy.visit('/playbooks/playbooks'); - - // # Start a blank playbook - cy.findByText('Blank').click(); - - // # Open the title dropdown and Rename - cy.findByTestId('playbook-editor-title').click(); - cy.findByText('Rename').click(); - - // # Change the name and save - cy.findByTestId('rendered-editable-text').type('{selectAll}{del}renamed playbook'); - cy.findByRole('button', {name: /save/i}).click(); - - cy.reload(); - - // * Verify the modified name persists - cy.findByRole('button', {name: /renamed playbook/i}).should('exist'); - }); - }); - - describe('Edit playbook description', () => { - it('can be updated', () => { - // # Open Playbooks - cy.visit('/playbooks/playbooks'); - - // # Start a blank playbook - cy.findByText('Blank').click(); - cy.findByText(/customize this playbook's description/i).dblclick(); - cy.focused().type('{selectAll}{del}some new description'); - cy.findByRole('button', {name: /save/i}).click(); - - cy.reload(); - - cy.findByText('some new description').should('exist'); - }); - }); - - describe('Duplicate', () => { - let testPlaybook; - beforeEach(() => { - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - it('can be duplicated', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Open the title dropdown and Duplicate - cy.findByTestId('playbook-editor-title').click(); - cy.findByText('Duplicate').click(); - - // * Verify that playbook got duplicated - cy.findByTestId('playbook-editor-header').within(() => { - cy.findByText('Copy of ' + testPlaybook.title).should('exist'); - }); - - // * Verify that the duplicated playbook is shown in the LHS - cy.findByTestId('Playbooks').within(() => { - cy.findByText('Copy of ' + testPlaybook.title).should('be.visible'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/task_actions_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/task_actions_spec.js deleted file mode 100644 index 15442d7884..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit/task_actions_spec.js +++ /dev/null @@ -1,465 +0,0 @@ -// 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 * as TIMEOUTS from '../../../../fixtures/timeouts'; - -describe('playbooks > edit > task actions', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testUser2; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateUser().then(({user: user2}) => { - testUser2 = user2; - - // # Add this new user to the team - cy.apiAddUserToTeam(team.id, testUser2.id); - }); - }); - }); - - let testPlaybook; - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - checklists: [{ - title: 'Test Checklist', - items: [ - {title: 'Test Task'}, - ], - }], - memberIDs: [ - testUser.id, - ], - }).then((playbook) => { - testPlaybook = playbook; - - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - }); - }); - - const editTask = () => { - cy.findByTestId('checkbox-item-container').within(() => { - cy.findByText('Test Task').trigger('mouseover'); - cy.findByTestId('hover-menu-edit-button').click(); - }); - }; - - it('disallows no keywords', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify no actions are configured - cy.findByText('Task Actions').should('exist'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, []); - assert.deepEqual(trigger.user_ids, []); - assert.isFalse(actions.enabled); - }); - }); - - it('allows a single keyword', () => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // Enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - - // # assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'taskactions_updated', - type: 'track', - properties: { - playbook_id: testPlaybook.id, - }, - }, - ]); - }); - - it('allows multiple keywords', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add multiple keywords - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - cy.get('input').eq(0).type('keyword2{enter}', {force: true}); - }); - - // Enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1', 'keyword2']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - }); - - it('allows multi-word phrases', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add a phrase - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('a phrase with multiple words{enter}', {force: true}); - }); - - // Enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['a phrase with multiple words']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - }); - - it('allows removing previously configured keywords', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add multiple keywords - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - cy.get('input').eq(0).type('keyword2{enter}', {force: true}); - }); - - // Enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Re-open the dialog - cy.findByText('1 action').click(); - - // Remove one trigger keyword - cy.get('.modal-body').within(() => { - cy.findByText('keyword1').next().click(); - }); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword2']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - }); - - it('disables when all keywords removed', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add multiple keywords - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - cy.get('input').eq(0).type('keyword2{enter}', {force: true}); - }); - - // Enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Re-open the dialog - cy.findByText('1 action').click(); - - // Remove all trigger keywords - cy.get('.modal-body').within(() => { - cy.findByText('keyword1').next().click(); - cy.findByText('keyword2').next().click(); - }); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions - cy.findByText('Task Actions'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, []); - assert.deepEqual(trigger.user_ids, []); - assert.isFalse(actions.enabled); - }); - }); - - it('disallows a user without keywords', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add a user - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify no actions are configured - cy.findByText('Task Actions').should('exist'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, []); - assert.deepEqual(trigger.user_ids, [testUser.id]); - assert.isFalse(actions.enabled); - }); - }); - - it('allows a single user', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // Add a user - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions and user - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, [testUser.id]); - assert.isTrue(actions.enabled); - }); - }); - - it('allows configuring multiple users', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // Add two users - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - cy.get('input').eq(1). - type('@' + testUser2.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions and user - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, [testUser.id, testUser2.id]); - assert.isTrue(actions.enabled); - }); - }); - - it('rejects unknown user', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // Type an unknown user - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@unknown', {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // Click away - cy.get('.modal-body').click(); - - // Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions and user - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - }); - - it('allows removing previously configured users', () => { - // Open the task actions modal - editTask(); - cy.findByText('Task Actions').click(); - - // Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // Add two users - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - cy.get('input').eq(1). - type('@' + testUser2.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Re-open the dialog - cy.findByText('1 action').click(); - - // Remove one user keyword - cy.get('.modal-body').within(() => { - cy.findByText(testUser.username).parent().parent().next().click(); - }); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - const trigger = JSON.parse(playbook.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbook.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, [testUser2.id]); - assert.isTrue(actions.enabled); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit_metrics_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit_metrics_spec.js deleted file mode 100644 index 46c696fc43..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/edit_metrics_spec.js +++ /dev/null @@ -1,568 +0,0 @@ -// 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('playbooks > edit_metrics', {testIsolation: true}, () => { - let testTeam; - let testUser; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - }); - }); - - describe('actions', () => { - let testPlaybook; - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - - // # Set a bigger viewport so the action don't scroll out of view - cy.viewport('macbook-16'); - cy.intercept('PUT', '/plugins/playbooks/api/v0/playbooks/**').as('addMetric'); - }); - - describe('adding and editing metrics', () => { - it('can add 4, but not 5 metrics; can save and re-edit with metrics saved', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}`); - - // # Switch to Outline tab and focus retro section - cy.findByText('Outline').click(); - cy.get('#retrospective').scrollIntoView(); - - // # Add and verify metric - addMetric('Duration', 'test duration', '0:0:1', 'test description'); - verifyViewMetric(0, 'test duration', '1 minute per run', 'test description'); - - // # Add and verify metric - addMetric('Cost', 'test dollars', '2', 'test description 2'); - verifyViewMetric(1, 'test dollars', '2 per run', 'test description 2'); - - // # Add and verify metric - addMetric('Integer', 'test integer', '4', 'test descr 3'); - verifyViewMetric(2, 'test integer', '4 per run', 'test descr 3'); - - // # Add and verify metric - addMetric('Duration', 'test duration 2', '0:0:2', 'test description 4'); - verifyViewMetric(3, 'test duration 2', '2 minutes per run', 'test description 4'); - - // * Verify Add Metric button is inactive - cy.findByRole('button', {name: 'Add Metric'}).should('be.disabled'); - - // * Verify we have four valid metrics and are editing none. - verifyViewsAndEdits(4, 0); - - // Refresh the page - cy.reload(); - - // * Verify we saved the metrics - verifyViewMetric(0, 'test duration', '1 minute per run', 'test description'); - verifyViewMetric(1, 'test dollars', '2 per run', 'test description 2'); - verifyViewMetric(2, 'test integer', '4 per run', 'test descr 3'); - verifyViewMetric(3, 'test duration 2', '2 minutes per run', 'test description 4'); - - // # Edit all 4 metrics and repeat the test - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.get('input[type=text]').eq(2).clear().type('12:8:97'); - saveMetric(); - cy.findAllByTestId('edit-metric').eq(1).click(); - cy.get('textarea').eq(0).clear().type('a new description'); - saveMetric(); - cy.findAllByTestId('edit-metric').eq(2).click(); - cy.get('input[type=text]').eq(2).clear().type('7777777'); - saveMetric(); - cy.findAllByTestId('edit-metric').eq(3).click(); - cy.get('input[type=text]').eq(1).clear().type('test duration 2!!!'); - saveMetric(); - - // # Refresh the page - cy.reload(); - - // * Verify we saved the metrics - verifyViewMetric(0, 'test duration', '12 days, 9 hours, 37 minutes per run', 'test description'); - verifyViewMetric(1, 'test dollars', '2 per run', 'a new description'); - verifyViewMetric(2, 'test integer', '7777777 per run', 'test descr 3'); - verifyViewMetric(3, 'test duration 2!!!', '2 minutes per run', 'test description 4'); - - // # Now test: verifies when clicking "Add", for duration type - // # (using the previous state) - - // # Edit the first metric - cy.findAllByTestId('edit-metric').eq(0).click(); - - // * Metrics need a title - cy.get('input[type=text]').eq(1).clear(); - saveMetric(); - cy.getStyledComponent('ErrorText').contains('Please add a title for your metric.'); - - // * Metrics need a unique title - cy.get('input[type=text]').eq(1).type('test dollars'); - saveMetric(); - cy.getStyledComponent('ErrorText'). - contains('A metric with the same name already exists. Please add a unique name for each metric.'); - - // * A duration target needs to be in the correct format (no letters) - cy.get('input[type=text]').eq(1).clear().wait(100).type('test duration again'); - cy.get('input[type=text]').eq(2).clear().type('a'); - saveMetric(); - cy.getStyledComponent('ErrorText'). - contains('Please enter a duration in the format: dd:hh:mm (e.g., 12:00:00), or leave the target blank.'); - - // * A duration target needs to be in the correct format (mm:dd:ss) - cy.get('input[type=text]').eq(2).clear().type('0:123:0'); - saveMetric(); - cy.getStyledComponent('ErrorText'). - contains('Please enter a duration in the format: dd:hh:mm (e.g., 12:00:00), or leave the target blank.'); - - // # A duration can have 1 or 2 numbers in each position - cy.get('input[type=text]').eq(2).clear().type('2:12:1'); - saveMetric(); - verifyViewMetric(0, 'test duration again', '2 days, 12 hours, 1 minute per run', 'test description'); - - // * Verify we have four valid metrics and are editing none. - verifyViewsAndEdits(4, 0); - - // # Now test: on clicking edit, closes & saves current editing metric, and switches - // # (using the previous state) - - // # Edit the second metric - cy.findAllByTestId('edit-metric').eq(1).click(); - - // * Verify editing correct metric, and only this metric - cy.getStyledComponent('EditContainer').should('have.length', 1).within(() => { - cy.get('input[type=text]').eq(0).should('have.value', 'test dollars'); - }); - cy.getStyledComponent('ViewContainer').should('have.length', 3); - - // # Switch to editing third metric (second is in edit mode, so this is the third:) - cy.findAllByTestId('edit-metric').eq(1).click(); - - // * Verify editing correct metric, and only this metric - cy.getStyledComponent('EditContainer').should('have.length', 1).within(() => { - cy.get('input[type=text]').eq(0).should('have.value', 'test integer'); - }); - cy.getStyledComponent('ViewContainer').should('have.length', 3); - - // # Edit third metric's title, switch to another metric - cy.getStyledComponent('EditContainer').should('have.length', 1).within(() => { - cy.get('input[type=text]').eq(0).clear().type('test integer222'); - }); - cy.findAllByTestId('edit-metric').eq(0).click(); - - // * Verify the title on the third metric (the second in view mode) was saved on switching - verifyViewMetric(1, 'test integer222', '7777777 per run', 'test descr 3'); - - // * Verify we have three valid metrics and are editing one. - verifyViewsAndEdits(3, 1); - }); - }); - - describe('adding and editing metrics (new playbook)', () => { - it('verifies when clicking "Add Metric", for Currency type, and switches to new edit', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}`); - - // # Switch to Outline tab and focus retro section - cy.findByText('Outline').click(); - cy.get('#retrospective').scrollIntoView(); - - // # Add and verify 1st metric - addMetric('Integer', 'test integer!', '12314123', 'test description'); - verifyViewMetric(0, 'test integer!', '12314123 per run', 'test description'); - - // # Add metric - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Cost').click(); - }); - - // # Don't fill in the metric's details - cy.get('input[type=text]').eq(1).clear(); - - // * Metrics need a title - cy.get('input[type=text]').eq(1).clear(); - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Integer').click(); - }); - cy.getStyledComponent('ErrorText').contains('Please add a title for your metric.'); - - // * Metrics need a unique title - cy.get('input[type=text]').eq(1).type('test integer!'); - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Integer').click(); - }); - cy.getStyledComponent('ErrorText'). - contains('A metric with the same name already exists. Please add a unique name for each metric.'); - - // # Fill in title - cy.get('input[type=text]').eq(1).clear().type('test currency!'); - - // * A Currency target cannot be text - cy.get('input[type=text]').eq(2).clear().type('z'); - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Integer').click(); - }); - cy.getStyledComponent('ErrorText').contains('Please enter a number, or leave the target blank.'); - - // * A Currency target /can/ be blank, so can the description, and Add next Integer metric - cy.get('input[type=text]').eq(2).clear(); - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Integer').click(); - }); - cy.getStyledComponent('EditContainer').should('be.visible'); - - // * Verify metric was added without target or description. - verifyViewMetric(1, 'test currency!', '', ''); - - // * Verify we have two valid metrics and are editing next one. - verifyViewsAndEdits(2, 1); - - // # Now test: verifies when clicking edit button, for Currency type, and switches to next edit - // # (using the previous state) - - // # Don't fill in the metric's details - cy.get('input[type=text]').eq(1).clear(); - - // * Metrics need a title - cy.get('input[type=text]').eq(1).clear(); - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.getStyledComponent('ErrorText').contains('Please add a title for your metric.'); - - // * Metrics need a unique title - cy.get('input[type=text]').eq(1).type('test currency!'); - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.getStyledComponent('ErrorText'). - contains('A metric with the same name already exists. Please add a unique name for each metric.'); - - // # Fill in title - cy.get('input[type=text]').eq(1).clear().type('test integer #2!!'); - - // * An Integer target cannot be text - cy.get('input[type=text]').eq(2).clear().type('arsoton'); - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.getStyledComponent('ErrorText').contains('Please enter a number, or leave the target blank.'); - - // * An Integer target /can/ be blank, so can the description, and edit first metric - cy.get('input[type=text]').eq(2).clear(); - cy.findAllByTestId('edit-metric').eq(0).click(); - - // * Verify we're editing the first metric, and only this metric - cy.getStyledComponent('EditContainer').should('have.length', 1).within(() => { - cy.get('input[type=text]').eq(0).should('have.value', 'test integer!'); - }); - cy.getStyledComponent('ViewContainer').should('have.length', 2); - - // # Stop editing - saveMetric(); - - // * Verify metric was added without target or description. - verifyViewMetric(2, 'test integer #2!!', '', ''); - - // * Verify we have three valid metrics and are editing none. - verifyViewsAndEdits(3, 0); - }); - }); - - describe('delete metric', () => { - it('verifies when clicking delete button; saved metrics have different confirmation text; deleted metrics are deleted', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}`); - - // # Switch to Outline tab and focus retro section - cy.findByText('Outline').click(); - cy.get('#retrospective').scrollIntoView(); - - // # Add and verify 1st metric - addMetric('Integer', 'test integer!', '12314123', 'test description'); - verifyViewMetric(0, 'test integer!', '12314123 per run', 'test description'); - - // # Add metric - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Cost').click(); - }); - - // # Don't fill in the metric's details - cy.get('input[type=text]').eq(1).clear(); - - // * Metrics need a title - cy.get('input[type=text]').eq(1).clear(); - cy.findAllByTestId('delete-metric').eq(0).click(); - cy.getStyledComponent('ErrorText').contains('Please add a title for your metric.'); - - // * Metrics need a unique title - cy.get('input[type=text]').eq(1).type('test integer!'); - cy.findAllByTestId('delete-metric').eq(0).click(); - cy.getStyledComponent('ErrorText'). - contains('A metric with the same name already exists. Please add a unique name for each metric.'); - - // # Fill in title - cy.get('input[type=text]').eq(1).clear().type('test currency!'); - - // * A Currency target cannot be text - cy.get('input[type=text]').eq(2).clear().type('z'); - cy.findAllByTestId('delete-metric').eq(0).click(); - cy.getStyledComponent('ErrorText').contains('Please enter a number, or leave the target blank.'); - - // # Remove error text and type another invalid entry - cy.get('input[type=text]').eq(2).clear().type('invalid'); - - // * Verify that we're allowed to delete a metric we are currently editing (even if it's invalid) - cy.findAllByTestId('delete-metric').eq(1).click(); - cy.get('#confirm-modal-light').should('be.visible').contains('Are you sure you want to delete?'); - - // # Should see the confirmation /without/ extra text because we haven't saved this metric yet - cy.get('#confirm-modal-light'). - should('not.contain.text', 'You will still be able to access historical data for this metric.'); - - // # Dismiss - cy.findByRole('button', {name: 'Cancel'}).click(); - - // * A Currency target /can/ be blank, so can the description, try to delete first metric - cy.get('input[type=text]').eq(2).clear(); - cy.findAllByTestId('delete-metric').eq(0).click(); - - cy.get('#confirm-modal-light'). - should('contain.text', 'If you delete this metric, the values for it will not be collected for any future runs.'); - - // # Delete first metric - cy.findByRole('button', {name: 'Delete metric'}).click(); - - // * Verify metric - verifyViewsAndEdits(1, 0); - verifyViewMetric(0, 'test currency!', '', ''); - - // # Make sure we can still edit and add a metric after deleting one (testing that the metrics - // component's state isn't broken) - addMetric('Integer', 'test integer 2!', '123', 'test description'); - verifyViewMetric(1, 'test integer 2!', '123 per run', 'test description'); - cy.findAllByTestId('delete-metric').eq(1).click(); - cy.findByRole('button', {name: 'Delete metric'}).click(); - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.get('input[type=text]').eq(1).clear().type('test currency 2!'); - saveMetric(); - verifyViewsAndEdits(1, 0); - verifyViewMetric(0, 'test currency 2!', '', ''); - - // # Make sure we can add a metric and then delete it, then can keep editing - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Cost').click(); - }); - cy.findAllByTestId('delete-metric').eq(1).click(); - cy.findByRole('button', {name: 'Delete metric'}).click(); - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.get('input[type=text]').eq(1).clear().type('test currency 3!'); - saveMetric(); - verifyViewsAndEdits(1, 0); - verifyViewMetric(0, 'test currency 3!', '', ''); - - // # Make sure we can add a metric and then delete it, then can keep adding - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Cost').click(); - }); - cy.findAllByTestId('delete-metric').eq(1).click(); - cy.findByRole('button', {name: 'Delete metric'}).click(); - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText('Cost').click(); - }); - cy.findAllByTestId('delete-metric').eq(1).click(); - cy.findByRole('button', {name: 'Delete metric'}).click(); - verifyViewsAndEdits(1, 0); - verifyViewMetric(0, 'test currency 3!', '', ''); - - // # Refresh and verify one is saved - cy.reload(); - verifyViewsAndEdits(1, 0); - verifyViewMetric(0, 'test currency 3!', '', ''); - - // # Delete metric - cy.findAllByTestId('delete-metric').eq(0).click(); - - // # Should see the confirmation /with/ extra text - cy.get('#confirm-modal-light'). - should('contain.text', 'If you delete this metric, the values for it will not be collected for any future runs. You will still be able to access historical data for this metric.'); - - // # Delete first metric - cy.findByRole('button', {name: 'Delete metric'}).click(); - - // * Verify - verifyViewsAndEdits(0, 0); - - // # Refresh and verify deleted - cy.reload(); - verifyViewsAndEdits(0, 0); - }); - }); - - describe('nullable and 0-able targets', () => { - it('can add 0 targets and no (null) targets', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}`); - - // # Switch to Outline tab and focus retro section - cy.findByText('Outline').click(); - cy.get('#retrospective').scrollIntoView(); - - // # Add and verify duration - addMetric('Duration', 'test duration', '0:0:0', 'test description'); - verifyViewMetric(0, 'test duration', '0 seconds per run', 'test description'); - - // # Verify it shows 0:0:0, then turn it into null. - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.get('input[type=text]').eq(2).should('have.value', '00:00:00'). - clear(); - saveMetric(); - - // # Verify that the 'Target' section is gone - cy.getStyledComponent('ViewContainer'). - getStyledComponent('DetailDiv'). - should('have.length', 1); - - verifyViewMetric(0, 'test duration', '', 'test description'); - - // * Verify it has null value when editing again. - cy.findAllByTestId('edit-metric').eq(0).click(); - cy.get('input[type=text]').eq(2).should('have.value', ''); - saveMetric(); - - // # Add and verify currency - addMetric('Cost', 'test money', '0', 'test description 2'); - cy.wait('@addMetric'); - verifyViewMetric(1, 'test money', '0', 'test description 2'); - - // # Verify it shows 0, then turn it into null. - cy.findAllByTestId('edit-metric').eq(1).click(); - cy.get('input[type=text]').eq(2).should('have.value', '0'). - clear(); - saveMetric(); - cy.getStyledComponent('ViewContainer').should('have.length', 2).eq(1).within(() => { - // # Verify that the 'Target' section is gone - cy.getStyledComponent('DetailDiv'). - should('have.length', 1); - }); - - verifyViewMetric(1, 'test money', '', 'test description 2'); - - // * Verify it has null value when editing again. - cy.findAllByTestId('edit-metric').eq(1).click(); - cy.get('input[type=text]').eq(2).should('have.value', ''); - saveMetric(); - - // # Add and verify Integer - addMetric('Integer', 'test number', '0', 'test description 3'); - cy.wait('@addMetric'); - verifyViewMetric(2, 'test number', '0', 'test description 3'); - - // # Verify it shows 0, then turn it into null. - cy.findAllByTestId('edit-metric').eq(2).click(); - cy.get('input[type=text]').eq(2).should('have.value', '0'). - clear(); - saveMetric(); - cy.getStyledComponent('ViewContainer').should('have.length', 3).eq(2).within(() => { - // # Verify that the 'Target' section is gone - cy.getStyledComponent('DetailDiv'). - should('have.length', 1); - }); - - verifyViewMetric(2, 'test number', '', 'test description 3'); - - // * Verify it has null value when editing again. - cy.findAllByTestId('edit-metric').eq(2).click(); - cy.get('input[type=text]').eq(2).should('have.value', ''); - saveMetric(); - - // * Verify we have three valid metrics and are editing none. - verifyViewsAndEdits(3, 0); - - // # Refresh - cy.reload(); - - // * Verify we saved the metrics - verifyViewMetric(0, 'test duration', '', 'test description'); - verifyViewMetric(1, 'test money', '', 'test description 2'); - verifyViewMetric(2, 'test number', '', 'test description 3'); - }); - }); - }); -}); - -const addMetric = (type, title, target, description) => { - const fullType = type === 'Duration' ? 'Duration (in dd:hh:mm)' : type; - - // # Add the requested metric - cy.findByRole('button', {name: 'Add Metric'}).click(); - cy.findByTestId('dropdownmenu').within(() => { - cy.findByText(fullType).click(); - }); - - // # Fill in the metric's details - cy.get('input[type=text]').eq(1).type(title). - tab().type(target). - tab().type(description); - - // # Add the metric - saveMetric(); - cy.wait('@addMetric'); -}; - -const verifyViewMetric = (index, title, target, description) => { - cy.getStyledComponent('ViewContainer').should('have.length.of.at.least', index + 1).eq(index).within(() => { - cy.getStyledComponent('Title').should('have.text', title); - - if (target) { - cy.getStyledComponent('DetailDiv').eq(0).contains(target); - } - - if (description) { - const idx = target ? 1 : 0; - cy.getStyledComponent('DetailDiv').eq(idx).contains(description); - } - }); -}; - -const verifyViewsAndEdits = (numViews, numEdits) => { - if (numViews === 0) { - cy.getStyledComponent('ViewContainer').should('not.exist'); - } else { - cy.getStyledComponent('ViewContainer').should('have.length', numViews); - } - - if (numEdits === 0) { - cy.getStyledComponent('EditContainer').should('not.exist'); - } else { - cy.getStyledComponent('EditContainer').should('have.length', numEdits); - } -}; - -function saveMetric() { - cy.get('#retrospective-metrics').within(() => { - cy.findByRole('button', {name: 'Save'}).click(); - }); -} diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/feedback_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/feedback_spec.js deleted file mode 100644 index 80a6de25cf..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/feedback_spec.js +++ /dev/null @@ -1,75 +0,0 @@ -// 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('playbooks > feedback', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as admin to create team and user below. - cy.apiAdminLogin(); - - // # Setup a team, user and playbook for each test. - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Test Playbook', - memberIDs: [], - }).then((playbook) => { - testPlaybook = playbook; - }); - - // # Login as the newly created testUser - cy.apiLogin(testUser); - }); - }); - - it('playbooks shows prompt in global header', () => { - // # Visit the playbooks product - cy.visit('/playbooks'); - - // # Verify Give Feedback link is configured to open in a new tab. - cy.findByText('Give feedback').invoke('attr', 'target').should('eq', '_blank'); - - // # Verify Give Feedback link href - cy.findByText('Give feedback').invoke('attr', 'href').should('match', /playbooks-feedback/); - }); - - it('playbooks shows prompt in rhs header', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - const playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Navigate directly to the application and the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Verify Give Feedback link is configured to open in a new tab. - cy.findByText('Give feedback').invoke('attr', 'target').should('eq', '_blank'); - - // # Verify Give Feedback link href - cy.findByText('Give feedback').invoke('attr', 'href').should('match', /playbooks-feedback/); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/list_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/list_spec.js deleted file mode 100644 index 6f383241cf..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/list_spec.js +++ /dev/null @@ -1,217 +0,0 @@ -// 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('playbooks > list', {testIsolation: true}, () => { - const playbookTitle = 'The Playbook Name'; - let testTeam; - let testUser; - let testUser2; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: user2}) => { - testUser2 = user2; - cy.apiAddUserToTeam(testTeam.id, testUser2.id); - }); - - // # Login as user-1 - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: playbookTitle, - memberIDs: [], - }); - - // # Create an archived public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook archived', - memberIDs: [], - }).then(({id}) => cy.apiArchivePlaybook(id)); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - it('has "Playbooks" in heading', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // * Assert contents of heading. - cy.findByTestId('titlePlaybook').should('exist').contains('Playbooks'); - }); - - it('join/leave playbook', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Click on the dot menu - cy.findByTestId('menuButtonActions').click(); - - // # Click on leave - cy.findByText('Leave').click(); - - // * Verify it has disappeared from the LHS - cy.findByTestId('lhs-navigation').findByText(playbookTitle).should('not.exist'); - - // # Join a playbook - cy.findByTestId('join-playbook').click(); - - // * Verify it has appeared in LHS - cy.findByTestId('lhs-navigation').findByText(playbookTitle).should('exist'); - }); - - it('can duplicate playbook', () => { - // # Login as testUser2 - cy.apiLogin(testUser2); - - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Click on the dot menu - cy.findByTestId('menuButtonActions').click(); - - // # Click on duplicate - cy.findByText('Duplicate').click(); - - // * Verify that playbook got duplicated - cy.findByText('Copy of ' + playbookTitle).should('exist'); - - // * Verify that the current user is a member and can run the playbook. - cy.findByText('Copy of ' + playbookTitle).closest('[data-testid="playbook-item"]').within(() => { - cy.findByTestId('run-playbook').should('exist'); - cy.findByTestId('join-playbook').should('not.exist'); - }); - - // * Verify that the duplicated playbook is shown in the LHS - cy.findByTestId('Playbooks').within(() => { - cy.findByText('Copy of ' + playbookTitle).should('be.visible'); - }); - }); - - context('archived playbooks', () => { - it('does not show them by default', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // * Assert the archived playbook is not there. - cy.findAllByTestId('playbook-title').should((titles) => { - expect(titles).to.have.length(2); - }); - }); - it('shows them upon click on the filter', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Click the With Archived button - cy.findByTestId('with-archived').click(); - - // * Assert the archived playbook is there. - cy.findAllByTestId('playbook-title').should((titles) => { - expect(titles).to.have.length(3); - }); - }); - }); - - describe('can import playbook', () => { - let validPlaybookExport; - let invalidTypePlaybookExport; - - const bufferToCypressFile = (fileName, fileData, fileType) => ({ - fileName, - contents: fileData, - mimeType: fileType, - }); - - before(() => { - // # Load fixtures and convert to File - cy.fixture('playbook-export.json', null).then((buffer) => { - validPlaybookExport = bufferToCypressFile('export.json', buffer, 'application/json'); - }); - cy.fixture('mp3-audio-file.mp3', null).then((buffer) => { - invalidTypePlaybookExport = bufferToCypressFile('audio.mp3', buffer, 'audio/mpeg'); - }); - }); - - it('triggered by drag and drop', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Drop loaded fixture onto playbook list - cy.findByTestId('playbook-list-scroll-container').selectFile(validPlaybookExport, { - action: 'drag-drop', - force: true, - }); - - // * Verify that a new playbook was created. - cy.findByTestId('playbook-editor-title').should('contain', 'Example Playbook'); - }); - - it('triggered by using button/input', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - cy.findByTestId('titlePlaybook').within(() => { - // # Select loaded fixture for upload - cy.findByTestId('playbook-import-input').selectFile(validPlaybookExport, {force: true}); - }); - - // * Verify that a new playbook was created. - cy.findByTestId('playbook-editor-title').should('contain', 'Example Playbook'); - }); - - it('fails to import invalid file type', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - cy.findByTestId('titlePlaybook').within(() => { - // # Select loaded fixture for upload - cy.findByTestId('playbook-import-input').selectFile(invalidTypePlaybookExport, {force: true}); - }); - - // * Verify that an error message is displayed. - cy.findByText('The file must be a valid JSON playbook template.').should('be.visible'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/overview_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/overview_spec.js deleted file mode 100644 index 60364f85d1..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/overview_spec.js +++ /dev/null @@ -1,468 +0,0 @@ -// 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 {stubClipboard} from '../../../utils'; - -describe('playbooks > overview', {testIsolation: true}, () => { - let testTeam; - let testOtherTeam; - let testUser; - let testUser2; - let testPublicPlaybook; - let testPlaybookOnTeamForSwitching; - let testPlaybookOnOtherTeamForSwitching; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: user2}) => { - testUser2 = user2; - cy.apiAddUserToTeam(testTeam.id, testUser2.id); - }); - - // # Create another team - cy.apiCreateTeam('second-team', 'Second Team').then(({team: createdTeam}) => { - testOtherTeam = createdTeam; - cy.apiAddUserToTeam(testOtherTeam.id, testUser.id); - - // # Create a dedicated run follower - cy.apiCreateUser().then(({user: createdUser}) => { - cy.apiAddUserToTeam(testTeam.id, createdUser.id); - cy.apiAddUserToTeam(testOtherTeam.id, createdUser.id); - }); - - // # Create another user - cy.apiCreateUser().then(({user: anotherUser}) => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - retrospectiveTemplate: 'Retro template text', - retrospectiveReminderIntervalSeconds: 60 * 60 * 24 * 7, // 7 days - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - - // # Create a private playbook with only the current user - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Private Only Mine Playbook', - memberIDs: [testUser.id], - }); - - // # Create a private playbook with multiple users - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Private Shared Playbook', - memberIDs: [testUser.id, anotherUser.id], - }); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Switch A', - memberIDs: [], - retrospectiveTemplate: 'Retro template text', - retrospectiveReminderIntervalSeconds: 60 * 60 * 24 * 7, // 7 days - }).then((playbook) => { - testPlaybookOnTeamForSwitching = playbook; - }); - - // # Create a public playbook on another team - cy.apiCreatePlaybook({ - teamId: testOtherTeam.id, - title: 'Switch B', - memberIDs: [], - }).then((playbook) => { - testPlaybookOnOtherTeamForSwitching = playbook; - }); - }); - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - }); - - it('redirects to not found error if the playbook is unknown', () => { - // # Visit the URL of a non-existing playbook - cy.visit('/playbooks/playbooks/an_unknown_id'); - - // * Verify that the user has been redirected to the playbooks not found error page - cy.url().should('include', '/playbooks/error?type=playbooks'); - }); - - describe('should switch to channels and prompt to run when clicking run', () => { - const openAndRunPlaybook = (team) => { - // # Navigate directly to town square on the team - cy.visit(`${team.name}/channels/town-square`); - - // # Open Playbooks - cy.get('[aria-label="Product switch menu"]').click({force: true}); - cy.get('a[href="/playbooks"]').click({force: true}); - - // Click through to open the playbook - cy.findByTestId('playbooksLHSButton').click({force: true}); - cy.get('[placeholder="Search for a playbook"]').type(testPlaybookOnTeamForSwitching.title); - cy.findByTestId('playbook-title').click({force: true}); - - // # Click Run Playbook - cy.findByTestId('run-playbook').click({force: true}); - - // * Verify the playbook run creation dialog has opened - cy.get('#playbooks_run_playbook_dialog').should('exist').within(() => { - cy.findByText('Start run').should('exist'); - }); - }; - - it('for testPlaybookOnTeamForSwitching from its own team', () => { - openAndRunPlaybook(testTeam, testPlaybookOnTeamForSwitching); - }); - - it('for testPlaybookOnTeamForSwitching from another team', () => { - openAndRunPlaybook(testOtherTeam, testPlaybookOnTeamForSwitching); - }); - - it('for testPlaybookOnOtherTeamForSwitching from its own team', () => { - openAndRunPlaybook(testTeam, testPlaybookOnOtherTeamForSwitching); - }); - - it('for testPlaybookOnOtherTeamForSwitchingOnOtherTeam from another team', () => { - openAndRunPlaybook(testOtherTeam, testPlaybookOnOtherTeamForSwitching); - }); - - it('on direct navigation to a playbook', () => { - // # Navigate directly to the playbook - cy.visit(`/playbooks/playbooks/${testPlaybookOnTeamForSwitching.id}`); - - // # Click Run Playbook - cy.findByTestId('run-playbook').click(); - - // * Verify the playbook run creation dialog has opened - cy.get('#playbooks_run_playbook_dialog').should('exist').within(() => { - cy.findByText('Start run').should('exist'); - }); - }); - }); - - it('should copy playbook link', () => { - // # Navigate directly to the playbook - cy.visit(`/playbooks/playbooks/${testPublicPlaybook.id}`); - - // # trigger the tooltip - cy.get('.icon-link-variant').trigger('mouseover', {force: true}); - - // * Verify tooltip text - cy.get('#copy-playbook-link-tooltip').should('contain', 'Copy link to'); - - stubClipboard().as('clipboard'); - - // # click on copy button - cy.get('.icon-link-variant').click({force: true}).then(() => { - // * Verify that tooltip text changed - cy.get('#copy-playbook-link-tooltip').should('contain', 'Copied!'); - - // * Verify clipboard content - cy.get('@clipboard').its('contents').should('contain', `/playbooks/playbooks/${testPublicPlaybook.id}`); - }); - }); - - it('should duplicate playbook', () => { - // # Login as testUser2 - cy.apiLogin(testUser2); - - // # Navigate directly to the playbook - cy.visit(`/playbooks/playbooks/${testPublicPlaybook.id}`); - - // # Click on playbook title - cy.findByTestId('playbook-editor-title').click(); - - // # Click on duplicate - cy.findByText('Duplicate').click(); - - // * Verify that playbook got duplicated - cy.findByTestId('playbook-editor-title').should('contain', `Copy of ${testPublicPlaybook.title}`); - - // * Verify that the current user is a member and can run the playbook. - cy.findByTestId('run-playbook').should('exist'); - cy.findByTestId('join-playbook').should('not.exist'); - - // * Verify that the current user is the only member. - cy.findByTestId('playbook-members').should('contain', '1'); - }); - - describe('checklists', () => { - describe('header', () => { - beforeEach(() => { - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - description: 'Cypress Playbook', - memberIDs: [], - checklists: [ - { - title: 'Stage 1', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - ], - }, - ], - retrospectiveTemplate: 'Cypress test template', - }).then((playbook) => { - cy.visit(`/playbooks/playbooks/${playbook.id}/outline`); - }); - }); - - it('has title', () => { - cy.get('#checklists').within(() => { - cy.findByText('Tasks').should('exist'); - }); - }); - }); - - it('shows checklists', () => { - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - description: 'Cypress Playbook', - memberIDs: [], - checklists: [ - { - title: 'Stage 1', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - ], - }, - ], - retrospectiveTemplate: 'Cypress test template', - }).then((playbook) => { - cy.visit(`/playbooks/playbooks/${playbook.id}`); - }); - - // # Switch to Outline section - cy.findByText('Outline').click(); - - // * Verify checklist and associated steps - cy.get('#checklists').within(() => { - cy.findByText('Stage 1').should('exist'); - cy.findByText('Step 1').should('exist'); - cy.findByText('Step 2').should('exist'); - }); - }); - }); - - it('shows correct retrospective timer and template text', () => { - cy.visit(`/playbooks/playbooks/${testPublicPlaybook.id}`); - cy.findByText('Outline').click(); - - cy.get('#retrospective').within(() => { - cy.findByText('7 days').should('exist'); - cy.findByText('Retro template text').should('exist'); - }); - }); - - it('shows statistics in usage tab', () => { - // # Start playbook run. - const now = Date.now(); - const playbookRunName = `Run (${now})`; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # Go to usage view - cy.visit(`/playbooks/playbooks/${testPublicPlaybook.id}`); - - // * Verify basic information. - cy.findByText('Runs currently in progress').next().should('contain', '1'); - cy.findByText('Participants currently active').next().should('contain', '1'); - cy.findByText('Runs finished in the last 30 days').next().should('contain', '0'); - - // # End the run so those metrics change. - cy.apiFinishRun(playbookRun.id).then(() => { - cy.reload(); - - // * Verify changes. - cy.findByText('Runs currently in progress').next().should('contain', '0'); - cy.findByText('Participants currently active').next().should('contain', '0'); - cy.findByText('Runs finished in the last 30 days').next().should('contain', '1'); - }); - }); - }); - - it('start a run', () => { - // # Visit playbook page - cy.visit(`/playbooks/playbooks/${testPublicPlaybook.id}`); - - // # Click Run Playbook - cy.findByTestId('run-playbook').click(); - - // # Enter the run name - cy.findByTestId('run-name-input').clear().type('run1234567'); - - // # Click start run button - cy.get('button[data-testid=modal-confirm-button]').click(); - - // * Verify the run is added to lhs - cy.findByTestId('Runs').findByTestId('run1234567').should('exist'); - }); - - describe('archiving', () => { - const playbookTitle = 'Playbook (' + Date.now() + ')'; - let testPlaybook; - - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: playbookTitle, - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - it('shows intended UI and disallows further updates', () => { - // # Programmatically archive it - cy.apiArchivePlaybook(testPlaybook.id); - - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}`); - - // * Verify we're on the right playbook - cy.get('[class^="Title-"]').contains(playbookTitle); - - // * Verify we can see the archived badge - cy.get('.icon-archive-outline').should('be.visible'); - - // * Verify the run button is disabled - cy.findByTestId('run-playbook').should('be.disabled'); - - // # Attempt to edit the playbook - cy.apiGetPlaybook(testPlaybook.id).then((playbook) => { - // # New title - playbook.title = 'new Title!!!'; - - // * Verify update fails - cy.apiUpdatePlaybook(playbook, 400); - }); - }); - }); - - describe('start a run', () => { - let testPlaybook; - - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - after(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - beforeEach(() => { - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - it('start a run, create a new channel', () => { - // # Visit playbook page - cy.visit(`/playbooks/playbooks/${testPlaybook.id}`); - - // # Click Run Playbook - cy.findByTestId('run-playbook').click(); - - // * Verify that channel configuration matches playbook config - cy.findByTestId('link-existing-channel-radio').should('not.be.checked'); - cy.get('#link-existing-channel-selector').should('not.exist'); - cy.findByTestId('create-channel-radio').should('be.checked'); - cy.findByTestId('create-private-channel-radio').should('be.checked'); - - // # Enter the run name - const runName = 'run' + Date.now(); - cy.findByTestId('run-name-input').clear().type(runName); - - // # Click start run button - cy.get('button[data-testid=modal-confirm-button]').click(); - - // * Verify the run is added to lhs - cy.findByTestId('Runs').findByTestId(runName).should('exist'); - - // * Verify the channel is created - cy.findByTestId('runinfo-channel-link').contains(runName); - }); - - it('start a run in existing channel', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Select the action section. - cy.get('#actions #link-existing-channel').within(() => { - // # Enable link to existing channel - cy.get('input[type=radio]').click(); - - // * Verify that the toggle is checked and input is enabled - cy.get('input[type=radio]').should('be.checked'); - cy.get('input[type=text]').should('not.be.disabled'); - - // # Select channel - cy.findByText('Select a channel').click().type('Town{enter}'); - }); - - // # Click Run Playbook - cy.findByTestId('run-playbook').click({force: true}); - - // # Enter the run name - const runName = 'run' + Date.now(); - cy.findByTestId('run-name-input').clear().type(runName); - - // * Verify that channel configuration matches playbook config - cy.findByTestId('link-existing-channel-radio').should('be.checked'); - cy.get('#link-existing-channel-selector').get('input[type=text]').should('be.enabled'); - cy.findByTestId('create-channel-radio').should('not.be.checked'); - cy.findByTestId('create-private-channel-radio').should('not.exist'); - - // # Click start run button - cy.get('button[data-testid=modal-confirm-button]').click(); - - // * Verify the run is added to lhs - cy.findByTestId('Runs').findByTestId(runName).should('exist'); - - // * Verify the channel is created - cy.findByTestId('runinfo-channel-link').contains('Town'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/pagination_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/pagination_spec.js deleted file mode 100644 index 4a2d06232e..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/pagination_spec.js +++ /dev/null @@ -1,68 +0,0 @@ -// 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('playbooks > list pagination', {testIsolation: true}, () => { - let testTeam; - let testUser; - const ExtraPlaybooks = 20; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as user-1 - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - }); - - // # Populate the DB with more elements to force the pagination - for (let i = 0; i < ExtraPlaybooks; i++) { - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Elements before', - memberIDs: [], - }); - } - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - }); - - it('reset page to 0 after search for an name with one value', () => { - // # Open the product - cy.visit('/playbooks'); - - // # Switch to Playbooks - cy.findByTestId('playbooksLHSButton').click(); - - // # Click on next page - cy.findByText('Next').click(); - - // # Click on Search input - cy.get('input[placeholder="Search for a playbook"]').type('Playbook'); - - // * Verify the page display the first page - cy.findByText('1–1 of 1 total'); - - // * Verify that previous isn't exist - cy.findByText('Previous').should('not.exist'); - }); -}); - diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/start_run_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/start_run_spec.js deleted file mode 100644 index 4cf5ac7e49..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/start_run_spec.js +++ /dev/null @@ -1,578 +0,0 @@ -// 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 - -const RUN_NAME_MAX_LENGTH = 64; - -describe('playbooks > start a run', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - }); - }); - - beforeEach(() => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - makePublic: true, - memberIDs: [testUser.id], - createPublicPlaybookRun: true, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - - // This data is intentionally changed here instead of via api - const fillPBE = ({name, summary, channelMode, channelNameToLink, defaultOwnerEnabled}) => { - // # fill channel name temaplte - if (name) { - cy.get('#create-new-channel input[type="text"]').clear().type('Channel template'); - } - - // # fill summary template - if (summary) { - cy.contains('run summary template').dblclick(); - cy.focused().type('run summary template'); - cy.findByRole('button', {name: /save/i}).click(); - } - if (channelMode === 'create_new_channel') { - cy.get('#create-new-channel input[type="radio"]').eq(0).click(); - } else if (channelMode === 'link_to_existing_channel') { - cy.get('#link-existing-channel input[type="radio"]').click(); - } - - if (channelNameToLink) { - cy.get('#link-existing-channel').within(() => { - cy.findByText('Select a channel').click().type(`${channelNameToLink}{enter}`); - }); - } - - if (defaultOwnerEnabled) { - cy.get('#assign-owner').within(() => { - // * Verify that the toggle is unchecked - cy.get('label input').should('not.be.checked'); - - // # Click on the toggle to enable the setting - cy.get('label input').click({force: true}); - - // * Verify that the toggle is checked - cy.get('label input').should('be.checked'); - }); - } - }; - describe('from playbook list', () => { - it('defaults', () => { - // # Visit playbook list - cy.visit('/playbooks/playbooks'); - - // # Click "Run" button on the first playbook - cy.findAllByTestId('playbook-item').first().within(() => { - cy.findByText('Run').click(); - }); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is filled - cy.findByTestId('run-name-input').clear().type('Run name'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'backstage_playbook_list', - playbookId: testPlaybook.id, - channelMode: 'create_new_channel', - hasPlaybookChanged: false, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: false, - hasChannelIdChanged: false, - hasPublicChanged: false, - }, - }, - ]); - - // * Verify we are on RDP - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=run_modal'); - - // * Verify run name - cy.get('h1').contains('Run name'); - }); - }); - - describe('from playbook editor', () => { - describe('pbe configured as create new channel', () => { - it('defaults', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // Fill default values - fillPBE({name: 'Channel template', summary: 'run summary template', channelMode: 'create_new_channel', defaultOwnerEnabled: true}); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is filled - cy.findByTestId('run-name-input').should('have.value', 'Channel template'); - - // * Assert template summary is filled - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'backstage_playbook_editor', - playbookId: testPlaybook.id, - channelMode: 'create_new_channel', - hasPlaybookChanged: false, - hasNameChanged: false, - hasSummaryChanged: false, - hasChannelModeChanged: false, - hasChannelIdChanged: false, - hasPublicChanged: false, - }, - }, - ]); - - // * Verify we are on RDP - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=run_modal'); - - // * Verify run name - cy.get('h1').contains('Channel template'); - - // * Verify run summary - cy.findByTestId('run-summary-section').contains('run summary template'); - }); - - it('change title/summary', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Fill default values - fillPBE({name: 'Channel template', summary: 'run summary template', channelMode: 'create_new_channel'}); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert template are filled (and force wait to them) - cy.findByTestId('run-name-input').should('have.value', 'Channel template'); - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Fill run summary - cy.findByTestId('run-summary-input').clear().type('Test Run Summary'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'backstage_playbook_editor', - playbookId: testPlaybook.id, - channelMode: 'create_new_channel', - hasPlaybookChanged: false, - hasNameChanged: true, - hasSummaryChanged: true, - hasChannelModeChanged: false, - hasChannelIdChanged: false, - hasPublicChanged: false, - }, - }, - ]); - - // * Verify we are on RDP - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=run_modal'); - - // * Verify run name - cy.get('h1').contains('Test Run Name'); - - // * Verify run summary - cy.findByTestId('run-summary-section').contains('Test Run Summary'); - }); - - it('change to link to existing channel does not default to current channel', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Fill default values - fillPBE({name: 'Channel template', summary: 'run summary template', channelMode: 'create_new_channel', defaultOwnerEnabled: true}); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // # Change to link to existing channel - cy.findByTestId('link-existing-channel-radio').click(); - - // * Assert selected channel is unchanged - cy.findByText('Select a channel').should('be.visible'); - }); - }); - - it('change to link to existing channel', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Fill default values - fillPBE({name: 'Channel template', summary: 'run summary template', channelMode: 'create_new_channel', defaultOwnerEnabled: true}); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // # Change to link to existing channel - cy.findByTestId('link-existing-channel-radio').click(); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // * Assert cta is disabled - cy.findByTestId('modal-confirm-button').should('be.disabled'); - - // # Fill Town square as the channel to be linked - cy.findByText('Select a channel').click().type('Town{enter}'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'backstage_playbook_editor', - playbookId: testPlaybook.id, - channelMode: 'link_existing_channel', - hasPlaybookChanged: false, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: true, - hasChannelIdChanged: true, - hasPublicChanged: false, - }, - }, - ]); - - // * Verify we are on RDP - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=run_modal'); - - // * Verify run name - cy.get('h1').contains('Test Run Name'); - - // # Click channel link - cy.findByTestId('runinfo-channel-link').click(); - - // * Verify we are on town square - cy.url().should('include', `/${testTeam.name}/channels/town-square`); - }); - }); - - describe('pbe configured as linked to existing channel', () => { - it('defaults', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Fill default values - fillPBE({summary: 'run summary template', channelMode: 'link_to_existing_channel', channelNameToLink: 'Town'}); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is empty - cy.findByTestId('run-name-input').should('be.empty'); - - // * Assert template summary is filled - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // * Assert button is still disabled - cy.findByTestId('modal-confirm-button').should('be.disabled'); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'backstage_playbook_editor', - playbookId: testPlaybook.id, - channelMode: 'link_existing_channel', - hasPlaybookChanged: false, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: false, - hasChannelIdChanged: false, - hasPublicChanged: false, - }, - }, - ]); - - // * Verify we are on RDP - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=run_modal'); - - // * Verify run name - cy.get('h1').contains('Test Run Name'); - - // * Verify run summary - cy.findByTestId('run-summary-section').contains('run summary template'); - - // # Click channel link - cy.findByTestId('runinfo-channel-link').click(); - - // * Verify we are on town square - cy.url().should('include', `/${testTeam.name}/channels/town-square`); - }); - - it('fill initially empty channel', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Fill default values - fillPBE({summary: 'run summary template', channelMode: 'link_to_existing_channel'}); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is empty - cy.findByTestId('run-name-input').should('be.empty'); - - // * Assert template summary is filled - cy.findByTestId('run-summary-input').should('have.value', 'run summary template'); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // * Assert button is still disabled - cy.findByTestId('modal-confirm-button').should('be.disabled'); - - // # Fill Town square as the channel to be linked - cy.findByText('Select a channel').click().type('Town{enter}'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'backstage_playbook_editor', - playbookId: testPlaybook.id, - channelMode: 'link_existing_channel', - hasPlaybookChanged: false, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: false, - hasChannelIdChanged: true, - hasPublicChanged: false, - }, - }, - ]); - - // * Verify we are on RDP - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=run_modal'); - - // * Verify run name - cy.get('h1').contains('Test Run Name'); - - // * Verify run summary - cy.findByTestId('run-summary-section').contains('run summary template'); - - // # Click channel link - cy.findByTestId('runinfo-channel-link').click(); - - // * Verify we are on town square - cy.url().should('include', `/${testTeam.name}/channels/town-square`); - }); - - it('change to create new channel', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // Fill default values - fillPBE({name: 'Channel template', summary: 'run summary template', channelMode: 'link_to_existing_channel', channelNameToLink: 'Town'}); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Change to create new channel - cy.findByTestId('create-channel-radio').click(); - - // # Fill run name - cy.findByTestId('run-name-input').clear().type('Test Run Name'); - - // # Click start button - cy.findByTestId('modal-confirm-button').click(); - }); - - // * Assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_create', - type: 'track', - properties: { - place: 'backstage_playbook_editor', - playbookId: testPlaybook.id, - channelMode: 'create_new_channel', - hasPlaybookChanged: false, - hasNameChanged: true, - hasSummaryChanged: false, - hasChannelModeChanged: true, - hasChannelIdChanged: false, - hasPublicChanged: false, - }, - }, - ]); - - // * Verify we are on RDP - cy.url().should('include', '/playbooks/runs/'); - cy.url().should('include', '?from=run_modal'); - - // * Verify run name - cy.get('h1').contains('Test Run Name'); - - // # Click channel link - cy.findByTestId('runinfo-channel-link').click(); - - // * Verify we are on channel Test Run Name - cy.url().should('include', `/${testTeam.name}/channels/test-run-name`); - }); - }); - }); - - describe('start run modal > invalid user input', () => { - it('submit button is disabled when run name is empty', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is empty - cy.findByTestId('run-name-input').should('have.value', ''); - - // * Assert start button is disabled - cy.findByTestId('modal-confirm-button').should('have.attr', 'disabled'); - }); - }); - - it('error is shown when maximum length of run name is exceeded', () => { - // # Visit the selected playbook - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Click start a run button - cy.findByTestId('run-playbook').click(); - - cy.get('#root-portal.modal-open').within(() => { - // # Wait the modal to render - cy.wait(500); - - // * Assert template name is empty - cy.findByTestId('run-name-input').should('have.value', ''); - - // # Type run name that exceeds maximum length - cy.findByTestId('run-name-input').type('a'.repeat(RUN_NAME_MAX_LENGTH + 1)); - - // * Assert error shown and contains maximum length in message - cy.findByTestId('run-name-error').should('contain', RUN_NAME_MAX_LENGTH); - - // * Assert start button is disabled - cy.findByTestId('modal-confirm-button').should('have.attr', 'disabled'); - - // # Delete last character via backspace - cy.findByTestId('run-name-input').type('{backspace}'); - - // * Assert that error is not shown anymore - cy.findByTestId('run-name-error').should('not.exist'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/playbooks/status_update_spec.js b/e2e-tests/cypress/tests/integration/playbooks/playbooks/status_update_spec.js deleted file mode 100644 index 9c6b44d530..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/playbooks/status_update_spec.js +++ /dev/null @@ -1,196 +0,0 @@ -// 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('playbooks > edit status update', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPlaybook; - let testChannel; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public channel - cy.apiCreateChannel( - testTeam.id, - 'public-channel', - 'Public Channel', - 'O', - ).then(({channel}) => { - testChannel = channel; - }); - }); - }); - - beforeEach(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a playbook - cy.apiCreateTestPlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - userId: testUser.id, - }).then((playbook) => { - testPlaybook = playbook; - }); - - // # Set a bigger viewport so the action don't scroll out of view - cy.viewport('macbook-16'); - }); - - describe('status update enable/disable', () => { - it('can enable/disable status update', () => { - // # Visit the selected playbook outline tab - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // * Verify status update message - cy.findAllByTestId('status-update-section').should('exist').within(() => { - cy.contains('A status update is expected every'); - cy.contains('1 day'); - cy.contains('no channels'); - cy.contains('no outgoing webhooks'); - }); - - // # Disable status update - cy.findAllByTestId('status-update-toggle').eq(0).click(); - - // * Verify status update message - cy.findAllByTestId('status-update-section').should('exist').within(() => { - cy.contains('Status updates are not expected.'); - cy.contains('A status update is expected every').should('not.exist'); - }); - }); - }); - - describe('edit channels and webhooks', () => { - it('can enable/disable status update', () => { - // # Visit the selected playbook outline tab - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Select a channel - cy.findAllByTestId('status-update-broadcast-channels').click(); - cy.get('#playbook-automation-broadcast').contains('Town Square').click({force: true}); - cy.findAllByTestId('status-update-broadcast-channels').click(); - - // # Refresh the page - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // # Add webhooks - cy.findAllByTestId('status-update-webhooks').click(); - cy.findAllByTestId('webhooks-input').type('http://hook1.com{enter}http://hook2.com{enter}http://hook3.com{enter}'); - cy.findAllByTestId('checklist-item-save-button').click(); - - // # Refresh the page - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // * Verify status update message - cy.findAllByTestId('status-update-section').should('exist').within(() => { - cy.contains('1 channel'); - cy.contains('3 outgoing webhooks'); - }); - - // # Disable status update - cy.findAllByTestId('status-update-toggle').eq(0).click(); - - // * Verify status update message - cy.get('#status-updates').within(() => { - cy.findByText('Status updates are not expected.').should('exist'); - }); - - // # Re-enable status update - cy.findAllByTestId('status-update-toggle').eq(0).click(); - - // # Refresh the page - cy.visit(`/playbooks/playbooks/${testPlaybook.id}/outline`); - - // * Verify that channels and webhooks persist - cy.get('#status-updates').within(() => { - cy.contains('1 channel').should('exist'); - cy.contains('3 outgoing webhooks').should('exist'); - }); - }); - }); - - describe('status enabled, broadcasts disabled, but channels and webhooks specified', () => { - it('can enable/disable status update', () => { - const broadcastChannelIds = [testChannel.id]; - const webhookOnStatusUpdateURLs = ['https://one.com', 'https://two.com']; - - // # Create a playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook #### (' + Date.now() + ')', - userId: testUser.id, - broadcastChannelIds, - webhookOnStatusUpdateURLs, - }).then((playbook) => { - // # Visit the selected playbook outline tab - cy.visit(`/playbooks/playbooks/${playbook.id}/outline`); - - // * Verify status update message. Status update should be enabled, but message should say `updates will be posted to no channels and no outgoing webhooks` - cy.findAllByTestId('status-update-section').should('exist').within(() => { - cy.contains('A status update is expected every'); - cy.contains('no channels'); - cy.contains('no outgoing webhooks'); - }); - - // * Verify selected channels style - cy.findAllByTestId('status-update-broadcast-channels').click(); - cy.get('.playbook-react-select__option').contains('Public Channel'). - invoke('css', 'text-decoration'). - should('equal', 'line-through solid rgba(63, 67, 80, 0.48)'); - - // # Close select options - cy.findAllByTestId('status-update-broadcast-channels').click(); - - // # Open webhooks text area - cy.findAllByTestId('status-update-webhooks').click(); - - // * Verify webhooks text style - cy.findAllByTestId('webhooks-input'). - invoke('css', 'text-decoration'). - should('equal', 'line-through solid rgba(63, 67, 80, 0.48)'); - - // # Edit webhooks - cy.findAllByTestId('webhooks-input').type('http://hook1.com{enter}http://hook2.com{enter}http://hook3.com{enter}'); - cy.findAllByTestId('checklist-item-save-button').click(); - - // # Select a channel - cy.findAllByTestId('status-update-broadcast-channels').click(); - cy.get('#playbook-automation-broadcast').contains('Town Square').click({force: true}); - cy.findAllByTestId('status-update-broadcast-channels').click(); - - // * Verify status update message. - cy.findAllByTestId('status-update-section').should('exist').within(() => { - cy.contains('A status update is expected every'); - cy.contains('2 channels'); - cy.contains('4 outgoing webhooks'); - }); - - // # Refresh the page - cy.visit(`/playbooks/playbooks/${playbook.id}/outline`); - - // * Verify status update message. - cy.findAllByTestId('status-update-section').should('exist').within(() => { - cy.contains('A status update is expected every'); - cy.contains('2 channels'); - cy.contains('4 outgoing webhooks'); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/list_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/list_spec.js deleted file mode 100644 index 1f3d518aa6..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/list_spec.js +++ /dev/null @@ -1,262 +0,0 @@ -// 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('runs > list', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testAnotherUser; - let testPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - // # Create another user - cy.apiCreateUser().then(({user: anotherUser}) => { - testTeam = team; - testUser = user; - testAnotherUser = anotherUser; - cy.apiAddUserToTeam(testTeam.id, anotherUser.id); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - makePublic: true, - memberIDs: [testUser.id, testAnotherUser.id], - createPublicPlaybookRun: true, - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show all - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - }); - - it('has "Runs" and team name in heading', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Open the product - cy.visit('/playbooks'); - - // # Switch to playbook runs - cy.findByTestId('playbookRunsLHSButton').click(); - - // * Assert contents of heading. - cy.findByTestId('titlePlaybookRun').should('exist').contains('Runs'); - }); - - it('loads playbook run details page when clicking on a playbook run', () => { - // # Run the playbook - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }); - - // # Open the product - cy.visit('/playbooks'); - - // # Switch to runs - cy.findByTestId('playbookRunsLHSButton').click(); - - // # Find the playbook run and click to open details view - cy.get('#playbookRunList').within(() => { - cy.findByText(playbookRunName).click(); - }); - - // * Verify that the header contains the playbook run name - cy.findByTestId('run-header-section').get('h1').contains(playbookRunName); - }); - - describe('filters my runs only', () => { - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Run a playbook with testUser as a participant - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'testUsers Run', - ownerUserId: testUser.id, - }); - - // # Login as testAnotherUser - cy.apiLogin(testAnotherUser); - - // # Run a playbook with testAnotherUser as a participant - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'testAnotherUsers Run', - - // ownerUserId: testUser.id, - ownerUserId: testAnotherUser.id, - }); - }); - - it('for testUser', () => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Open the product - cy.visit('/playbooks/runs'); - - cy.get('#playbookRunList').within(() => { - // # Make sure both runs are visible by default - cy.findByText('testUsers Run').should('be.visible'); - cy.findByText('testAnotherUsers Run').should('be.visible'); - - // # Filter to only my runs - cy.findByTestId('my-runs-only').click(); - - // # Verify runs by testAnotherUser are not visible - cy.findByText('testAnotherUsers Run').should('not.exist'); - - // # Verify runs by testUser remain visible - cy.findByText('testUsers Run').should('be.visible'); - }); - }); - - it('for testAnotherUser', () => { - // # Login as testAnotherUser - cy.apiLogin(testAnotherUser); - - // # Open the product - cy.visit('/playbooks'); - cy.get('#playbookRunList').within(() => { - // Make sure both runs are visible by default - cy.findByText('testUsers Run').should('be.visible'); - cy.findByText('testAnotherUsers Run').should('be.visible'); - - // # Filter to only my runs - cy.findByTestId('my-runs-only').click(); - - // # Verify runs by testUser are not visible - cy.findByText('testUsers Run').should('not.exist'); - - // # Verify runs by testAnotherUser remain visible - cy.findByText('testAnotherUsers Run').should('be.visible'); - }); - }); - }); - - describe('filters Finished runs correctly', () => { - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Run a playbook with testUser as a participant - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'testUsers Run to be finished', - ownerUserId: testUser.id, - }).then((playbook) => { - cy.apiFinishRun(playbook.id); - }); - }); - - it('shows finished runs', () => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Open the product - cy.visit('/playbooks'); - - cy.get('#playbookRunList').within(() => { - // # Make sure runs are visible by default, and finished is not - cy.findByText('testUsers Run').should('be.visible'); - cy.findByText('testAnotherUsers Run').should('be.visible'); - cy.findByText('testUsers Run to be finished').should('not.exist'); - - // # Filter to finished runs as well - cy.findByTestId('finished-runs').click(); - - // # Verify runs remain visible - cy.findByText('testUsers Run').should('be.visible'); - cy.findByText('testAnotherUsers Run').should('be.visible'); - - // # Verify finished run is visible - cy.findByText('testUsers Run to be finished').should('be.visible'); - }); - }); - }); - - describe('LHS run list', () => { - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - const runs = [ - { - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'run-sort-check 0', - ownerUserId: testUser.id, - }, - { - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'run-sort-check 1', - ownerUserId: testUser.id, - }, - { - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'run-sort-check 2', - ownerUserId: testUser.id, - }, - { - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: 'run-sort-check 3', - ownerUserId: testUser.id, - }, - ]; - - Promise.all(runs.map((run) => { - return new Promise((resolve) => cy.apiRunPlaybook(run).then(resolve)); - })).then(() => { - cy.visit('/playbooks'); - }); - }); - - it('lhs run list sorted by name', () => { - cy.findByTestId('lhs-navigation').within(() => { - cy.get('li:contains(run-sort-check)').each((item, index) => { - // * Verify run list order - cy.wrap(item).should('have.text', 'run-sort-check ' + index); - }); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/permissions_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/permissions_spec.js deleted file mode 100644 index 734d739eb0..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/permissions_spec.js +++ /dev/null @@ -1,498 +0,0 @@ -// 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 {getRandomId} from '../../../utils'; - -describe('runs > permissions', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testOtherTeam; - - let playbookMember; - let runParticipant; - let runFollower; - let teamMember; - let nonTeamMember; - let sysadminInTeam; - let sysadminNotInTeam; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Create a dedicated playbook member - cy.apiCreateUser().then(({user: createdUser}) => { - playbookMember = createdUser; - - cy.apiAddUserToTeam(testTeam.id, createdUser.id); - }); - - // # Create a dedicated run participant - cy.apiCreateUser().then(({user: createdUser}) => { - runParticipant = createdUser; - - cy.apiAddUserToTeam(testTeam.id, createdUser.id); - }); - - // # Create a dedicated run follower - cy.apiCreateUser().then(({user: createdUser}) => { - runFollower = createdUser; - - cy.apiAddUserToTeam(testTeam.id, createdUser.id); - }); - - // # Create a dedicated member in team 1 - cy.apiCreateUser().then(({user: createdUser}) => { - teamMember = createdUser; - - cy.apiAddUserToTeam(testTeam.id, createdUser.id); - }); - - // # Create a dedicated sysadmin in team 1 - cy.apiCreateCustomAdmin().then(({sysadmin: createdUser}) => { - sysadminInTeam = createdUser; - - cy.apiAddUserToTeam(testTeam.id, createdUser.id); - }); - - // # Create a public playbook and corresponding run with a public channel in - // team 1. This is to ensure the list isn't empty for users who can't access the - // run under test. - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook (Team 1)', - memberIDs: [], - createPublicPlaybookRun: true, - }).then((createdPlaybook) => { - // Create a run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: createdPlaybook.id, - playbookRunName: getRandomId(), - ownerUserId: testUser.id, - }); - }); - - // # Create another team - cy.apiCreateTeam('second-team', 'Second Team').then(({team: createdTeam}) => { - testOtherTeam = createdTeam; - - // # Create a dedicated member not in team 1 - cy.apiCreateUser().then(({user: createdUser}) => { - nonTeamMember = createdUser; - - cy.apiAddUserToTeam(testOtherTeam.id, createdUser.id); - }); - - // # Create a dedicated sysadmin not in team 1 - cy.apiCreateCustomAdmin().then(({sysadmin: createdUser}) => { - sysadminNotInTeam = createdUser; - - cy.apiAddUserToTeam(testOtherTeam.id, createdUser.id); - }); - - // # Create a public playbook and corresponding run with a public channel in - // team 2. This is to ensure the list isn't empty for users who can't access the - // run under test. - cy.apiCreatePlaybook({ - teamId: testOtherTeam.id, - title: 'Playbook (Team 2)', - memberIDs: [], - createPublicPlaybookRun: true, - }).then((createdPlaybook) => { - // Create a run - cy.apiRunPlaybook({ - teamId: testOtherTeam.id, - playbookId: createdPlaybook.id, - playbookRunName: getRandomId(), - ownerUserId: nonTeamMember.id, - }); - }); - }); - }); - }); - - describe('run with private channel from a public playbook', () => { - let playbook; - let run; - - before(() => { - // # Login as the user setup during initialization. - cy.apiLogin(testUser); - - // # Create a public playbook, configured to create private channels for runs - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - createPublicPlaybookRun: false, - }).then((createdPlaybook) => { - playbook = createdPlaybook; - - // Create a run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: getRandomId(), - ownerUserId: runParticipant.id, - }).then((createdRun) => { - run = createdRun; - - // Have the dedicated participant join the run - cy.apiAddUsersToRun(run.id, [runParticipant.id]); - - // # Have the dedicated follower follow this playbook run - cy.apiLogin(runFollower); - cy.apiFollowPlaybookRun(run.id); - }); - }); - }); - - describe('should be visible', () => { - it('to playbook members', () => { - assertRunIsVisible(run, playbookMember); - }); - - it('to run participants', () => { - assertRunIsVisible(run, runParticipant); - }); - - it('to run followers', () => { - assertRunIsVisible(run, runFollower); - }); - - it('to team members', () => { - assertRunIsVisible(run, teamMember); - }); - - it('to admins in the team', () => { - assertRunIsVisible(run, sysadminInTeam); - }); - - // XXX: The following asserts that while sysadmins don't see runs from other teams in - // the list, they still have access to view the overview directly. Once we support - // sudo-admins, we should change this behaviour to be consistent with normal users. - it('to admins not in the team (overview only)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunOverviewIsVisible(run); - }); - }); - - describe('should not be visible', () => { - it('to non-team members', () => { - assertRunIsNotVisible(run, nonTeamMember); - }); - - it('to admins not in the team (list only)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunIsNotVisibleInList(run); - }); - }); - }); - - describe('run with public channel from a public playbook', () => { - let playbook; - let run; - - before(() => { - // # Login as the user setup during initialization. - cy.apiLogin(testUser); - - // # Create a public playbook, configured to create public channels for runs - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - }).then((createdPlaybook) => { - playbook = createdPlaybook; - - // Create a run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: getRandomId(), - ownerUserId: runParticipant.id, - }).then((createdRun) => { - run = createdRun; - - // Have the dedicated participant join the run - cy.apiAddUsersToRun(run.id, [runParticipant.id]); - - // # Have the dedicated follower follow this playbook run - cy.apiLogin(runFollower); - cy.apiFollowPlaybookRun(run.id); - }); - }); - }); - - describe('should be visible', () => { - it('to playbook members', () => { - assertRunIsVisible(run, playbookMember); - }); - - it('to run participants', () => { - assertRunIsVisible(run, runParticipant); - }); - - it('to run followers', () => { - assertRunIsVisible(run, runFollower); - }); - - it('to team members', () => { - assertRunIsVisible(run, teamMember); - }); - - it('to admins in the team', () => { - assertRunIsVisible(run, sysadminInTeam); - }); - - // XXX: The following asserts that while sysadmins don't see runs from other teams in - // the list, they still have access to view the overview directly. Once we support - // sudo-admins, we should change this behaviour to be consistent with normal users. - it('to admins not in the team (overview only)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunOverviewIsVisible(run); - }); - }); - - describe('should not be visible', () => { - it('to non-team members', () => { - assertRunIsNotVisible(run, nonTeamMember); - }); - - it('to admins not in the team (list only)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunIsNotVisibleInList(run); - }); - }); - }); - - describe('run with private channel from a private playbook', () => { - let playbook; - let run; - - before(() => { - // # Login as the user setup during initialization. - cy.apiLogin(testUser); - - // # Create private playbook, configured to create private channels for runs - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - makePublic: false, - memberIDs: [testUser.id, playbookMember.id], - createPublicPlaybookRun: false, - }).then((createdPlaybook) => { - playbook = createdPlaybook; - - // Login as the playbook member authorized to start a run - cy.apiLogin(playbookMember); - - // Create a run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: getRandomId(), - ownerUserId: runParticipant.id, - }).then((createdRun) => { - run = createdRun; - - // Have the dedicated participant join the run - cy.apiAddUsersToRun(run.id, [runParticipant.id]); - }); - }); - }); - - describe('should be visible', () => { - it('to playbook members', () => { - assertRunIsVisible(run, playbookMember); - }); - - it('to run participants', () => { - assertRunIsVisible(run, runParticipant); - }); - - // Followers cannot follow a run with a private channel from a private playbook - it('to run followers', () => { - assertRunIsNotVisible(run, runFollower); - }); - - it('to admins in the team', () => { - assertRunIsVisible(run, sysadminInTeam); - }); - - // XXX: The following asserts that while sysadmins don't see runs from other teams in - // the list, they still have access to view the run directly. Once we support - // sudo-admins, we should change this behaviour to be consistent with normal users. - it('to admins not in the team (run directly)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunOverviewIsVisible(run); - }); - }); - - describe('should not be visible', () => { - it('to team members', () => { - assertRunIsNotVisible(run, teamMember); - }); - - it('to non-team members', () => { - assertRunIsNotVisible(run, nonTeamMember); - }); - - it('to admins not in the team (list only)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunIsNotVisibleInList(run); - }); - }); - }); - - describe('run with public channel from a private playbook', () => { - let playbook; - let run; - - before(() => { - // # Login as the user setup during initialization. - cy.apiLogin(testUser); - - // # Create private playbook, configured to create private channels for runs - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook', - memberIDs: [testUser.id, playbookMember.id], - makePublic: false, - createPublicPlaybookRun: true, - }).then((createdPlaybook) => { - playbook = createdPlaybook; - - // Login as the playbook member authorized to start a run - cy.apiLogin(playbookMember); - - // Create a run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: getRandomId(), - ownerUserId: runParticipant.id, - }).then((createdRun) => { - run = createdRun; - - // Have the dedicated participant join the run - cy.apiAddUsersToRun(run.id, [runParticipant.id]); - }); - }); - }); - - describe('should be visible', () => { - it('to playbook members', () => { - assertRunIsVisible(run, playbookMember); - }); - - it('to run participants', () => { - assertRunIsVisible(run, runParticipant); - }); - - // Followers cannot follow a run with a private channel from a private playbook - it('to run followers', () => { - assertRunIsNotVisible(run, runFollower); - }); - - it('to admins in the team', () => { - assertRunIsVisible(run, sysadminInTeam); - }); - - // XXX: The following asserts that while sysadmins don't see runs from other teams in - // the list, they still have access to view the run directly. Once we support - // sudo-admins, we should change this behaviour to be consistent with normal users. - it('to admins not in the team (run directly)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunOverviewIsVisible(run); - }); - }); - - describe('should not be visible', () => { - it('to team members', () => { - assertRunIsNotVisible(run, teamMember); - }); - - it('to non-team members', () => { - assertRunIsNotVisible(run, nonTeamMember); - }); - - it('to admins not in the team (list only)', () => { - cy.apiLogin(sysadminNotInTeam); - - assertRunIsNotVisibleInList(run); - }); - }); - }); -}); - -const assertRunIsVisible = (run, user) => { - // # Login as the user in question - cy.apiLogin(user); - - // # Open Runs - cy.visit('/playbooks/runs'); - - // # Find the playbook run and click to open details view - cy.get('#playbookRunList').within(() => { - cy.findByText(run.name).click(); - }); - - // * Verify that the details loaded - cy.findByTestId('run-header-section').get('h1').contains(run.name); -}; - -const assertRunOverviewIsVisible = (run) => { - // # Opening the playbook run directly - cy.visit(`/playbooks/runs/${run.id}`); - - // * Verify that the details loaded - cy.findByTestId('run-header-section').get('h1').contains(run.name); -}; - -const assertRunIsNotVisible = (run, user) => { - // # Login as the user in question - cy.apiLogin(user); - - assertRunIsNotVisibleInList(run, user); - assertRunOverviewIsNotVisible(run, user); -}; - -const assertRunIsNotVisibleInList = (run) => { - // # Open Runs - cy.visit('/playbooks/runs'); - - // * Verify the playbook run is not visible - cy.get('#playbookRunList').within(() => { - cy.findByText(run.name).should('not.exist'); - }); -}; - -const assertRunOverviewIsNotVisible = (run) => { - // # Opening the playbook run directly - cy.visit(`/playbooks/runs/${run.id}`); - - // * Verify the not found error screen - cy.get('.error__container').within(() => { - cy.findByText('Run not found').should('be.visible'); - cy.findByText('The run you\'re requesting is private or does not exist.').should('be.visible'); - }); -}; diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_general_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_general_spec.js deleted file mode 100644 index c5f60b0077..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_general_spec.js +++ /dev/null @@ -1,83 +0,0 @@ -// 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('runs > run details page', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testPublicPlaybook; - let testPlaybookRun; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testPlaybookRun = playbookRun; - }); - }); - - it('redirects to not found error if the playbook run is unknown', () => { - // # Visit the URL of a non-existing playbook run - cy.visit('/playbooks/runs/an_unknown_id'); - - // * Verify that the user has been redirected to the playbook runs not found error page - cy.url().should('include', '/playbooks/error?type=playbook_runs'); - }); - - it('telemetry is triggered', () => { - // # Intercept all calls to telemetry - cy.interceptTelemetry(); - - // # Visit the URL of a non-existing playbook run - cy.visit(`/playbooks/runs/${testPlaybookRun.id}`); - - // * assert telemetry pageview - cy.expectTelemetryToContain([ - { - name: 'run_details', - type: 'page', - properties: { - from: '', - role: 'participant', - playbookrun_id: testPlaybookRun.id, - playbook_id: testPublicPlaybook.id, - }, - }, - ]); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_checklist_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_checklist_spec.js deleted file mode 100644 index 7e7e6f6218..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_checklist_spec.js +++ /dev/null @@ -1,150 +0,0 @@ -// 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 - -// Note that this test checks the basic behavior in Run details page as participant / viewer -// It relies on the Channel RHS Checklist test to cover the full behavior of the checklists - -describe('runs > run details page > checklist', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testRun; - const taskIndex = 0; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - checklists: [ - { - title: 'Stage 1', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - ], - }, - { - title: 'Stage 2', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - ], - }, - ], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - const getChecklist = () => cy.findByTestId('run-checklist-section'); - const getChecklistTasks = () => getChecklist().findAllByTestId('checkbox-item-container'); - - const commonTests = () => { - it('is visible', () => { - // * Verify the tasks section is present - getChecklist().should('be.visible'); - }); - - it('has title', () => { - // * Verify the task section has a title - getChecklist().find('h3').contains('Tasks'); - }); - - it('can see the tasks', () => { - // * Verify tasks are shown - getChecklistTasks().should('have.length', 4); - }); - }; - - describe('as participant', () => { - commonTests(); - - it('click marks task as done', () => { - // # Click first task - getChecklistTasks().eq(taskIndex).find('.checkbox').check({force: true}); - - // * Assert checkbox is checked - getChecklistTasks().eq(taskIndex).find('.checkbox').should('be.checked'); - }); - - it('has hover menu', () => { - // # Hover over the checklist item - getChecklistTasks().eq(taskIndex).trigger('mouseover'); - - // # Click dot menu - getChecklistTasks().eq(taskIndex).findByTitle('More').click({force: true}); - - // * Assert actions are available - cy.findByRole('button', {name: 'Skip task'}).should('be.visible'); - cy.findByRole('button', {name: 'Duplicate task'}).should('be.visible'); - }); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - commonTests(); - - it('click does not work', () => { - // # Click first task - getChecklistTasks().eq(taskIndex).find('.checkbox').should('have.attr', 'readonly'); - }); - - it('has not hover menu', () => { - // # Hover over the checklist item - getChecklistTasks().eq(taskIndex).trigger('mouseover'); - - // * Check that the hover menu is not rendered - getChecklistTasks().eq(taskIndex).findByTitle('More').should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_finish_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_finish_spec.js deleted file mode 100644 index 28aa61efcf..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_finish_spec.js +++ /dev/null @@ -1,130 +0,0 @@ -// 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('runs > run details page > finish', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPlaybookRun; - let testPublicPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name(' + Date.now() + ')', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testPlaybookRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - it('is hidden as viewer', () => { - cy.apiLogin(testViewerUser).then(() => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${testPlaybookRun.id}`); - }); - - // * Assert that finish section does not exist - cy.findByTestId('run-finish-section').should('not.exist'); - }); - - it('is visible', () => { - // * Verify the finish section is present - cy.findByTestId('run-finish-section').should('be.visible'); - }); - - it('has a placeholder visible', () => { - // * Verify the placeholder is present - cy.findByTestId('run-finish-section').contains('Time to wrap up?'); - }); - - describe('finish run', () => { - it('can be confirmed', () => { - // # Click finish run button - cy.findByTestId('run-finish-section').find('button').click(); - - // * Check that status badge is in-progress - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - - // * Check that finish run modal is open and has the right title - cy.get('#confirmModal').should('be.visible'); - cy.get('#confirmModal').find('h1').contains('Confirm finish run'); - - // # Click on confirm - cy.get('#confirmModal').get('#confirmModalButton').click(); - - // * Assert finish section is not visible anymore - cy.findByTestId('run-finish-section').should('not.exist'); - - // * Assert status badge is finished - cy.findByTestId('run-header-section').findByTestId('badge').contains('Finished'); - - // * Verify run has been removed from LHS - cy.findByTestId('lhs-navigation').findByText(testPlaybookRun.name).should('not.exist'); - }); - - it('can be canceled', () => { - // # Click on finish run - cy.findByTestId('run-finish-section').find('button').click(); - - // * Check that status badge is in-progress - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - - // * Check that finish run modal is open - cy.get('#confirmModal').should('be.visible'); - cy.get('#confirmModal').find('h1').contains('Confirm finish run'); - - // # Click on cancel - cy.get('#confirmModal').get('#cancelModalButton').click(); - - // * Check that status badge is still in-progress - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - - // * Check that section is still visible - cy.findByTestId('run-finish-section').should('be.visible'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_header_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_header_spec.js deleted file mode 100644 index aa4814cc48..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_header_spec.js +++ /dev/null @@ -1,869 +0,0 @@ -// 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 {stubClipboard} from '../../../utils'; - -describe('runs > run details page > header', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testPublicPlaybookAndChannel; - let playbookRun; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // # Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - createPublicPlaybookRun: true, - memberIDs: [], - }).then((playbook) => { - testPublicPlaybookAndChannel = playbook; - }); - }); - }); - - const openRunActionsModal = () => { - // # Click on the run actions modal button - cy.findByRole('button', {name: /Run Actions/i}).click({force: true}); - - // * Verify that the modal is shown - cy.findByRole('dialog', {name: /Run Actions/i}).should('exist'); - }; - - const saveRunActionsModal = () => { - // # Click on the Save button without changing anything - cy.findByRole('button', {name: /Save/i}).click(); - - // * Verify that the modal is no longer there - cy.findByRole('dialog', {name: /Run Actions/i}).should('not.exist'); - }; - - const getHeader = () => { - return cy.findByTestId('run-header-section'); - }; - - const getHeaderIcon = (selector) => { - return getHeader().find(selector); - }; - - const getDropdownItemByText = (text) => { - cy.findByTestId('run-header-section').find('h1').click(); - return cy.findByTestId('dropdownmenu').findByText(text); - }; - - const commonHeaderTests = () => { - it('shows the title', () => { - // * Assert title is shown in h1 inside header - cy.findByTestId('run-header-section').find('h1').contains(playbookRun.name); - }); - - it('shows the in-progress status badge', () => { - // * Assert in progress status badge - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - }); - - it('has a copy-link icon', () => { - // # Mouseover on the icon - getHeaderIcon('.icon-link-variant').trigger('mouseover'); - - // * Assert tooltip is shown - cy.get('#copy-run-link-tooltip').should('contain', 'Copy link to run'); - - stubClipboard().as('clipboard'); - getHeaderIcon('.icon-link-variant').click().then(() => { - // * Verify that tooltip text changed - cy.get('#copy-run-link-tooltip').should('contain', 'Copied!'); - - // * Verify clipboard content - cy.get('@clipboard').its('contents').should('contain', `/playbooks/runs/${playbookRun.id}`); - }); - }); - }; - - const commonContextDropdownTests = () => { - it('shows on click', () => { - // # Click title - cy.findByTestId('run-header-section').find('h1').click(); - - // * Assert context menu is opened - cy.findByTestId('dropdownmenu').should('be.visible'); - }); - - it('can copy link', () => { - stubClipboard().as('clipboard'); - - getDropdownItemByText('Copy link').click().then(() => { - // * Verify clipboard content - cy.get('@clipboard').its('contents').should('contain', `/playbooks/runs/${playbookRun.id}`); - }); - }); - }; - - describe('as participant', () => { - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name(' + Date.now() + ')', - ownerUserId: testUser.id, - }).then((run) => { - playbookRun = run; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - - cy.assertRunDetailsPageRenderComplete(testUser.username); - }); - }); - - describe('title, icons and buttons', () => { - commonHeaderTests(); - - it('has not participate button', () => { - // * Assert button is not showed - getHeader().findByText('Participate').should('not.exist'); - }); - - describe('run actions', () => { - describe('modal behaviour', () => { - it('shows and hides as expected', () => { - // * Verify that the run actions modal is shown when clicking on the button - openRunActionsModal(); - - // # Click on the Cancel button - cy.findByRole('button', {name: /Cancel/i}).click(); - - // * Verify that the modal is no longer there - cy.findByRole('dialog', {name: /Run Actions/i}).should('not.exist'); - - // # Open the run actions modal - openRunActionsModal(); - - // Intercept all telemetry calls - cy.interceptTelemetry(); - - // * Verify that saving the modal hides it - saveRunActionsModal(); - - // * assert telemetry call - cy.expectTelemetryToContain([ - { - name: 'playbookrun_update_actions', - type: 'track', - properties: { - playbookrun_id: playbookRun.id, - playbook_id: playbookRun.playbook_id, - }, - }, - ]); - }); - - it('can not save an invalid form', () => { - // * Verify that the run actions modal is shown when clicking on the button - openRunActionsModal(); - - cy.findByRole('dialog', {name: /Run Actions/i}).within(() => { - // # click on webhooks toggle - cy.findByText('Send outgoing webhook').click(); - - // # Type an invalid webhook URL - cy.getStyledComponent('TextArea').clear().type('invalidurl'); - - // # Click outside textarea - cy.findByText('Run Actions').click(); - - // * Assert the error message is displayed - cy.findByText('Invalid webhook URLs').should('be.visible'); - - // # Click save - cy.findByTestId('modal-confirm-button').click(); - - // * Assert that modal is still open - cy.findByText('Run Actions').should('be.visible'); - }); - }); - - it('honours the settings from the playbook', () => { - cy.apiCreateChannel( - testTeam.id, - 'action-channel', - 'Action Channel', - 'O', - ).then(({channel}) => { - // # Create a different playbook with both settings enabled and populated with data, - // # and then start a run from it - const broadcastChannelIds = [channel.id]; - const webhookOnStatusUpdateURLs = ['https://one.com', 'https://two.com']; - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook' + Date.now(), - broadcastEnabled: true, - broadcastChannelIds, - webhookOnStatusUpdateEnabled: true, - webhookOnStatusUpdateURLs, - }).then((playbook) => { - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: 'Run with actions preconfigured', - ownerUserId: testUser.id, - }); - }); - - // # Navigate to the run page - cy.visit(`/${testTeam.name}/channels/run-with-actions-preconfigured`); - cy.findByRole('button', {name: /Run details/i}).click({force: true}); - - // # Open the run actions modal - openRunActionsModal(); - - // * Verify that the broadcast-to-channels toggle is checked - cy.findByText('Broadcast update to selected channels').parent().within(() => { - cy.get('input').should('be.checked'); - }); - - // * Verify that the channel is in the selector - cy.findByText(channel.display_name); - - // * Verify that the send-webhooks toggle is checked - cy.findByText('Send outgoing webhook').parent().within(() => { - cy.get('input').should('be.checked'); - }); - }); - }); - }); - }); - - describe('trigger: when a status update is posted', () => { - describe('action: Broadcast update to selected channels', () => { - it('shows channel information on first load', () => { - // # Open the run actions modal - openRunActionsModal(); - - // # Enable broadcast to channels - cy.findByText('Broadcast update to selected channels').click(); - - // # Select a couple of channels - cy.findByText('Select channels').click().type('town square{enter}off-topic{enter}'); - - // # Save the changes - saveRunActionsModal(); - - // # Reload the page, so that the store is not pre-populated when visiting Channels - cy.visit(`/playbooks/runs/${playbookRun.id}/overview`); - - // # Open the run actions modal - openRunActionsModal(); - - // * Check that the channels previously added are shown with their full name, - // * verifying that the store has been populated by the modal component. - cy.findByText('Town Square').should('exist'); - cy.findByText('Off-Topic').should('exist'); - }); - - it('broadcasts to two channels configured when it is enabled', () => { - // # Open the run actions modal - openRunActionsModal(); - - // # Enable broadcast to channels - cy.findByText('Broadcast update to selected channels').click(); - - // # Select a couple of channels - cy.findByText('Select channels').click().type('town square{enter}off-topic{enter}', {delay: 100}); - - // # Save the changes - saveRunActionsModal(); - - // # Post a status update, with a reminder in 1 second. - const message = 'Status update - ' + Date.now(); - cy.apiUpdateStatus({ - playbookRunId: playbookRun.id, - message, - }); - - // # Navigate to the town square channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // * Verify that the last post contains the status update - cy.getLastPost().then((post) => { - cy.get(post).contains(message); - }); - - // # Navigate to the off-topic channel - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // * Verify that the last post contains the status update - cy.getLastPost().then((post) => { - cy.get(post).contains(message); - }); - }); - - it('does not broadcast if it is disabled, even if there are channels configured', () => { - // # Open the run actions modal - openRunActionsModal(); - - // # Enable broadcast to channels - cy.findByText('Broadcast update to selected channels').click(); - - // # Select a couple of channels - cy.findByText('Select channels').click().type('town square{enter}off-topic{enter}', {delay: 100}); - - // # Disable broadcast to channels - cy.findByText('Broadcast update to selected channels').click(); - - // # Save the changes - saveRunActionsModal(); - - // # Post a status update, with a reminder in 1 second. - const message = 'Status update - ' + Date.now(); - cy.apiUpdateStatus({ - playbookRunId: playbookRun.id, - message, - }); - - // # Navigate to the town square channel - cy.visit(`/${testTeam.name}/channels/town-square`); - - // * Verify that the last post does not contain the status update - cy.getLastPost().then((post) => { - cy.get(post).contains(message).should('not.exist'); - }); - - // # Navigate to the off-topic channel - cy.visit(`/${testTeam.name}/channels/off-topic`); - - // * Verify that the last post does not contain the status update - cy.getLastPost().then((post) => { - cy.get(post).contains(message).should('not.exist'); - }); - }); - }); - }); - }); - - describe('context menu', () => { - commonContextDropdownTests(); - - it('can rename run', () => { - // # Click on rename run - getDropdownItemByText('Rename run').click(); - - cy.findByTestId('run-header-section').within(() => { - // # Type a new name - cy.findByTestId('rendered-editable-text').clear().type('The new fancy name'); - - // # Save - cy.findByTestId('checklist-item-save-button').click(); - - // * Assert name is updated - cy.get('h1').contains('The new fancy name'); - }); - - cy.reload(); - - cy.findByTestId('run-header-section').within(() => { - // * Assert name is persisted - cy.get('h1').contains('The new fancy name'); - }); - }); - - describe('finish run', () => { - it('can be confirmed', () => { - // * Check that status badge is in-progress - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - - // # Click on finish run - getDropdownItemByText('Finish run').click(); - - // # Check that finish run modal is open - cy.get('#confirmModal').should('be.visible'); - cy.get('#confirmModal').find('h1').contains('Confirm finish run'); - - // # Click on confirm - cy.get('#confirmModal').get('#confirmModalButton').click(); - - // * Assert option is not anymore in context dropdown - getDropdownItemByText('Finish run').should('not.exist'); - - // * Assert status badge is finished - cy.findByTestId('run-header-section').findByTestId('badge').contains('Finished'); - }); - - it('can be canceled', () => { - // * Check that status badge is in-progress - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - - // # Click on finish run - getDropdownItemByText('Finish run').click(); - - // * Check that finish run modal is open - cy.get('#confirmModal').should('be.visible'); - cy.get('#confirmModal').find('h1').contains('Confirm finish run'); - - // # Click on cancel - cy.get('#confirmModal').get('#cancelModalButton').click(); - - // * Assert option is not anymore in context dropdown - getDropdownItemByText('Finish run').should('be.visible'); - - // * Assert status badge is still in progress - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - }); - }); - - describe('run actions', () => { - it('modal can be opened', () => { - // # Click on finish run - getDropdownItemByText('Run actions').click(); - - // * Assert modal pop up - cy.findByRole('dialog', {name: /Run Actions/i}).should('exist'); - - // # Click on cancel - cy.findByRole('dialog', {name: /Run Actions/i}).findByTestId('modal-cancel-button').click(); - - // * Assert modal disappeared - cy.findByRole('dialog', {name: /Run Actions/i}).should('not.exist'); - }); - }); - - describe('leave run', () => { - it('can leave run', () => { - // # Intercept all calls to telemetry - cy.interceptTelemetry(); - - // # Add viewer user to the channel - cy.apiAddUsersToRun(playbookRun.id, [testViewerUser.id]); - cy.findAllByTestId('timeline-item', {exact: false}).should('have.length', 3); - - // # Change the owner to testViewerUser - cy.apiChangePlaybookRunOwner(playbookRun.id, testViewerUser.id); - cy.findByTestId('assignee-profile-selector').should('contain', testViewerUser.username); - - // # Click on leave run - getDropdownItemByText('Leave and unfollow run').click(); - - // # confirm modal - cy.get('#confirmModal').get('#confirmModalButton').click(); - - // NOTE: this check fails because the front doesn't receive updated run object. Will deal in separate PR. - // * Assert that the Participate button is shown - getHeader().findByText('Participate').should('be.visible'); - - // * Verify run has been removed from LHS - cy.findByTestId('lhs-navigation').findByText(playbookRun.name).should('not.exist'); - - // # assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_leave', - type: 'track', - properties: { - from: 'run_details', - playbookrun_id: playbookRun.id, - }, - }, - ]); - }); - }); - }); - }); - - describe('as viewer', () => { - let playbookRunChannelName; - let playbookRunName; - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - const now = Date.now(); - playbookRunName = 'Playbook Run (' + now + ')'; - playbookRunChannelName = 'playbook-run-' + now; - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((run) => { - playbookRun = run; - - cy.apiLogin(testViewerUser).then(() => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - - cy.assertRunDetailsPageRenderComplete(testUser.username); - }); - }); - - describe('title, icons and buttons', () => { - commonHeaderTests(); - - describe('Favorite', () => { - it('add and remove from LHS', () => { - // # Click fav icon - getHeader().getStyledComponent('StarButton').click(); - - // * Assert run appears in LHS - cy.findByTestId('lhs-navigation').findByText(playbookRunName).should('exist'); - - // # Click fav icon again (unfav) - getHeader().getStyledComponent('StarButton').click(); - - // * Assert run disappeared from LHS - cy.findByTestId('lhs-navigation').findByText(playbookRunName).should('not.exist'); - }); - }); - - describe('Participate', () => { - it('shows button', () => { - // * Assert that the button is shown - getHeader().findByText('Participate').should('be.visible'); - }); - - describe('Join action enabled', () => { - it('click button to show modal and cancel', () => { - // * Assert that component is rendered - getHeader().findByText('Participate').should('be.visible'); - - // # Click Participate button - getHeader().findByText('Participate').click(); - - // * Verify modal message is correct - cy.findByText('You’ll also be added to the channel linked to this run.').should('exist'); - - // # cancel modal - cy.findByTestId('modal-cancel-button').click(); - - // * Assert modal is not shown - cy.get('#become-participant-modal').should('not.exist'); - - // # Login as testUser - cy.apiLogin(testUser).then(() => { - // # Visit the channel run - cy.visit(`${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Assert user has not been added to the channel - cy.getLastPost().should('not.contain', 'Someone'); - cy.getLastPost().should('not.contain', testViewerUser.username); - }); - }); - - it('click button to show modal and confirm when private channel', () => { - // # Intercept all calls to telemetry - cy.interceptTelemetry(); - - // * Assert component is rendered - getHeader().findByText('Participate').should('be.visible'); - - // # Click start-participating button - getHeader().findByText('Participate').click(); - - // * Verify modal message is correct - cy.findByText('You’ll also be added to the channel linked to this run.').should('exist'); - - // # confirm modal - cy.findByTestId('modal-confirm-button').click(); - - // * Assert that modal is not shown - cy.get('#become-participant-modal').should('not.exist'); - - // * Verify run has been added to LHS - verifyRunHasBeenAddedToLHS(playbookRunName); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Verify channel loads - cy.get('#channelHeaderTitle').should('be.visible').should('contain', playbookRunName); - - // * assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'playbookrun_participate', - type: 'track', - properties: { - from: 'run_details', - playbookrun_id: playbookRun.id, - }, - }, - ]); - }); - - it('click button and confirm to when public channel', () => { - // # Login as testUser - cy.apiLogin(testUser); - - const now = Date.now(); - playbookRunName = 'Playbook Run (' + now + ')'; - playbookRunChannelName = 'playbook-run-' + now; - - // # Create a run with public chanel - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybookAndChannel.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((run) => { - cy.apiLogin(testViewerUser); - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${run.id}`); - cy.assertRunDetailsPageRenderComplete(testUser.username); - - // * Assert that component is rendered - getHeader().findByText('Participate').should('be.visible'); - - // # Click start-participating button - getHeader().findByText('Participate').click(); - - // * Verify modal message is correct - cy.findByText('You’ll also be added to the channel linked to this run.').should('exist'); - - // # confirm modal - cy.findByTestId('modal-confirm-button').click(); - - // * Assert that modal is not shown - cy.get('#become-participant-modal').should('not.exist'); - - // * Verify run has been added to LHS - cy.findByTestId('lhs-navigation').findByText(playbookRunName).should('exist'); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Verify channel loads - cy.get('#channelHeaderTitle').should('be.visible').should('contain', playbookRunName); - }); - }); - }); - - describe('Join action disabled', () => { - beforeEach(() => { - cy.apiLogin(testUser); - - // # Disable join action - cy.apiUpdateRun(playbookRun.id, {createChannelMemberOnNewParticipant: false}); - - cy.apiLogin(testViewerUser).then(() => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - - cy.assertRunDetailsPageRenderComplete(testUser.username); - }); - - it('join the run with private channel, request to join the channel', () => { - // # Click start-participating button - getHeader().findByText('Participate').click(); - - // * Verify modal message is correct - cy.findByText('Request access to the channel linked to this run').should('exist'); - - // # Select checkbox - cy.findByTestId('also-add-to-channel').click({force: true}); - - // # confirm modal - cy.findByTestId('modal-confirm-button').click(); - - // * Assert that modal is not shown - cy.get('#become-participant-modal').should('not.exist'); - - // * Verify run has been added to LHS - verifyRunHasBeenAddedToLHS(playbookRunName); - - // # Login as testUser to check if join request was posted in the channel - cy.apiLogin(testUser); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the request was sent to the channel - cy.getLastPostId().then((id) => { - cy.get(`#postMessageText_${id}`).within(() => { - cy.contains(`@${testViewerUser.username} is a run participant and wants join this channel. Any member of the channel can invite them.`); - }); - }); - }); - - it('join the run with private channel, no request to join the channel', () => { - // # Click start-participating button - getHeader().findByText('Participate').click(); - - // * Verify modal message is correct - cy.findByText('Request access to the channel linked to this run').should('exist'); - - // # confirm modal - cy.findByTestId('modal-confirm-button').click(); - - // * Assert that modal is not shown - cy.get('#become-participant-modal').should('not.exist'); - - // * Verify run has been added to LHS - verifyRunHasBeenAddedToLHS(playbookRunName); - - // # Login as testUser to check if join request was posted in the channel - cy.apiLogin(testUser); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Verify that the request was sent to the channel - cy.getLastPostId().then((id) => { - cy.get(`#postMessageText_${id}`).within(() => { - cy.contains(`@${testViewerUser.username} is a run participant and wants join this channel. Any member of the channel can invite them.`).should('not.exist'); - }); - }); - }); - - it('join run with public channel, join the channel', () => { - // # Login as testUser - cy.apiLogin(testUser); - - const now = Date.now(); - playbookRunName = 'Playbook Run (' + now + ')'; - playbookRunChannelName = 'playbook-run-' + now; - - // Create a run with public chanel - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybookAndChannel.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((run) => { - cy.apiLogin(testViewerUser); - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${run.id}`); - cy.assertRunDetailsPageRenderComplete(testUser.username); - - // * Assert that component is rendered - getHeader().findByText('Participate').should('be.visible'); - - // # Click start-participating button - getHeader().findByText('Participate').click(); - - // * Verify modal message is correct - cy.findByText('You’ll also be added to the channel linked to this run.').should('exist'); - - // # confirm modal - cy.findByTestId('modal-confirm-button').click(); - - // * Assert that modal is not shown - cy.get('#become-participant-modal').should('not.exist'); - - // * Verify run has been added to LHS - cy.findByTestId('lhs-navigation').findByText(playbookRunName).should('exist'); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // # Verify channel loads - cy.get('#channelHeaderTitle').should('be.visible').should('contain', playbookRunName); - }); - }); - }); - }); - - describe('run actions', () => { - describe('modal behaviour', () => { - it('modal can be opened read-only', () => { - // # Click on run actions - getDropdownItemByText('Run actions').click(); - - // * Assert modal pop up - cy.findByRole('dialog', {name: /Run Actions/i}).should('exist'); - - // * Assert there are no buttons - cy.findByRole('dialog', {name: /Run Actions/i}).findByTestId('modal-cancel-button').should('not.exist'); - cy.findByRole('button', {name: /Save/i}).should('not.exist'); - - // # Close modal - cy.findByRole('dialog', {name: /Run Actions/i}).find('.close').click(); - }); - }); - }); - }); - - describe('context menu', () => { - commonContextDropdownTests(); - - it('can not rename run', () => { - // # There's no rename option - getDropdownItemByText('Rename run').should('not.exist'); - }); - - it('can not finish run', () => { - // * There's no finish run item - getDropdownItemByText('Finish run').should('not.exist'); - }); - - describe('run actions', () => { - it('modal can be opened read-only', () => { - // # Click on finish run - getDropdownItemByText('Run actions').click(); - - // * Assert modal pop up - cy.findByRole('dialog', {name: /Run Actions/i}).should('exist'); - - // * Assert there are no buttons - cy.findByRole('dialog', {name: /Run Actions/i}).findByTestId('modal-cancel-button').should('not.exist'); - cy.findByRole('button', {name: /Save/i}).should('not.exist'); - - // # Close modal - cy.findByRole('dialog', {name: /Run Actions/i}).find('.close').click(); - }); - }); - }); - }); -}); - -const verifyRunHasBeenAddedToLHS = (playbookRunName) => { - // * Verify run has been added to LHS - cy.findByTestId('lhs-navigation'). - should('be.visible'). - findByText(playbookRunName). - should('be.visible'); -}; diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_restore_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_restore_spec.js deleted file mode 100644 index b3a7da35f3..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_restore_spec.js +++ /dev/null @@ -1,107 +0,0 @@ -// 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('runs > run details page > restart run', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testRun; - - // const taskIndex = 0; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - checklists: [ - { - title: 'Stage 1', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - ], - }, - { - title: 'Stage 2', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - ], - }, - ], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - describe('restart run', () => { - it('can be confirmed', () => { - cy.intercept('PUT', `/plugins/playbooks/api/v0/runs/${testRun.id}/finish`).as('routeFinish'); - cy.intercept('PUT', `/plugins/playbooks/api/v0/runs/${testRun.id}/restore`).as('routeRestore'); - - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - - // # Click finish run button - cy.findByTestId('run-finish-section').find('button').click(); - cy.get('#confirmModal').get('#confirmModalButton').click(); - - cy.wait('@routeFinish'); - cy.findByTestId('run-header-section').findByTestId('badge').contains('Finished'); - - cy.findByTestId('runDropdown').click(); - cy.get('.restartRun').find('span').contains('Restart run'); - - cy.get('.restartRun').click(); - cy.get('#confirmModal').get('#confirmModalButton').click(); - cy.wait('@routeRestore'); - cy.findByTestId('run-header-section').findByTestId('badge').contains('In Progress'); - cy.findByTestId('lhs-navigation').findByText(testRun.name).should('exist'); - }, - ); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_retrospective_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_retrospective_spec.js deleted file mode 100644 index 25841c28c5..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_retrospective_spec.js +++ /dev/null @@ -1,500 +0,0 @@ -// 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 - -const editAndPublishRetro = () => { - getRetro().within(() => { - // # Start editing - cy.findByTestId('retro-report-text').click(); - - // * Verify the provided template text is pre-filled - cy.focused().should('include.text', 'This is a retrospective template.'); - - // # Change the retro text - cy.focused().clear().type('Edited retrospective.'); - - // # Save it by clicking outside the text area - cy.findByText('Report').click(); - - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - }); - - cy.get('#confirm-modal-light').within(() => { - // * Verify we're showing the publish retro confirmation modal - cy.findByText('Are you sure you want to publish?'); - - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - }); - - // * Verify that retro got published - getRetro().get('.icon-check-all').should('be.visible'); -}; - -const getMetricInput = (index) => getRetro().getStyledComponent('InputContainer').eq(index); - -const verifyMetricInput = (index, title, target, description, placeholder) => { - getMetricInput(index).within(() => { - cy.getStyledComponent('Title').contains(title); - - if (target) { - cy.getStyledComponent('TargetTitle').contains(target); - } else { - cy.getStyledComponent('TargetTitle').should('not.exist'); - } - - if (description) { - cy.getStyledComponent('HelpText').contains(description); - } - if (placeholder) { - cy.get('input').should('have.attr', 'placeholder', placeholder); - } - }); -}; - -const getRetro = () => cy.findByTestId('run-retrospective-section'); - -describe('runs > run details page', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testPublicPlaybookWithMetrics; - let testRun; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - retrospectiveTemplate: 'This is a retrospective template.', - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - metrics: [ - { - title: 'title1', - description: 'description1', - type: 'metric_duration', - target: 720000, - }, - { - title: 'title2', - description: 'description2', - type: 'metric_currency', - target: 40, - }, - { - title: 'title3', - description: 'description3', - type: 'metric_integer', - target: 30, - }, - ], - }).then((playbook) => { - testPublicPlaybookWithMetrics = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('retrospective', () => { - const commonTests = () => { - it('is visible', () => { - // * Verify the retrospective section is present - getRetro().should('be.visible'); - }); - - it('has title', () => { - // * Verify the retrospective section has a title - getRetro().find('h3').contains('Retrospective'); - }); - - it('has template text', () => { - // * Verify the retrospective text is rendered - getRetro().findByTestId('retro-report-text').contains('This is a retrospective template.'); - }); - - it('has no metrics', () => { - // * Verify there are no metric for this playbook - getRetro().getStyledComponent('InputContainer').should('not.exist'); - }); - }; - - describe('as participant', () => { - beforeEach(() => { - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - commonTests(); - - it('publishing posts to run channel', () => { - editAndPublishRetro(); - - // # Switch to the run channel - cy.findByTestId('runinfo-channel-link').click(); - - // * Verify the modified retro text is posted - cy.getStyledComponent('CustomPostContent').should('exist').contains('Edited retrospective.'); - }); - - it('can be published once', () => { - editAndPublishRetro(); - - // * Verify the button is disabled - getRetro().findByText('Publish').should('not.be.enabled'); - }); - }); - - describe('as viewer', () => { - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create test playbook run - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - }); - }); - - beforeEach(() => { - // Login as the test viewer - cy.apiLogin(testViewerUser); - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - - commonTests(); - - it('text is not clickable', () => { - getRetro().findByTestId('retro-report-text').click(); - getRetro().find('textarea').should('not.exist'); - }); - - it('there is no publish button', () => { - getRetro().findByText('Publish').should('not.exist'); - }); - }); - }); - - describe('metrics', () => { - const commonTests = () => { - it('inputs info(title, target, description) and order', () => { - // * Verify the created metrics - verifyMetricInput(0, 'title1', '12 minutes', 'description1', 'Add value (in dd:hh:mm)'); - verifyMetricInput(1, 'title2', '40', 'description2', 'Add value'); - verifyMetricInput(2, 'title3', '30', 'description3', 'Add value'); - }); - }; - - describe('as participant', () => { - beforeEach(() => { - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybookWithMetrics.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - }); - }); - - beforeEach(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - - commonTests(); - - it('inputs, null and zero values', () => { - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - createPublicPlaybookRun: true, - metrics: [ - { - title: 'title1', - description: 'description1', - type: 'metric_duration', - target: null, - }, - { - title: 'title2', - description: 'description2', - type: 'metric_currency', - target: 0, - }, - { - title: 'title3', - description: 'description3', - type: 'metric_integer', - target: 30, - }, - ], - }).then((playbook) => { - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - // # Navigate directly to the retro tab - cy.visit(`/playbooks/runs/${playbookRun.id}`); - - // * Verify changes are reflected - verifyMetricInput(0, 'title1', null, 'description1', 'Add value (in dd:hh:mm)'); - verifyMetricInput(1, 'title2', '0', 'description2', 'Add value'); - verifyMetricInput(2, 'title3', '30', 'description3', 'Add value'); - }); - }); - }); - - it('auto save', () => { - getRetro().within(() => { - // # Enter metric values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('12:11:10'). - tab().type('56'). - tab().type('123'); - - // # Click outside - cy.findByText('Retrospective').click({force: true}); - cy.wait(2000); - - // * Validate if values persist - cy.get('input[type=text]').eq(0).should('have.value', '12:11:10'); - cy.get('input[type=text]').eq(1).should('have.value', '56'); - cy.get('input[type=text]').eq(2).should('have.value', '123'); - - // # Enter new values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).clear().type('12:00:10'). - tab().clear().type('20'). - tab().clear().type('21'); - }); - - // # Wait 2 sec to auto save - cy.wait(2000); - - // # Reload page - cy.visit(`/playbooks/runs/${testRun.id}`); - - getRetro().within(() => { - // * Validate if values are saved - cy.get('input[type=text]').eq(0).should('have.value', '12:00:10'); - cy.get('input[type=text]').eq(1).should('have.value', '20'); - cy.get('input[type=text]').eq(2).should('have.value', '21'); - }); - }); - - it('save empty and zero values', () => { - getRetro().within(() => { - // # Enter metric values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).clear().type('00:00:00'). - tab().type('7'). - tab().type('0'); - - // # Click outside - cy.findByText('Retrospective').click({force: true}); - - // * Validate if values persist - cy.get('input[type=text]').eq(0).should('have.value', '00:00:00'); - cy.get('input[type=text]').eq(1).should('have.value', '7'); - cy.get('input[type=text]').eq(2).should('have.value', '0'); - - // # Clear first two metrics values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).clear(). - tab().clear(); - - // # Click outside - cy.findByText('Retrospective').click({force: true}); - - // * Validate if values persist - cy.get('input[type=text]').eq(0).should('have.value', ''); - cy.get('input[type=text]').eq(1).should('have.value', ''); - cy.get('input[type=text]').eq(2).should('have.value', '0'); - }); - }); - - it('only valid values are saved. check error messages', () => { - getRetro().within(() => { - // # Enter invalid metric values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('5'). - tab().type('56d'). - tab().type('125'); - - // * Validate error messages - cy.getStyledComponent('ErrorText').eq(0).contains('Please enter a duration in the format: dd:hh:mm (e.g., 12:00:00).'); - cy.getStyledComponent('ErrorText').eq(1).contains('Please enter a number.'); - - // # Click outside - cy.findByText('Retrospective').click({force: true}); - }); - - // # Reload page and navigate to the retro tab - cy.visit(`/playbooks/runs/${testRun.id}`); - - getRetro().within(() => { - // * Validate that values are not saved - cy.get('input[type=text]').eq(0).should('have.value', ''); - cy.get('input[type=text]').eq(1).should('have.value', ''); - cy.get('input[type=text]').eq(2).should('have.value', '125'); - - // # Enter new metric values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('s'). - tab().type('d'). - tab().type('k'); - }); - }); - - it('publish retro', () => { - getRetro().within(() => { - // # Enter metric invalid values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('20:00:12d'). - tab().type('56'). - tab().type('125v'); - - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - }); - - // * Verify we're not showing the publish retro confirmation modal - cy.get('#confirm-modal-light').should('not.exist'); - - getRetro().within(() => { - //# Enter empty metric values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).clear(). - tab().clear(). - tab().clear().type(24); - - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - - // * Validate error messages - cy.getStyledComponent('ErrorText').eq(0).contains('Please fill in the metric value.'); - cy.getStyledComponent('ErrorText').eq(1).contains('Please fill in the metric value.'); - cy.getStyledComponent('ErrorText').should('have.length', 2); - }); - - // * Verify we're not showing the publish retro confirmation modal - cy.get('#confirm-modal-light').should('not.exist'); - - getRetro().within(() => { - //# Enter valid metric values - cy.get('input[type=text]').eq(0).click(); - cy.get('input[type=text]').eq(0).type('09:87:12'). - tab().type(123); - - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - }); - - cy.get('#confirm-modal-light').within(() => { - // * Verify we're showing the publish retro confirmation modal - cy.findByText('Are you sure you want to publish?'); - - // # Publish - cy.findByRole('button', {name: 'Publish'}).click(); - }); - - getRetro().within(() => { - // * Verify that retro got published - cy.get('.icon-check-all').should('be.visible'); - - // * Verify that metrics inputs are disabled - cy.get('input[type=text]').each(($el) => { - cy.wrap($el).should('not.be.enabled'); - }); - }); - }); - }); - - describe('as viewer', () => { - before(() => { - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybookWithMetrics.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - }); - }); - - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - commonTests(); - - it('are not editable', () => { - // * Verify that inputs are disabled - getMetricInput(0).find('input').should('be.disabled'); - getMetricInput(1).find('input').should('be.disabled'); - getMetricInput(2).find('input').should('be.disabled'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_statusupdate_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_statusupdate_spec.js deleted file mode 100644 index b384e659a1..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_statusupdate_spec.js +++ /dev/null @@ -1,304 +0,0 @@ -// 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('runs > run details page > status update', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testRun; - let playbookRunChannelName; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - const now = Date.now(); - const playbookRunName = 'Playbook Run (' + now + ')'; - playbookRunChannelName = 'playbook-run-' + now; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName, - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - - cy.assertRunDetailsPageRenderComplete(testUser.username); - }); - }); - - describe('as participant', () => { - it('is visible', () => { - // * Verify the status update section is present - cy.findByTestId('run-statusupdate-section').should('be.visible'); - }); - - it('has no title', () => { - // * Verify the title - cy.findByTestId('run-statusupdate-section').find('h3').should('not.exist'); - }); - - describe('post update', () => { - it('button disappears if we finish the run', () => { - // * Check that post update button is visible - cy.findByTestId('run-statusupdate-section').findByTestId('post-update-button').should('be.visible'); - - // # Click finish button and confirm modal - cy.findByTestId('run-finish-section').find('button').click(); - cy.get('#confirmModal').get('#confirmModalButton').click(); - - // * Check that post update button does not exist anymore - cy.findByTestId('run-statusupdate-section').findByTestId('post-update-button').should('not.exist'); - }); - - it('button triggers post update modal', () => { - // * Check due date - cy.findByTestId('update-due-date-text').contains('Update due'); - cy.findByTestId('update-due-date-time').contains('in 24 hours'); - - // # Click post update - cy.findByTestId('run-statusupdate-section').findByTestId('post-update-button').click(); - - // * Assert modal is opened - cy.getStatusUpdateDialog().should('be.visible'); - - // # Write message - cy.findByTestId('update_run_status_textbox').clear().type('my nice update'); - cy.get('#reminder_timer_datetime').within(() => { - cy.get('input').type('15 minutes', {delay: 200, force: true}).type('{enter}', {force: true}); - }); - - // # Post update - cy.getStatusUpdateDialog().findByTestId('modal-confirm-button').click(); - - // * Check new due date - cy.findByTestId('update-due-date-text').contains('Update due'); - cy.findByTestId('update-due-date-time').contains('in 15 minutes'); - - // # Intercept all calls to telemetry - cy.interceptTelemetry(); - - // # go to channel - cy.visit(`/${testTeam.name}/channels/${playbookRunChannelName}`); - - // * check that post has been added - cy.getLastPost().contains('my nice update'); - - // * assert telemetry pageview - cy.expectTelemetryToContain([ - { - name: 'run_status_update', - type: 'page', - properties: { - channel_type: 'P', - }, - }, - ]); - }); - }); - - describe('request an update', () => { - it('is disabled if the run is finished', () => { - cy.apiFinishRun(testRun.id).then(() => { - // # reload url - cy.visit(`/playbooks/runs/${testRun.id}`); - cy.assertRunDetailsPageRenderComplete(testUser.username); - - // # Click on kebab menu - cy.findByTestId('run-statusupdate-section').getStyledComponent('Kebab').click(); - - // # click on request update option (force because is disabled) - cy.findByText('Request update...').click({force: true}); - - // * assert modal is not opened - cy.get('#confirmModalButton').should('not.exist'); - }); - }); - - it('requests and confirm', () => { - // # Click on kebab menu - cy.findByTestId('run-statusupdate-section').getStyledComponent('Kebab').click(); - - cy.findByTestId('dropdownmenu').within(($dropdown) => { - cy.wrap($dropdown).children().should('have.length', 2); - - // # Click on request update - cy.findByText('Request update...').click(); - }); - - // # Click on modal confirmation - cy.get('#confirmModalButton').click(); - - // # Go to channel - cy.visit(`${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Assert that message has been sent - cy.getLastPost().contains(`${testUser.username} requested a status update for ${testRun.name}.`); - }); - - it('requests and cancel', () => { - // # Click on kebab menu - cy.findByTestId('run-statusupdate-section').getStyledComponent('Kebab').click(); - cy.findByTestId('dropdownmenu').within(($dropdown) => { - cy.wrap($dropdown).children().should('have.length', 2); - - // # Click on request update - cy.findByText('Request update...').click(); - }); - - // # Click on modal confirmation - cy.get('#cancelModalButton').click(); - - // # Go to channel - cy.visit(`${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Assert that message has not been sent - cy.getLastPost().should('not.contain', `${testUser.username} requested a status update for ${testRun.name}.`); - }); - }); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - cy.assertRunDetailsPageRenderComplete(testUser.username); - }); - }); - - it('is visible', () => { - // * Verify the status update section is present - cy.findByTestId('run-statusupdate-section').should('be.visible'); - }); - - it('has a title', () => { - // * Verify the title - cy.findByTestId('run-statusupdate-section').find('h3').contains('Recent status update'); - }); - - it('has placeholder', () => { - // * Verify the placeholder - cy.findByTestId('run-statusupdate-section').find('i').contains('No updates have been posted yet'); - }); - - it('has a due date', () => { - // * Verify the due date - cy.findByTestId('update-due-date-text').contains('Update due'); - cy.findByTestId('update-due-date-time').contains('in 24 hours'); - }); - - it('shows the most recent update', () => { - // # Login as participant - cy.apiLogin(testUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - cy.assertRunDetailsPageRenderComplete(testUser.username); - }); - - // # Click post update - cy.findByTestId('run-statusupdate-section'). - should('be.visible'). - findByTestId('post-update-button').click(); - - // * Assert modal is opened - cy.getStatusUpdateDialog().should('be.visible'); - - // # Write message - cy.findByTestId('update_run_status_textbox').clear().type('my nice update'); - cy.get('#reminder_timer_datetime').within(() => { - cy.get('input').type('15 minutes', {delay: 200, force: true}).type('{enter}', {force: true}); - }); - - // # Post update - cy.getStatusUpdateDialog().findByTestId('modal-confirm-button').click(); - - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - cy.assertRunDetailsPageRenderComplete(testUser.username); - - // * Check new due date - cy.findByTestId('update-due-date-text').contains('Update due'); - cy.findByTestId('update-due-date-time').contains('in 15 minutes'); - - // * Assert the recent updated text - cy.findByTestId('status-update-card').contains('my nice update'); - }); - }); - - it('requests an update and confirm', () => { - // # Click on request update - cy.findByTestId('run-statusupdate-section'). - should('be.visible'). - findByText('Request update...').click(); - - // # Click on modal confirmation - cy.get('#confirmModalButton').click(); - - cy.apiLogin(testUser).then(() => { - // # Go to channel - cy.visit(`${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Assert that message has been sent - cy.getLastPost().contains(`${testViewerUser.username} requested a status update for ${testRun.name}.`); - }); - }); - - it('requests an update and cancel', () => { - // # Click request update - cy.findByTestId('run-statusupdate-section'). - should('be.visible'). - findByText('Request update...').click(); - - // # Click on modal confirmation - cy.get('#cancelModalButton').click(); - - cy.apiLogin(testUser).then(() => { - // # Go to channel - cy.visit(`${testTeam.name}/channels/${playbookRunChannelName}`); - - // * Assert that message has been sent - cy.getLastPost().should('not.contain', `${testUser.username} requested a status update for ${testPublicPlaybook.name}].`); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_summary_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_summary_spec.js deleted file mode 100644 index 7b5ecc4384..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_summary_spec.js +++ /dev/null @@ -1,162 +0,0 @@ -// 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('runs > run details page > summary', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testRun; - let testViewerUser; - let testPublicPlaybook; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - const commonTests = () => { - it('is visible', () => { - // * Verify the summary section is present - cy.findByTestId('run-summary-section').should('be.visible'); - }); - - it('has title', () => { - // * Verify the summary section is present - cy.findByTestId('run-summary-section').find('h3').contains('Summary'); - }); - }; - - describe('as participant', () => { - commonTests(); - - it('has a placeholder', () => { - // * Assert the placeholder content - cy.findByTestId('run-summary-section').findByTestId('rendered-text').contains('Add a run summary'); - }); - - it('can be edited', () => { - // # Mouseover the summary - cy.findByTestId('run-summary-section').trigger('mouseover'); - - cy.findByTestId('run-summary-section').within(() => { - // # Click the edit icon - cy.findByTestId('hover-menu-edit-button').click(); - - // # Write a summary - cy.findByTestId('editabletext-markdown-textbox2').clear().type('This is my new summary'); - - // # Save changes - cy.findByTestId('checklist-item-save-button').click(); - - // * Assert that data has changed - cy.findByTestId('rendered-text').contains('This is my new summary'); - }); - - // * Assert last edition date is visible - cy.findByTestId('run-summary-section').contains('Last edited'); - }); - - it('can be canceled', () => { - // # Mouseover the summary - cy.findByTestId('run-summary-section').trigger('mouseover'); - - cy.findByTestId('run-summary-section').within(() => { - // # Click the edit icon - cy.findByTestId('hover-menu-edit-button').click(); - - // # Write a summary - cy.findByTestId('editabletext-markdown-textbox2').clear().type('This is my new summary'); - - // # Cancel changes - cy.findByText('Cancel').click(); - - // * Assert that data has not changed - cy.findByTestId('rendered-text').contains('Add a run summary'); - }); - - // * Assert last edition date is not visible - cy.findByTestId('run-summary-section').should('not.contain', 'Last edited'); - }); - - it('can not be edited once run is finished', () => { - // # Finish the run - cy.apiFinishRun(testRun.id); - - // # Mouseover the summary - cy.findByTestId('run-summary-section').trigger('mouseover'); - - // * Verify that the edit button is not rendered - cy.findByTestId('run-summary-section').findByTestId('hover-menu-edit-button').should('not.exist'); - }); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - commonTests(); - - it('has a placeholder', () => { - // * Assert the placeholder content - cy.findByTestId('run-summary-section').findByTestId('rendered-text').contains('There\'s no summary'); - }); - - it('can not be edited', () => { - // # Mouseover the summary - cy.findByTestId('run-summary-section').trigger('mouseover'); - - // * Verify that the edit button is not rendered - cy.findByTestId('run-summary-section').findByTestId('hover-menu-edit-button').should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_taskactions_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_taskactions_spec.js deleted file mode 100644 index a289da7792..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_main_taskactions_spec.js +++ /dev/null @@ -1,712 +0,0 @@ -// 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 * as TIMEOUTS from '../../../fixtures/timeouts'; - -describe('runs > task actions', {testIsolation: true}, () => { - let testPlaybook; - let testTeam; - let testUser; - let testUser2; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateUser().then(({user: user2}) => { - testUser2 = user2; - - // # Add this new user to the team - cy.apiAddUserToTeam(team.id, testUser2.id); - }); - - // # Create a playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Playbook (' + Date.now() + ')', - checklists: [{ - title: 'Test Checklist', - items: [ - {title: 'Test Task'}, - ], - }], - memberIDs: [ - testUser.id, - ], - }).then((playbook) => { - testPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # intercepts telemetry - cy.interceptTelemetry(); - - // # Login as testUser - cy.apiLogin(testUser); - }); - - describe('keywords trigger - mark task as done', () => { - let testPlaybookRun; - - const getChecklist = () => cy.findByTestId('run-checklist-section'); - const getChecklistTasks = () => getChecklist().findAllByTestId('checkbox-item-container'); - - beforeEach(() => { - // # Run a playbook - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: `the run name ${Date.now()}`, - ownerUserId: testUser.id, - }).then((playbookRun) => { - testPlaybookRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - it('disallows no keywords', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify no actions are configured - cy.findByText('Task Actions').should('exist'); - - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, []); - assert.deepEqual(trigger.user_ids, []); - assert.isFalse(actions.enabled); - }); - }); - - it('allows a single keyword', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // # Enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - - // # assert telemetry data - cy.expectTelemetryToContain([ - { - name: 'taskactions_updated', - type: 'track', - properties: { - playbookrun_id: testPlaybookRun.id, - }, - }, - ]); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser2.username} checked off checklist item "Test Task"`); - }); - - it('allows multiple keywords', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add multiple keywords - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - cy.get('input').eq(0).type('keyword2{enter}', {force: true}); - }); - - // # Enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1', 'keyword2']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword2 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser2.username} checked off checklist item "Test Task"`); - }); - - it('allows multi-word phrases', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a phrase - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('a phrase with multiple words{enter}', {force: true}); - }); - - // # Enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['a phrase with multiple words']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and a phrase with multiple words happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser2.username} checked off checklist item "Test Task"`); - }); - - it('allows removing previously configured keywords', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add multiple keywords - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - cy.get('input').eq(0).type('keyword2{enter}', {force: true}); - }); - - // # Enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // # Re-open the dialog - cy.findByText('1 action').click(); - - // # Remove one trigger keyword - cy.get('.modal-body').within(() => { - cy.findByText('keyword1').next().click(); - }); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword2']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - - // # Post without activating trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action not activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('not.be.checked'); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword2 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser2.username} checked off checklist item "Test Task"`); - }); - - it('disables when all keywords removed', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add multiple keywords - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - cy.get('input').eq(0).type('keyword2{enter}', {force: true}); - }); - - // # Enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // # Re-open the dialog - cy.findByText('1 action').click(); - - // # Remove all trigger keywords - cy.get('.modal-body').within(() => { - cy.findByText('keyword1').next().click(); - cy.findByText('keyword2').next().click(); - }); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions - cy.findByText('Task Actions'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, []); - assert.deepEqual(trigger.user_ids, []); - assert.isFalse(actions.enabled); - }); - - // # Post without activating trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh keyword1 keyword2 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action not activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('not.be.checked'); - }); - - it('disallows a user without keywords', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a user - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // # Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify no actions are configured - cy.findByText('Task Actions'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, []); - assert.deepEqual(trigger.user_ids, [testUser.id]); - assert.isFalse(actions.enabled); - }); - }); - - it('allows a single user', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // # Add a user - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // # Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions and user - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, [testUser.id]); - assert.isTrue(actions.enabled); - }); - - // # Post without activating trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action not activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('not.be.checked'); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser.id); - cy.postMessageAs({ - sender: testUser, - message: `hello from ${testUser.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser.username} checked off checklist item "Test Task"`); - }); - - it('allows configuring multiple users', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // # Add two users - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - cy.get('input').eq(1). - type('@' + testUser2.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // # Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions and user - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, [testUser.id, testUser2.id]); - assert.isTrue(actions.enabled); - }); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser.id); - cy.postMessageAs({ - sender: testUser, - message: `hello from ${testUser.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser.username} checked off checklist item "Test Task"`); - - // # Reset-uncheck task - cy.apiSetChecklistItemState(testPlaybookRun.id, 0, 0, ''); - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('not.be.checked'); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser2.username} checked off checklist item "Test Task"`); - }); - - it('rejects unknown user', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // # Type an unknown user - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@unknown', {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // # Click away - cy.get('.modal-body').click(); - - // # Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions and user - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser.id); - cy.postMessageAs({ - sender: testUser, - message: `hello from ${testUser.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser.username} checked off checklist item "Test Task"`); - }); - - it('allows removing previously configured users', () => { - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // # Add two users - cy.get('.modal-body').within(() => { - cy.get('input').eq(1). - type('@' + testUser.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - cy.get('input').eq(1). - type('@' + testUser2.username, {force: true}). - wait(TIMEOUTS.ONE_SEC). - type('{enter}', {force: true}); - }); - - // # Attempt to enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // # Re-open the dialog - cy.findByText('1 action').click(); - - // # Remove one user keyword - cy.get('.modal-body').within(() => { - cy.findByText(testUser.username).parent().parent().next().click(); - }); - - // Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybookRun(testPlaybookRun.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, [testUser2.id]); - assert.isTrue(actions.enabled); - }); - - // # Post without activating trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser.id); - cy.postMessageAs({ - sender: testUser, - message: `hello from ${testUser.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action NOT activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('not.be.checked'); - - // # Attempt to activate trigger - cy.apiAddUserToChannel(testPlaybookRun.channel_id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testPlaybookRun.channel_id, - }); - - // * Verify action activated - getChecklistTasks().eq(0).find('input[type="checkbox"]').should('be.checked'); - cy.findAllByTestId('timeline-item task_state_modified').findByText(`${testUser2.username} checked off checklist item "Test Task"`); - }); - }); - - describe('keywords trigger - mark task as done, multiple runs in a channel', () => { - let testChannel; - let testPlaybookRun1; - let testPlaybookRun2; - - const configureTaskAction = (run) => { - // # Visit the playbook run - cy.visit(`/playbooks/runs/${run.id}`); - - // # Open the task actions modal - cy.findByText('Task Actions').click(); - - // # Add a keyword - cy.get('.modal-body').within(() => { - cy.get('input').eq(0).type('keyword1{enter}', {force: true}); - }); - - // # Enable the trigger - cy.findByText('Mark the task as done').click(); - - // # Save the dialog - cy.findByTestId('modal-confirm-button').click(); - - // * Verify configured actions - cy.findByText('1 action'); - cy.apiGetPlaybookRun(run.id).then(({body: playbookRun}) => { - const trigger = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].trigger.payload); - const actions = JSON.parse(playbookRun.checklists[0].items[0].task_actions[0].actions[0].payload); - - assert.deepEqual(trigger.keywords, ['keyword1']); - assert.deepEqual(trigger.user_ids, []); - assert.isTrue(actions.enabled); - }); - }; - - beforeEach(() => { - cy.apiCreateChannel(testTeam.id, 'channel', 'Channel').then(({channel}) => { - testChannel = channel; - - // # Run #1 - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: `the run name ${Date.now()}`, - ownerUserId: testUser.id, - channelId: testChannel.id, - }).then((playbookRun) => { - testPlaybookRun1 = playbookRun; - configureTaskAction(testPlaybookRun1); - }); - - // # Run #2 - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPlaybook.id, - playbookRunName: `the run name ${Date.now()}`, - ownerUserId: testUser.id, - channelId: testChannel.id, - }).then((playbookRun) => { - testPlaybookRun2 = playbookRun; - configureTaskAction(testPlaybookRun2); - }); - }); - }); - - it('triggers', () => { - // # Attempt to activate trigger - cy.apiAddUserToChannel(testChannel.id, testUser2.id); - cy.postMessageAs({ - sender: testUser2, - message: `hello from ${testUser2.username}: ${Date.now()}, oh and keyword1 happened`, - channelId: testChannel.id, - }); - - // Give the system a chance to effect the task actions. - cy.wait(TIMEOUTS.HALF_SEC); - - // * Verify action activated ion testPlaybookRun1 - cy.apiGetPlaybookRun(testPlaybookRun1.id).then(({body: playbookRun}) => { - assert.equal(playbookRun.checklists[0].items[0].state, 'closed'); - }); - - // * Verify action activated in testPlaybookRun2 - cy.apiGetPlaybookRun(testPlaybookRun2.id).then(({body: playbookRun}) => { - assert.equal(playbookRun.checklists[0].items[0].state, 'closed'); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_participants_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_participants_spec.js deleted file mode 100644 index 3ac82f83d8..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_participants_spec.js +++ /dev/null @@ -1,266 +0,0 @@ -// 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('runs > run details page > rhs > participants', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testUser2; - let testViewerUser; - let testPublicPlaybook; - let testRun; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testUser2 = viewer; - cy.apiAddUserToTeam(testTeam.id, testUser2.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the-run-name' + Date.now(), - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Add viewer user to the channel - cy.apiAddUsersToRun(testRun.id, [testUser2.id]); - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - describe('as participant', () => { - it('switching between manage modes', () => { - navigateToParticipantsList(); - - // # Switch to manage mode - cy.findByRole('button', {name: 'Manage'}).click(); - - // * Verify that we are in manage mode - cy.findByRole('button', {name: 'Manage'}).should('not.exist'); - - // # Switch to normal mode - cy.findByRole('button', {name: 'Done'}).click(); - - // * Verify that we are in normal mode - cy.findByRole('button', {name: 'Manage'}).should('exist'); - }); - - it('change owner', () => { - navigateToParticipantsList(); - - // * Verify run owner - cy.findByTestId('run-owner').contains(testUser.username); - - // # Switch to manage mode - cy.findByRole('button', {name: 'Manage'}).click(); - - // # Change owner - cy.findByTestId(testUser2.id).findByTestId('menuButton').click(); - cy.findByTestId('dropdownmenu').findByText('Make run owner').click(); - - // # Wait for changes to apply - cy.wait(2000); - - // * Verify the owner has changed - cy.findByTestId('run-owner').contains(testUser2.username); - }); - - it('remove participant', () => { - navigateToParticipantsList(); - - // * Verify run owner - cy.findByTestId('run-owner').contains(testUser.username); - - // # Switch to manage mode - cy.findByRole('button', {name: 'Manage'}).click(); - - // # remove participant - cy.findByTestId(testUser2.id).findByTestId('menuButton').click(); - cy.findByTestId('dropdownmenu').findByText('Remove from run').click(); - - // * Verify the user has been removed - cy.findByTestId(testUser2.id).should('not.exist'); - }); - - describe('add participant', () => { - it('join action enabled', () => { - navigateToParticipantsList(); - - // * Verify run owner - cy.findByTestId('run-owner').contains(testUser.username); - - // # show add participant modal - cy.findByRole('button', {name: 'Add'}).click(); - - // # Select two new participants - cy.get('#profile-autocomplete').click().type(testUser2.username + '{enter}', {delay: 400}); - cy.get('#profile-autocomplete').click().type(testViewerUser.username + '{enter}', {delay: 400}); - - // # Intercept all calls to telemetry - cy.interceptTelemetry(); - - // * Verify modal message is correct - cy.findByText('Participants will also be added to the channel linked to this run').should('exist'); - - // # Add selected participant - cy.findByTestId('modal-confirm-button').click(); - - // * Verify telemetry - cy.expectTelemetryToContain([ - { - name: 'playbookrun_participate', - type: 'track', - properties: { - from: 'run_details', - trigger: 'add_participant', - count: '2', - }, - }, - ]); - - // * Verify the users have been added - cy.findByTestId(testUser2.id).should('exist'); - cy.findByTestId(testViewerUser.id).should('exist'); - }); - - it('join action disabled', () => { - cy.apiUpdateRun(testRun.id, {createChannelMemberOnNewParticipant: false}); - navigateToParticipantsList(); - - // * Verify run owner - cy.findByTestId('run-owner').contains(testUser.username); - - // # show add participant modal - cy.findByRole('button', {name: 'Add'}).click(); - - // # Select two new participants - cy.get('#profile-autocomplete').click().type(testViewerUser.username + '{enter}', {delay: 400}); - - // * Verify modal message is correct - cy.findByText('Also add people to the channel linked to this run').should('exist'); - - // # Add selected participant - cy.findByTestId('modal-confirm-button').click(); - - // * Verify the user has been added to the run - cy.findByTestId(testViewerUser.id).should('exist'); - - // # Intercept fetching channel members - cy.intercept('channels/members/me/view').as('members'); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${testRun.name}`); - - // * Verify that no users were invited - cy.getFirstPostId().then((id) => { - cy.get(`#postMessageText_${id}`).within(() => { - // just to wait until the username is fetched - cy.contains('Someone').should('not.exist'); - cy.contains('You were added to the channel by @playbooks.'); - cy.contains(`@${testViewerUser.username}`).should('not.exist'); - }); - }); - }); - - it('join action disabled, checkbox selected', () => { - cy.apiUpdateRun(testRun.id, {createChannelMemberOnNewParticipant: false}); - navigateToParticipantsList(); - - // * Verify run owner - cy.findByTestId('run-owner').contains(testUser.username); - - // # show add participant modal - cy.findByRole('button', {name: 'Add'}).click(); - - // # Select two new participants - cy.get('#profile-autocomplete').click().type(testViewerUser.username + '{enter}', {delay: 400}); - - // * Verify modal message is correct - cy.findByText('Also add people to the channel linked to this run').should('exist'); - - // # Select checkbox - cy.findByTestId('also-add-to-channel').click({force: true}); - - // # Add selected participant - cy.findByTestId('modal-confirm-button').click(); - - // * Verify the user has been added to the run - cy.findByTestId(testViewerUser.id).should('exist'); - - // # Navigate to the playbook run channel - cy.visit(`/${testTeam.name}/channels/${testRun.name}`); - - // * Verify that the user was added to the channel - cy.getFirstPostId().then((id) => { - cy.get(`#postMessageText_${id}`).within(() => { - cy.contains('Someone').should('not.exist'); - cy.contains(`@${testViewerUser.username}`); - }); - }); - }); - }); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - it('no manage button', () => { - navigateToParticipantsList(); - - // * Verify that there is no manage button - cy.findByRole('button', {name: 'Manage'}).should('not.exist'); - }); - }); -}); - -const navigateToParticipantsList = () => { - // # Click on participants row - cy.findByTestId('runinfo-participants').click(); -}; diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_runinfo_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_runinfo_spec.js deleted file mode 100644 index 09df49b33e..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_runinfo_spec.js +++ /dev/null @@ -1,549 +0,0 @@ -// 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('runs > run details page > run info', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testRun; - - const getHeader = () => { - return cy.findByTestId('run-header-section'); - }; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - const getRHSSection = (title) => cy.findByRole('complementary').contains('section', title); - - describe('> overview', () => { - const getOverviewEntry = (entryName) => ( - getRHSSection('Overview').findByTestId(`runinfo-${entryName}`) - ); - - const commonTests = () => { - it('Playbook entry links to the playbook', () => { - // # Click on the Playbook entry - getOverviewEntry('playbook').within(() => cy.getStyledComponent('ItemLink').click()); - - // * Verify the we're in the right playbook page - cy.url().should('include', '/playbooks/playbooks'); - cy.findByTestId('playbook-editor-title').contains(testPublicPlaybook.title); - }); - - it('Owner entry shows the owner', () => { - // * Verify that the owner is shown - getOverviewEntry('owner').contains(testUser.username); - }); - - it('Participants entry shows the participants', () => { - // * Verify that the participants are rendered - getOverviewEntry('participants').within(() => { - cy.getStyledComponent('Participants').within(() => { - cy.getStyledComponent('UserPic').should('exist'); - }); - }); - }); - - it('clicking on Participants show the full list of participants', () => { - // * Click on the Participants entry - getOverviewEntry('participants').click(); - - cy.findByRole('complementary').within(() => { - // * Verify that the Participants RHS is shown - cy.findByTestId('rhs-title').contains('Participants'); - - // * Verify that the back button is shown - cy.findByTestId('rhs-back-button').should('exist'); - - // * Verify that the participants list shows the number of participants - cy.findByText('1 Participant'); - - // * Verify that the participants list contains the test user - cy.findByText(`@${testUser.username}`); - - // # Click on the back button - cy.findByTestId('rhs-back-button').click(); - - // * Verify that the RHS is back to Run info - cy.findByTestId('rhs-title').contains('Run info'); - }); - }); - }; - - describe('as participant', () => { - commonTests(); - - it('Following button can be toggled', () => { - // # Intercept all calls to telemetry - cy.interceptTelemetry(); - - getOverviewEntry('following').within(() => { - // * Verify that the user shows in the following list - cy.getStyledComponent('UserRow').within(() => { - cy.getStyledComponent('UserPic').should('have.length', 1); - }); - - // # Click the Following button - cy.findByRole('button', {name: /Following/}).click({force: true}); - - // * Verify that it now says (exactly) Follow - cy.findByRole('button', {name: /^Follow$/}).should('exist'); - - // * Verify that the user no longer shows in the following list - cy.getStyledComponent('UserRow').should('not.exist'); - - // # Click the Follow button - cy.findByRole('button', {name: /^Follow$/}).click({force: true}); - - // * Verify that it now says Following - cy.findByRole('button', {name: /Following/}).should('exist'); - }); - - cy.expectTelemetryToContain([ - { - name: 'playbookrun_unfollow', - type: 'track', - from: 'run_details', - playbookrun_id: testRun.id, - }, - { - name: 'playbookrun_follow', - type: 'track', - from: 'run_details', - playbookrun_id: testRun.id, - }, - ], {waitForCalls: 2}); - }); - - it('click channel link navigates to run\'s channel', () => { - // * Assert channel name - getOverviewEntry('channel').contains('the run name'); - - // # Click on channel item - getOverviewEntry('channel').within(() => cy.getStyledComponent('ItemLink').click()); - - // * Assert we navigated correctly - cy.url().should('include', `${testTeam.name}/channels/the-run-name`); - }); - - it('channel is still there when the run is finished', () => { - cy.apiFinishRun(testRun.id).then(() => { - // # Reload page - cy.reload(); - - // * Assert channel name - getOverviewEntry('channel').contains('the run name'); - - // # Click on channel item - getOverviewEntry('channel').within(() => cy.getStyledComponent('ItemLink').click()); - - // * Assert we navigated correctly - cy.url().should('include', `${testTeam.name}/channels/the-run-name`); - }); - }); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - commonTests(); - - it('Following button can be toggled', () => { - getOverviewEntry('following').within(() => { - // * Verify that the user is not in the following list - cy.getStyledComponent('UserRow').within(() => { - cy.getStyledComponent('UserPic').should('have.length', 1); - }); - - // # Click the Follow button - cy.findByRole('button', {name: /^Follow$/}).click({force: true}); - - // * Verify that it now says Following - cy.findByRole('button', {name: /Following/}).should('exist'); - - // * Verify that the user is now in the following list - cy.getStyledComponent('UserRow').within(() => { - cy.getStyledComponent('UserPic').should('have.length', 2); - }); - - // # Click the Follow button - cy.findByRole('button', {name: /Following/}).click({force: true}); - - // * Verify that it now says (exactly) Follow - cy.findByRole('button', {name: /^Follow$/}).should('exist'); - }); - }); - - it('there is no channel link but can request to join', () => { - // * Assert that the section exists with label Private - getOverviewEntry('channel').contains('Private'); - - // * Assert that link does not exist - getOverviewEntry('channel').within(() => { - cy.get('a').should('not.exist'); - }); - - // * Assert that request-join button does not exist - getOverviewEntry('channel').within(() => { - cy.get('button').should('not.exist'); - }); - - cy.wait(500); - - // # Click Participate button - getHeader().findByText('Participate').click(); - - // * Assert that modal is shown - cy.get('#become-participant-modal').should('exist'); - - // # Confirm modal - cy.findByTestId('modal-confirm-button').click(); - - // Assert that request-join button doesn't exist - getOverviewEntry('channel').within(() => { - cy.get('button').should('not.exist'); - }); - }); - }); - }); - - describe('> key metrics', () => { - describe('playbook without metrics', () => { - describe('it should not render', () => { - it('as participant', () => { - // * assert metrics does not exist - getRHSSection('Key Metrics').should('not.exist'); - }); - - it('as viewer', () => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - - // * assert metrics does not exist - getRHSSection('Key Metrics').should('not.exist'); - }); - }); - }); - - describe('playbook with metrics (enabled retro)', () => { - let playbookWithMetrics; - let runWithMetrics; - - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook with metrics - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook with metrics', - memberIDs: [], - metrics: [ - { - title: 'Duration', - description: 'duration', - type: 'metric_duration', - target: 6000, - }, - { - title: 'Currency', - description: 'currency', - type: 'metric_currency', - target: 100, - }, - { - title: 'Integer', - description: 'integer', - type: 'metric_integer', - target: 1, - }, - ], - }).then((playbook) => { - playbookWithMetrics = playbook; - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbookWithMetrics.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - runWithMetrics = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - const commonTests = () => { - it('key metrics is present', () => { - getRHSSection('Key Metrics').should('exist'); - }); - - it('link scrolls to retrospective', () => { - // # click in view retro link - cy.findByRole('link', {name: /View Retrospective/}).click({force: true}); - - // * verify that URL has been changed - cy.url().should('contain', '#playbook-run-retrospective'); - }); - - it('metric items scroll to corresponding metric', () => { - getRHSSection('Key Metrics').within(() => { - playbookWithMetrics.metrics.forEach((metric) => { - // # Click on metric - cy.findByText(metric.title).click({force: true}); - - // * Verify that url changed (and therefore we scrolled) - cy.url().should('contain', `#playbook-run-retrospective${metric.id}`); - }); - }); - }); - }; - - describe('as participant', () => { - commonTests(); - - it('metric items show Add value if empty', () => { - getRHSSection('Key Metrics').within(() => { - playbookWithMetrics.metrics.forEach((metric) => { - // * Verify that we show a placeholder when empty - cy.findByText(metric.title).parent().contains('Add value...'); - }); - }); - }); - - it('click on metric items, type and see the result in the RHS', () => { - const testData = { - metric_duration: { - input: '12:06:03', - expected: '12d, 6h, 3m', - }, - metric_currency: { - input: '5000', - expected: '5000', - }, - metric_integer: { - input: '42', - expected: '42', - }, - }; - - // # Type the values for the metrics - getRHSSection('Key Metrics').within(() => { - playbookWithMetrics.metrics.forEach((metric) => { - // # Click on the metric row - cy.findByText(metric.title).click(); - - // # Seems there's a re-render between clicking the title and - // # typing that occasionally leads to dropped keystrokes in - // # .type(). Wait for it to avoid. - cy.wait(1000); - - // # Type a value for the metric - cy.focused().type(testData[metric.type].input); - }); - }); - - // * Verify that the RHS is updated with those values - getRHSSection('Key Metrics').within(() => { - playbookWithMetrics.metrics.forEach((metric) => { - // * Verify that the metric was updated in the RHS - cy.findByText(metric.title).parent().contains(testData[metric.type].expected); - }); - }); - }); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${runWithMetrics.id}`); - }); - }); - - commonTests(); - - it('metric items show - if empty', () => { - getRHSSection('Key Metrics').within(() => { - playbookWithMetrics.metrics.forEach((metric) => { - // * verify that values are shown as - when empty - cy.findByText(metric.title).parent().contains('-'); - }); - }); - }); - }); - }); - - describe('playbook with metrics (disabled retro)', () => { - let playbookWithMetrics; - let runWithMetrics; - - before(() => { - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook with metrics - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook with metrics', - memberIDs: [], - metrics: [ - { - title: 'Integer', - description: 'integer', - type: 'metric_integer', - target: 1, - }, - ], - retrospectiveEnabled: false, - }).then((playbook) => { - playbookWithMetrics = playbook; - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: playbookWithMetrics.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - runWithMetrics = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - const commonTests = () => { - it('key metrics is hidden', () => { - getRHSSection('Key Metrics').should('not.exist'); - }); - }; - - describe('as participant', () => { - commonTests(); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${runWithMetrics.id}`); - }); - }); - - commonTests(); - }); - }); - }); - - describe('> recent activity', () => { - const commonTests = () => { - it('recent activity is present and it contains a timeline', () => { - getRHSSection('Recent Activity').within(() => { - // * assert that section is shown - cy.findByTestId('rhs-timeline').should('exist'); - }); - }); - - it('link switches the RHS to Timeline', () => { - getRHSSection('Recent Activity').within(() => { - // * click link to see all timeline - cy.findByText('View all').click({force: true}); - }); - - cy.findByRole('complementary').within(() => { - // * verify we changed to RHS-timeline - cy.findByTestId('rhs-title').contains('Timeline'); - cy.findByTestId('rhs-back-button').should('exist'); - }); - }); - }; - - describe('as participant', () => { - commonTests(); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - commonTests(); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_spec.js deleted file mode 100644 index 8a34f9f40e..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_spec.js +++ /dev/null @@ -1,129 +0,0 @@ -// 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('runs > run details page > RHS', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testRun; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - const getRHS = () => cy.findByRole('complementary'); - - const getHeaderButton = (name) => cy.findByTestId(`rhs-header-button-${name}`); - - const checkRHSTitle = (expectedTitle) => { - getRHS().within(() => { - cy.findByTestId('rhs-title').contains(expectedTitle); - }); - }; - - const commonTests = () => { - it('timeline button toggles timeline in the RHS', () => { - // * Verify that the run info RHS is open - checkRHSTitle('Run info'); - - // # Click on the header timeline button - getHeaderButton('timeline').click(); - - // * Verify that the run info RHS changed to Timeline - checkRHSTitle('Timeline'); - - // # Wait so we don't double-click - cy.wait(500); - - // # Click again on the header timeline button - getHeaderButton('timeline').click(); - - // * Verify that the RHS is closed - getRHS().should('not.exist'); - }); - - it('info button toggles info in the RHS', () => { - // * Verify that the run info RHS is open - checkRHSTitle('Run info'); - - // # Click on the header info button - getHeaderButton('info').click(); - - // * Verify that the RHS is now closed - getRHS().should('not.exist'); - - // # Wait so we don't double-click - cy.wait(500); - - // # Click again on the header info button - getHeaderButton('info').click(); - - // * Verify that the run info RHS is open again - checkRHSTitle('Run info'); - }); - }; - - describe('as participant', () => { - commonTests(); - }); - - describe('as viewer', () => { - beforeEach(() => { - cy.apiLogin(testViewerUser).then(() => { - cy.visit(`/playbooks/runs/${testRun.id}`); - }); - }); - - commonTests(); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_statusupdates_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_statusupdates_spec.js deleted file mode 100644 index 36510edd0a..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/rdp_rhs_statusupdates_spec.js +++ /dev/null @@ -1,150 +0,0 @@ -// 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('runs > run details page > status update', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testViewerUser; - let testPublicPlaybook; - let testRun; - - const getRHS = () => cy.findByRole('complementary'); - const getStatusUpdates = () => getRHS().findAllByTestId('status-update-card'); - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - - // # Visit the playbook run - cy.visit(`/playbooks/runs/${playbookRun.id}`); - }); - }); - - describe('as participant', () => { - it('rhs can not be open when there is no updates', () => { - // * Assert that the link is not present - cy.findByTestId('run-statusupdate-section').findByText('View all updates').should('not.exist'); - }); - - it('link opens the RHS when there are updates', () => { - cy.apiUpdateStatus({ - playbookRunId: testRun.id, - message: 'message 1', - reminder: 300, - }); - cy.apiUpdateStatus({ - playbookRunId: testRun.id, - message: 'message 2', - reminder: 300, - }); - - // # Click View all updates link - cy.findByTestId('run-statusupdate-section').findByText('View all updates').click(); - - // * Assert RHS is open and have the correct title/subtitle - getRHS().should('be.visible'); - getRHS().findByTestId('rhs-title').contains('Status updates'); - getRHS().findByTestId('rhs-subtitle').contains(testRun.name); - - // * Assert that we have both updates in reverse order - getStatusUpdates().should('have.length', 2); - getStatusUpdates().eq(0).contains('message 2'); - getStatusUpdates().eq(0).contains(testUser.username); - getStatusUpdates().eq(1).contains('message 1'); - getStatusUpdates().eq(1).contains(testUser.username); - }); - }); - - describe('as viewer', () => { - it('rhs can not be open when there is no updates', () => { - // * Log in as viewer user - cy.apiLogin(testViewerUser); - - // * Browse to test run - cy.visit(`/playbooks/runs/${testRun.id}`); - - // * Assert that the link is not present - cy.findByTestId('run-statusupdate-section').findByText('View all updates').should('not.exist'); - }); - - it('link opens the RHS when there are updates', () => { - cy.apiLogin(testUser).then(() => { - cy.apiUpdateStatus({ - playbookRunId: testRun.id, - message: 'message 1', - reminder: 300, - }); - cy.apiUpdateStatus({ - playbookRunId: testRun.id, - message: 'message 2', - reminder: 300, - }); - }); - - // * Log in as viewer user - cy.apiLogin(testViewerUser); - - // * Browse to test run - cy.visit(`/playbooks/runs/${testRun.id}`); - - // # Click View all updates link - cy.findByTestId('run-statusupdate-section').findByText('View all updates').click(); - - // * Assert RHS is open and have the correct title/subtitle - getRHS().should('be.visible'); - getRHS().findByTestId('rhs-title').contains('Status updates'); - getRHS().findByTestId('rhs-subtitle').contains(testRun.name); - - // * Assert that we have both updates in reverse order - getStatusUpdates().should('have.length', 2); - getStatusUpdates().eq(0).contains('message 2'); - getStatusUpdates().eq(0).contains(testUser.username); - getStatusUpdates().eq(1).contains('message 1'); - getStatusUpdates().eq(1).contains(testUser.username); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/runs/taskinbox_spec.js b/e2e-tests/cypress/tests/integration/playbooks/runs/taskinbox_spec.js deleted file mode 100644 index f7c156871c..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/runs/taskinbox_spec.js +++ /dev/null @@ -1,189 +0,0 @@ -// 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('Task Inbox >', {testIsolation: true}, () => { - let testTeam; - let testUser; - - let testViewerUser; - let testPublicPlaybook; - let testRun; - - before(() => { - cy.apiInitSetup().then(({team, user}) => { - testTeam = team; - testUser = user; - - cy.apiCreateCustomAdmin().then(({sysadmin: adminUser}) => { - cy.apiAddUserToTeam(testTeam.id, adminUser.id); - }); - - // Create another user in the same team - cy.apiCreateUser().then(({user: viewer}) => { - testViewerUser = viewer; - cy.apiAddUserToTeam(testTeam.id, testViewerUser.id); - }); - - // # Login as testUser - cy.apiLogin(testUser); - - // # Create a public playbook - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Public Playbook', - checklists: [ - { - title: 'Stage 1', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - {title: 'Step 3'}, - {title: 'Step 4'}, - ], - }, - ], - memberIDs: [], - }).then((playbook) => { - testPublicPlaybook = playbook; - - cy.apiRunPlaybook({ - teamId: testTeam.id, - playbookId: testPublicPlaybook.id, - playbookRunName: 'the run name', - ownerUserId: testUser.id, - }).then((playbookRun) => { - testRun = playbookRun; - cy.apiChangeChecklistItemAssignee(testRun.id, 0, 0, testUser.id); - }); - }); - }); - }); - - beforeEach(() => { - // # Size the viewport to show the RHS without covering posts. - cy.viewport('macbook-13'); - - // # Login as testUser - cy.apiLogin(testUser); - - cy.visit(`/playbooks/runs/${testRun.id}`); - cy.assertRunDetailsPageRenderComplete(testUser.username); - }); - - const getRHS = () => cy.get('#playbooks-backstage-sidebar-right'); - - it('icon in global header', () => { - // # Visit the playbooks product - cy.visit('/playbooks'); - - // # Verify icon present in global header icon to open - cy.findByTestId('header-task-inbox-icon').click(); - }); - - it('icon toggles taskinbox view', () => { - // # Intercept all calls to telemetry - cy.interceptTelemetry(); - - // # Click on global header icon to open - cy.findByTestId('header-task-inbox-icon').click(); - - // * assert RHS is shown - getRHS().should('be.visible'); - - // * assert telemetry pageview - cy.expectTelemetryToContain([ - { - name: 'task_inbox', - type: 'page', - }, - ]); - - // * assert zero case - getRHS().within(() => { - cy.getStyledComponent('HeaderTitle').contains('Your tasks'); - cy.getStyledComponent('Body').contains('1 assigned'); - }); - - // # Click on global header icon to close - cy.findByTestId('header-task-inbox-icon').click(); - - // * assert RHS is not shown - getRHS().should('not.exist'); - }); - - it('show unassigned tasks from runs I own', () => { - // # Click on global header icon to open - cy.findByTestId('header-task-inbox-icon').click(); - - // * assert 4 tasks are shown (all tasks from runs I own enabled by default) - getRHS().within(() => { - cy.getStyledComponent('TaskList').within(() => { - cy.getStyledComponent('Container').should('have.length', 4); - }); - }); - }); - - it('show only assigned tasks', () => { - // # Click on global header icon to open - cy.findByTestId('header-task-inbox-icon').click(); - - getRHS().within(() => { - cy.getStyledComponent('TaskList').within(() => { - // * assert 4 tasks are shown - cy.getStyledComponent('Container').should('have.length', 4); - }); - - // # Click on filters - cy.findByText('Filters').click(); - }); - - // # Deactivate show alltasks - cy.findByText('Show all tasks from runs I own').click(); - - cy.getStyledComponent('TaskList').within(() => { - // * assert 1 tasks are shown - cy.getStyledComponent('Container').should('have.length', 1); - }); - }); - - it('tasks can be checked', () => { - // # Click on global header icon to open - cy.findByTestId('header-task-inbox-icon').click(); - - getRHS().within(() => { - cy.getStyledComponent('TaskList').within(() => { - // * assert 4 tasks are shown - cy.getStyledComponent('Container').should('have.length', 4); - - // # Check the first task - cy.getStyledComponent('Container').eq(0).within(() => { - cy.get('input').click(); - }); - - // * assert 3 tasks are shown - cy.getStyledComponent('Container').should('have.length', 3); - }); - - // # Click on filters - cy.findByText('Filters').click(); - }); - - // # Activate checked task visibility in filters - cy.findByText('Show checked tasks').click(); - - getRHS().within(() => { - cy.getStyledComponent('TaskList').within(() => { - // * assert 4 tasks are shown - cy.getStyledComponent('Container').should('have.length', 4); - }); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/integration/playbooks/tours_spec_ignore_.js b/e2e-tests/cypress/tests/integration/playbooks/tours_spec_ignore_.js deleted file mode 100644 index 10983a06dc..0000000000 --- a/e2e-tests/cypress/tests/integration/playbooks/tours_spec_ignore_.js +++ /dev/null @@ -1,121 +0,0 @@ -// 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('playbook tour points', {testIsolation: true}, () => { - let testTeam; - let testUser; - let testSysadmin; - beforeEach(() => { - cy.apiInitSetup({promoteNewUserAsAdmin: true}).then(({team, user: sysadmin}) => { - testTeam = team; - testSysadmin = sysadmin; - - // # Create a user with tutorials enabled - cy.apiCreateUser({bypassTutorial: false}).then(({user: userWithTours}) => { - testUser = userWithTours; - cy.apiAddUserToTeam(team.id, testUser.id); - cy.apiLogin(userWithTours); - }); - }); - }); - - afterEach(() => { - // # Ensure apiInitSetup() can run again - cy.apiLogin(testSysadmin); - }); - - it('creation tour', () => { - // # Open creation view from RHS - cy.visit(`/${testTeam.name}/channels/town-square`); - cy.get('#incidentIcon').click({force: true}); - cy.findByRole('button', {name: /create playbook/i}).click(); - cy.url().should('contain', '/playbooks/playbooks/new'); - - // * Verify the tutorial steps - cy.contains('Create and assign tasks').should('be.visible'); - cy.findByRole('button', {name: /next/i}).click(); - - cy.contains('Set up assumptions').should('be.visible'); - cy.findByRole('button', {name: /next/i}).click(); - - cy.contains('Keep stakeholders updated').should('be.visible'); - cy.findByRole('button', {name: /next/i}).click(); - - cy.contains('Learn AND reflect').should('be.visible'); - cy.findByRole('button', {name: /done/i}).click(); - }); - - it('preview tour', () => { - // # Make a playbook to preview - cy.apiCreatePlaybook({ - teamId: testTeam.id, - title: 'Preview Tour Test Playbook', - memberIDs: [], - }).then(() => { - // # Open the playbook - cy.visit('/playbooks/playbooks'); - cy.findByText('Preview Tour Test Playbook').click(); - - // * Verify the tutorial steps - cy.contains('Welcome to the playbook preview page!').should('be.visible'); - cy.findByRole('button', {name: /next/i}).click(); - - cy.contains('different sections of the playbook').should('be.visible'); - cy.findByRole('button', {name: /next/i}).click(); - - cy.contains('Ready to run your playbook?').should('be.visible'); - cy.findByRole('button', {name: /done/i}).click(); - }); - }); - - describe('run tour', () => { - beforeEach(() => { - // # Disable the preview tour which we would otherwise see - cy.apiSaveUserPreference([{ - user_id: testUser.id, - category: 'playbook_preview', - name: testUser.id, - value: '999', - }], testUser.id); - - // # Start a run from the tutorial template - cy.visit('/playbooks/playbooks'); - cy.findByText('Learn how to use playbooks').click(); - cy.findByRole('button', {name: /run playbook/i}).click({force: true}); - - // * Verify the tour confirmation modal is shown (other tours don't have one) - cy.contains('auto-created your run').should('be.visible'); - }); - - it('follows the tour when chosen from modal', () => { - // # Accept the tour - cy.contains('quick tour').click(); - - // * Verify the tutorial steps - cy.contains('See who is involved').should('be.visible'); - cy.findByRole('button', {name: /next/i}).click(); - - cy.contains('Post status updates').should('be.visible'); - cy.findByRole('button', {name: /next/i}).click(); - - cy.contains('Track progress and ownership').should('be.visible'); - cy.findByRole('button', {name: /done/i}).click(); - }); - - it('does not follow the tour when dismissed from modal', () => { - // # Dismiss the tour - cy.findByRole('button', {name: /let me explore/i}).click(); - - // * Verify the first step is _not_ shown - cy.contains('See who is involved').should('not.exist'); - }); - }); -}); diff --git a/e2e-tests/cypress/tests/support/api/index.js b/e2e-tests/cypress/tests/support/api/index.js index 6d38b1883b..7efc31c641 100644 --- a/e2e-tests/cypress/tests/support/api/index.js +++ b/e2e-tests/cypress/tests/support/api/index.js @@ -11,7 +11,6 @@ import './data_retention'; import './group'; import './keycloak'; import './ldap'; -import './playbooks'; import './preference'; import './plugin'; import './role'; diff --git a/e2e-tests/cypress/tests/support/api/playbooks.js b/e2e-tests/cypress/tests/support/api/playbooks.js deleted file mode 100644 index 472ee9f351..0000000000 --- a/e2e-tests/cypress/tests/support/api/playbooks.js +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -const playbookRunsEndpoint = '/plugins/playbooks/api/v0/runs'; - -const StatusOK = 200; -const StatusCreated = 201; - -/** - * Get all playbook runs directly via API - */ -Cypress.Commands.add('apiGetAllPlaybookRuns', (teamId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: '/plugins/playbooks/api/v0/runs', - qs: {team_id: teamId, per_page: 10000}, - method: 'GET', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response); - }); -}); - -/** - * Get all InProgress playbook runs directly via API - */ -Cypress.Commands.add('apiGetAllInProgressPlaybookRuns', (teamId, userId = '') => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: '/plugins/playbooks/api/v0/runs', - qs: {team_id: teamId, status: 'InProgress', participant_id: userId}, - method: 'GET', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response); - }); -}); - -/** - * Get playbook run by name directly via API - */ -Cypress.Commands.add('apiGetPlaybookRunByName', (teamId, name) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: '/plugins/playbooks/api/v0/runs', - qs: {team_id: teamId, search_term: name}, - method: 'GET', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response); - }); -}); - -/** - * Get a playbook run directly via API - * @param {String} playbookRunId - * All parameters required - */ -Cypress.Commands.add('apiGetPlaybookRun', (playbookRunId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `${playbookRunsEndpoint}/${playbookRunId}`, - method: 'GET', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response); - }); -}); - -/** - * Start a playbook run directly via API. - */ -Cypress.Commands.add('apiRunPlaybook', ( - { - teamId, - playbookId, - playbookRunName, - ownerUserId, - channelId, - description, - }, options) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: playbookRunsEndpoint, - method: 'POST', - body: { - name: playbookRunName, - owner_user_id: ownerUserId, - team_id: teamId, - playbook_id: playbookId, - channel_id: channelId, - description, - }, - failOnStatusCode: !(options?.expectedStatusCode), - }).then((response) => { - const statusCode = options?.expectedStatusCode || StatusCreated; - expect(response.status).to.equal(statusCode); - cy.wrap(response.body); - }); -}); - -// Finish a playbook's run programmaticially. Uses currently logged in user, so that user must -// have edit permissions on the run -Cypress.Commands.add('apiFinishRun', (playbookRunId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `${playbookRunsEndpoint}/${playbookRunId}/finish`, - method: 'PUT', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response.body); - }); -}); - -// Update a playbook run's status programmatically. -Cypress.Commands.add('apiUpdateStatus', ( - { - playbookRunId, - message, - reminder = 300, - }) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `${playbookRunsEndpoint}/${playbookRunId}/status`, - method: 'POST', - body: { - message, - reminder, - }, - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response.body); - }); -}); - -/** - * Change the owner of a playbook run directly via API - * @param {String} playbookRunId - * @param {String} userId - * All parameters required - */ -Cypress.Commands.add('apiChangePlaybookRunOwner', (playbookRunId, userId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: playbookRunsEndpoint + '/' + playbookRunId + '/owner', - method: 'POST', - body: { - owner_id: userId, - }, - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response); - }); -}); - -/** - * Change the assignee of a checklist item directly via API - * @param {String} playbookRunId - * @param {String} checklistId - * @param {String} itemId - * @param {String} userId - * All parameters required - */ -Cypress.Commands.add('apiChangeChecklistItemAssignee', (playbookRunId, checklistId, itemId, userId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: playbookRunsEndpoint + `/${playbookRunId}/checklists/${checklistId}/item/${itemId}/assignee`, - method: 'PUT', - body: { - assignee_id: userId, - }, - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response); - }); -}); - -/** - * Check a checklist item directly via API - * @param {String} playbookRunId - * @param {String} checklistId - * @param {String} itemId - * @param {String} state ('' or 'closed') - */ -Cypress.Commands.add('apiSetChecklistItemState', (playbookRunId, checklistId, itemId, state) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: playbookRunsEndpoint + `/${playbookRunId}/checklists/${checklistId}/item/${itemId}/state`, - method: 'PUT', - body: { - new_state: state, - }, - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response); - }); -}); - -// Verify playbook run is created -Cypress.Commands.add('verifyPlaybookRunActive', (teamId, playbookRunName, playbookRunDescription) => { - cy.apiGetPlaybookRunByName(teamId, playbookRunName).then((response) => { - const returnedPlaybookRuns = response.body; - const playbookRun = returnedPlaybookRuns.items.find((inc) => inc.name === playbookRunName); - assert.isDefined(playbookRun); - assert.equal(playbookRun.end_at, 0); - assert.equal(playbookRun.name, playbookRunName); - - cy.log('test 1'); - - // Only check the description if provided. The server may supply a default depending - // on how the playbook run was started. - if (playbookRunDescription) { - assert.equal(playbookRun.description, playbookRunDescription); - } - }); -}); - -// Verify playbook run exists but is not active -Cypress.Commands.add('verifyPlaybookRunEnded', (teamId, playbookRunName) => { - cy.apiGetPlaybookRunByName(teamId, playbookRunName).then((response) => { - const returnedPlaybookRuns = response.body; - const playbookRun = returnedPlaybookRuns.items.find((inc) => inc.name === playbookRunName); - assert.isDefined(playbookRun); - assert.notEqual(playbookRun.end_at, 0); - }); -}); - -// Create a playbook programmatically. -Cypress.Commands.add('apiCreatePlaybook', ( - { - teamId, - title, - description, - createPublicPlaybookRun, - createChannelMemberOnNewParticipant = true, - checklists, - memberIDs, - makePublic = true, - broadcastEnabled, - broadcastChannelIds, - reminderMessageTemplate, - reminderTimerDefaultSeconds = 24 * 60 * 60, // 24 hours - statusUpdateEnabled = true, - retrospectiveReminderIntervalSeconds, - retrospectiveTemplate, - retrospectiveEnabled = true, - invitedUserIds, - inviteUsersEnabled, - defaultOwnerId, - defaultOwnerEnabled, - announcementChannelId, - announcementChannelEnabled, - webhookOnCreationURLs, - webhookOnCreationEnabled, - webhookOnStatusUpdateURLs, - webhookOnStatusUpdateEnabled, - messageOnJoin, - messageOnJoinEnabled, - signalAnyKeywords, - signalAnyKeywordsEnabled, - channelNameTemplate, - runSummaryTemplate, - runSummaryTemplateEnabled, - channelMode = 'create_new_channel', - channelId = '', - metrics, - }) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: '/plugins/playbooks/api/v0/playbooks', - method: 'POST', - body: { - title, - description, - team_id: teamId, - create_public_playbook_run: createPublicPlaybookRun, - create_channel_member_on_new_participant: createChannelMemberOnNewParticipant, - checklists, - public: makePublic, - members: memberIDs?.map((val) => ({user_id: val, roles: ['playbook_member', 'playbook_admin']})), - broadcast_enabled: broadcastEnabled, - broadcast_channel_ids: broadcastChannelIds, - reminder_message_template: reminderMessageTemplate, - reminder_timer_default_seconds: reminderTimerDefaultSeconds, - status_update_enabled: statusUpdateEnabled, - retrospective_reminder_interval_seconds: retrospectiveReminderIntervalSeconds, - retrospective_template: retrospectiveTemplate, - retrospective_enabled: retrospectiveEnabled, - invited_user_ids: invitedUserIds, - invite_users_enabled: inviteUsersEnabled, - default_owner_id: defaultOwnerId, - default_owner_enabled: defaultOwnerEnabled, - announcement_channel_id: announcementChannelId, - announcement_channel_enabled: announcementChannelEnabled, - webhook_on_creation_urls: webhookOnCreationURLs, - webhook_on_creation_enabled: webhookOnCreationEnabled, - webhook_on_status_update_urls: webhookOnStatusUpdateURLs, - webhook_on_status_update_enabled: webhookOnStatusUpdateEnabled, - message_on_join: messageOnJoin, - message_on_join_enabled: messageOnJoinEnabled, - signal_any_keywords: signalAnyKeywords, - signal_any_keywords_enabled: signalAnyKeywordsEnabled, - channel_name_template: channelNameTemplate, - run_summary_template: runSummaryTemplate, - run_summary_template_enabled: runSummaryTemplateEnabled, - channel_mode: channelMode, - channel_id: channelId, - metrics, - }, - }).then((response) => { - expect(response.status).to.equal(201); - cy.wrap(response.headers.location); - }).then((location) => { - cy.request({ - url: location, - method: 'GET', - }).then((response) => { - cy.wrap(response.body); - }); - }); -}); - -// Create a test playbook programmatically. -Cypress.Commands.add('apiCreateTestPlaybook', ( - { - teamId, - title, - userId, - broadcastEnabled, - broadcastChannelIds, - reminderMessageTemplate, - checklists, - inviteUsersEnabled, - reminderTimerDefaultSeconds = 24 * 60 * 60, // 24 hours - otherMembers = [], - invitedUserIds = [], - channelNameTemplate = '', - }) => ( - cy.apiCreatePlaybook({ - teamId, - title, - checklists: checklists || [{ - title: 'Stage 1', - items: [ - {title: 'Step 1'}, - {title: 'Step 2'}, - ], - }], - memberIDs: [ - userId, - ...otherMembers, - ], - broadcastEnabled, - broadcastChannelIds, - reminderMessageTemplate, - reminderTimerDefaultSeconds, - invitedUserIds, - inviteUsersEnabled, - channelNameTemplate, - createChannelMemberOnNewParticipant: true, - removeChannelMemberOnRemovedParticipant: true, - }) -)); - -// Verify that the playbook was created -Cypress.Commands.add('verifyPlaybookCreated', (teamId, playbookTitle) => ( - cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: '/plugins/playbooks/api/v0/playbooks', - qs: {team_id: teamId, sort: 'title', direction: 'asc'}, - method: 'GET', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - const playbookResults = response.body; - const playbook = playbookResults.items.find((p) => p.title === playbookTitle); - assert.isDefined(playbook); - }) -)); - -// Get a playbook -Cypress.Commands.add('apiGetPlaybook', (playbookId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `/plugins/playbooks/api/v0/playbooks/${playbookId}`, - method: 'GET', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response.body); - }); -}); - -// Update a playbook -Cypress.Commands.add('apiUpdatePlaybook', (playbook, expectedHttpCode = StatusOK) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `/plugins/playbooks/api/v0/playbooks/${playbook.id}`, - method: 'PUT', - body: JSON.stringify(playbook), - failOnStatusCode: false, - }).then((response) => { - expect(response.status).to.equal(expectedHttpCode); - cy.wrap(response.body); - }); -}); - -// Archive a playbook -Cypress.Commands.add('apiArchivePlaybook', (playbookId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `/plugins/playbooks/api/v0/playbooks/${playbookId}`, - method: 'DELETE', - }).then((response) => { - expect(response.status).to.equal(204); - }); -}); - -// Follow a playbook run -Cypress.Commands.add('apiFollowPlaybookRun', (playbookRunId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `/plugins/playbooks/api/v0/runs/${playbookRunId}/followers`, - method: 'PUT', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response.body); - }); -}); - -// Unfollow a playbook run -Cypress.Commands.add('apiUnfollowPlaybookRun', (playbookRunId) => { - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: `/plugins/playbooks/api/v0/runs/${playbookRunId}/followers`, - method: 'DELETE', - }).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response.body); - }); -}); - -//addUsersToRun -Cypress.Commands.add('apiAddUsersToRun', (playbookRunId, usersIds) => { - const query = ` - mutation AddRunParticipants($runID: String!, $userIDs: [String!]!) { - addRunParticipants(runID: $runID, userIDs: $userIDs) - } - `; - const vars = { - runID: playbookRunId, - userIDs: usersIds, - }; - return doGraphqlQuery(query, 'AddRunParticipants', vars).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response.body); - }); -}); - -//updateRun -Cypress.Commands.add('apiUpdateRun', (playbookRunId, updates) => { - const query = ` - mutation UpdateRun($id: String!, $updates: RunUpdates!) { - updateRun(id: $id, updates: $updates) - } - `; - const vars = { - id: playbookRunId, - updates, - }; - return doGraphqlQuery(query, 'UpdateRun', vars).then((response) => { - expect(response.status).to.equal(StatusOK); - cy.wrap(response.body); - }); -}); - -const doGraphqlQuery = (query, operationName, variables) => { - const payload = {query, operationName, variables}; - return cy.request({ - headers: {'X-Requested-With': 'XMLHttpRequest'}, - url: '/plugins/playbooks/api/v0/query', - body: JSON.stringify(payload), - method: 'POST', - }); -}; diff --git a/e2e-tests/cypress/tests/support/ui/index.js b/e2e-tests/cypress/tests/support/ui/index.js index c841f133cd..9344e441b1 100644 --- a/e2e-tests/cypress/tests/support/ui/index.js +++ b/e2e-tests/cypress/tests/support/ui/index.js @@ -19,7 +19,6 @@ import './login'; import './menu'; import './mfa'; import './modal'; -import './playbooks'; import './post'; import './post_dropdown_menu'; import './search'; diff --git a/e2e-tests/cypress/tests/support/ui/playbooks.js b/e2e-tests/cypress/tests/support/ui/playbooks.js deleted file mode 100644 index 9e23debf73..0000000000 --- a/e2e-tests/cypress/tests/support/ui/playbooks.js +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import * as TIMEOUTS from '../../fixtures/timeouts'; -const playbookRunStartCommand = '/playbook run '; - -Cypress.Commands.add('startPlaybookRun', (playbookName, playbookRunName) => { - cy.get('#interactiveDialogModal').should('exist').within(() => { - // # Select playbook - cy.selectPlaybookFromDropdown(playbookName); - - // # Type playbook run name - cy.findByTestId('playbookRunNameinput').type(playbookRunName, {force: true}); - - // # Submit - cy.get('#interactiveDialogSubmit').click(); - }); - - cy.get('#interactiveDialogModal').should('not.exist'); -}); - -// Opens playbook run dialog using the `/playbook run` slash command -Cypress.Commands.add('openPlaybookRunDialogFromSlashCommand', () => { - cy.uiPostMessageQuickly(playbookRunStartCommand); -}); - -// Starts playbook run with the `/playbook run` slash command -Cypress.Commands.add('startPlaybookRunWithSlashCommand', (playbookName, playbookRunName) => { - cy.openPlaybookRunDialogFromSlashCommand(); - - cy.startPlaybookRun(playbookName, playbookRunName); -}); - -// Selects Playbooks icon in the App Bar -Cypress.Commands.add('getPlaybooksAppBarIcon', () => { - cy.get('#channel_view').should('be.visible'); - - return cy.get('.app-bar').find('#app-bar-icon-playbooks .app-bar__icon-inner'); -}); - -// Starts playbook run from the playbook run RHS -Cypress.Commands.add('startPlaybookRunFromRHS', (playbookName, playbookRunName) => { - cy.get('#channel-header').within(() => { - // open flagged posts to ensure playbook run RHS is closed - cy.get('#channelHeaderFlagButton').click(); - - // open the playbook run RHS - cy.getPlaybooksAppBarIcon().should('exist').click(); - }); - - cy.get('#rhsContainer').should('exist').within(() => { - cy.findByText('Run playbook').click(); - }); - - cy.startPlaybookRun(playbookName, playbookRunName); -}); - -// Create a new task from the RHS -Cypress.Commands.add('addNewTaskFromRHS', (taskname) => { - // Click add new task - cy.findByTestId('add-new-task-0').click(); - - // Type a name - cy.findByTestId('checklist-item-textarea-title').type(taskname); - - // Save task - cy.findByTestId('checklist-item-save-button').click(); -}); - -// Starts playbook run from the post menu -Cypress.Commands.add('startPlaybookRunFromPostMenu', (playbookName, playbookRunName) => { - // post a message as user to avoid system message - cy.findByTestId('post_textbox').clear().type('new message here{enter}'); - - // post a second message because cypress has trouble finding latest post when there's only one message - cy.findByTestId('post_textbox').clear().type('another new message here{enter}'); - cy.clickPostActionsMenu(); - cy.findByTestId('playbookRunPostMenuIcon').click(); - cy.startPlaybookRun(playbookName, playbookRunName); -}); - -// Create playbook -Cypress.Commands.add('createPlaybook', (teamName, playbookName) => { - cy.visit('/playbooks/playbooks/new'); - - cy.findByTestId('save_playbook', {timeout: TIMEOUTS.HALF_MIN}).should('exist'); - - // # Type playbook name - cy.get('#playbook-name .editable-trigger').click(); - cy.get('#playbook-name .editable-input').type(playbookName); - cy.get('#playbook-name .editable-input').type('{enter}'); - - // # Save playbook - cy.findByTestId('save_playbook', {timeout: TIMEOUTS.HALF_MIN}).should('not.be.disabled').click(); - cy.wait(TIMEOUTS.TWO_SEC); - cy.findByTestId('save_playbook', {timeout: TIMEOUTS.HALF_MIN}).should('not.be.disabled').click(); -}); - -// Select the playbook from the dropdown menu -Cypress.Commands.add('selectPlaybookFromDropdown', (playbookName) => { - cy.findByTestId('autoCompleteSelector').should('exist').within(() => { - cy.get('input').click().type(playbookName.toLowerCase(), {force: true}); - cy.get('#suggestionList').contains(playbookName).click({force: true}); - }); -}); - -Cypress.Commands.add('createPost', (message) => { - // post a message as user to avoid system message - cy.findByTestId('post_textbox').clear().type(`${message}{enter}`); -}); - -Cypress.Commands.add('addPostToTimelineUsingPostMenu', (playbookRunName, summary, postId) => { - cy.clickPostDotMenu(postId); - cy.findByTestId('playbookRunAddToTimeline').click(); - - cy.get('#interactiveDialogModal').should('exist').within(() => { - // # Select playbook run - cy.findByTestId('autoCompleteSelector').should('exist').within(() => { - cy.get('input').click().type(playbookRunName); - cy.get('#suggestionList').contains(playbookRunName).click({force: true}); - }); - - // # Type playbook run name - cy.findByTestId('summaryinput').clear().type(summary, {force: true}); - - // # Submit - cy.get('#interactiveDialogSubmit').click(); - }); - - cy.get('#interactiveDialogModal').should('not.exist'); -}); - -Cypress.Commands.add('openSelector', () => { - cy.findByText('Search for people').click({force: true}); -}); - -Cypress.Commands.add('addInvitedUser', (userName) => { - cy.get('.invite-users-selector__menu').within(() => { - cy.findByText(userName).click({force: true}); - }); -}); - -Cypress.Commands.add('selectOwner', (userName) => { - cy.get('.assign-owner-selector__menu').within(() => { - cy.findByText(userName).click({force: true}); - }); -}); - -Cypress.Commands.add('selectChannel', (channelName) => { - cy.get('#playbook-automation-broadcast .playbooks-rselect__menu').within(() => { - cy.findByText(channelName).click({force: true}); - }); -}); - -Cypress.Commands.add('openReminderSelector', () => { - cy.get('#reminder_timer_datetime input').click({force: true}); -}); - -Cypress.Commands.add('selectReminderTime', (timeText) => { - cy.get('#reminder_timer_datetime .playbooks-rselect__menu').within(() => { - cy.findByText(timeText).click({force: true}); - }); -}); - -/** - * Update the status of the current playbook run through the slash command. - */ -Cypress.Commands.add('updateStatus', (message, reminderQuery) => { - // # Run the slash command to update status. - cy.uiPostMessageQuickly('/playbook update '); - - // # Get the interactive dialog modal. - cy.getStatusUpdateDialog().within(() => { - // # remove what's there if applicable, and type the new update in the textbox. - cy.findByTestId('update_run_status_textbox').clear().type(message); - - if (reminderQuery) { - cy.get('#reminder_timer_datetime').within(() => { - cy.get('input').type(reminderQuery, {delay: TIMEOUTS.TWO_HUNDRED_MILLIS, force: true}).wait(TIMEOUTS.ONE_SEC).type('{enter}'); - }); - } - - // # Submit the dialog. - cy.get('button.confirm').click(); - }); - - // * Verify that the interactive dialog has gone. - cy.getStatusUpdateDialog().should('not.exist'); - - // # Return the post ID of the status update. - return cy.getLastPostId(); -}); - -/** - * Edit a post through the post dot menu. - * @param {String} postId - ID of the post to delete. - * @param {String} newMessage - New content of the post. - */ -Cypress.Commands.add('editPost', (postId, newMessage) => { - // # Open the post dot menu. - cy.clickPostDotMenu(postId); - - // # Click on the Edit menu option. - cy.get(`#edit_post_${postId}`).click(); - - // # Overwrite the post content with the new message provided. - cy.get('#edit_textbox').clear().type(newMessage); - - // # Confirm the edit in the dialog. - cy.get('#editButton').click(); -}); - -Cypress.Commands.add('getStatusUpdateDialog', () => { - return cy.findByRole('dialog', {name: /post update/i}); -}); - -Cypress.Commands.add('getStyledComponent', (className) => { - cy.get(`[class^="${className}-"]`); -}); - -/** - * Get the provided pseudo-class from the previous element and return the property passed as argument - * @param {String} pseudoClass - CSS pseudo class to get. - * @param {String} property - Property that will be returned. - * - * Stolen from https://stackoverflow.com/questions/55516990/cypress-testing-pseudo-css-class-before - */ -Cypress.Commands.add('cssPseudoClass', {prevSubject: 'element'}, (el, pseudoClass, property) => { - const win = el[0].ownerDocument.defaultView; - const pseudoElem = win.getComputedStyle(el[0], pseudoClass); - return pseudoElem.getPropertyValue(property).replace(/(^")|("$)/g, ''); -}); - -/** - * Get the :before pseudo-class from the previous element and return the property passed as argument - * @param {String} property - Property that will be returned. - */ -Cypress.Commands.add('before', {prevSubject: 'element'}, (el, property) => { - return cy.wrap(el).cssPseudoClass('before', property); -}); - -/** - * Get the :after pseudo-class from the previous element and return the property passed as argument - * @param {String} property - Property that will be returned. - */ -Cypress.Commands.add('after', {prevSubject: 'element'}, (el, property) => { - return cy.wrap(el).cssPseudoClass('after', property); -}); - -function waitUntilPermanentPost() { - cy.get('#postListContent').should('exist'); - cy.waitUntil(() => cy.findAllByTestId('postView').last().then((el) => !(el[0].id.includes(':')))); -} - -Cypress.Commands.add('getFirstPostId', () => { - waitUntilPermanentPost(); - - cy.findAllByTestId('postView').first().should('have.attr', 'id').and('not.include', ':'). - invoke('replace', 'post_', ''); -}); - -Cypress.Commands.add('assertRunDetailsPageRenderComplete', (expectedRunOwner) => { - cy.findByTestId('lhs-navigation').should('be.visible').within(() => { - cy.contains('Playbooks').should('be.visible'); - cy.contains('Runs').should('be.visible'); - }); - cy.get('#playbooks-sidebar-right').should('be.visible').within(() => { - cy.findByTestId('assignee-profile-selector').should('contain', expectedRunOwner); - cy.findAllByTestId('timeline-item', {exact: false}).should('have.length.of.at.least', 1); - cy.findAllByTestId('profile-option', {exact: false}).should('have.length.of.at.least', 1); - }); -}); - -Cypress.Commands.add('interceptTelemetry', () => { - cy.intercept('/plugins/playbooks/api/v0/telemetry').as('telemetry'); -}); - -const defaultExpectTelemetryToContainOptions = { - waitForCalls: 'auto', -}; - -// cy.expectTelemetryToContain expects to find the given telemetry events in the order given among the -// recorded telemetry. It doesn't fail if other telemetry events happen to occur in between. -Cypress.Commands.add('expectTelemetryToContain', (items, opts) => { - const options = {...defaultExpectTelemetryToContainOptions, ...opts}; - - // Wait for at least as many telemetry events as requested if auto, or explicit number if passed. - if (options.waitForCalls === 'auto') { - items.forEach(() => cy.wait('@telemetry')); - } else { - for (let i = 0; i < options.waitForCalls; i++) { - cy.wait('@telemetry'); - } - } - - // When additional telemetry events are emitted than what is expected, the ones we want may - // still be be pending, so wait a bit more to try to let requests settle. - cy.wait(TIMEOUTS.HALF_SEC); - - cy.get('@telemetry.all').then((xhrs) => { - let xhrIndex = 0; - items.forEach((item) => { - while (xhrIndex < xhrs.length) { - const xhr = xhrs[xhrIndex]; - - // Advance to the next xhr element regardless of whether or not we find a match. - xhrIndex++; - - if (xhr.request.body.name === item.name && xhr.request.body.type === item.type) { - // Validate only passed properties - if (item.properties) { - for (const [key, value] of Object.entries(item.properties)) { - expect(xhr.request.body.properties[key]).to.eq(value, `Property ${key} does not match for event ${item.name}`); - } - } - - return; - } - } - - throw new Error(`failed to find telemetry event '${item.type}' '${item.name}'`); - }); - }); -});