CLD-7841 Optimize E2E testing costs (#27883)

* Utilize free runners for E2E tests, report back to PR on run completion
* Increase test stability on smaller instances
* Merge worker reports
* merge start+prepare steps
* upgrade keycloak
* increase test timeouts
* Add video recording to report artifacts

Co-authored-by: Saturnino Abril <5334504+saturninoabril@users.noreply.github.com>

---------

Co-authored-by: Saturnino Abril <5334504+saturninoabril@users.noreply.github.com>
Этот коммит содержится в:
Mario Vitale
2024-08-14 21:39:08 +02:00
коммит произвёл GitHub
родитель 5f19d8513b
Коммит 948f8941f0
37 изменённых файлов: 261 добавлений и 151 удалений

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

@@ -188,6 +188,10 @@ describe('Verify Accessibility Support in Post', () => {
cy.get(`#CENTER_flagIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'save message');
cy.focused().tab();
// * Verify focus is on the actions button
cy.get(`#CENTER_actions_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'actions');
cy.focused().tab();
// * Verify focus is on the comment button
cy.get(`#CENTER_commentIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'reply');
cy.focused().tab();
@@ -234,6 +238,10 @@ describe('Verify Accessibility Support in Post', () => {
cy.get(`#RHS_COMMENT_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'more');
cy.focused().tab({shift: true});
// * Verify focus is on the actions button
cy.get(`#RHS_COMMENT_actions_button_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'actions');
cy.focused().tab({shift: true});
// * Verify focus is on the save icon
cy.get(`#RHS_COMMENT_flagIcon_${postId}`).should('be.focused').and('have.attr', 'aria-label', 'save message');
cy.focused().tab({shift: true});
@@ -333,8 +341,9 @@ function verifyPostLabel(elementId, username, labelSuffix) {
// * Verify reader reads out the post correctly
cy.get('@lastPost').then((el) => {
// # Get the post time
cy.wrap(el).find('time.post__time').invoke('text').then((time) => {
const expectedLabel = `At ${time} ${Cypress.dayjs().format('dddd, MMMM D')}, ${username} ${labelSuffix}`;
cy.wrap(el).find('time.post__time').invoke('attr', 'datetime').then((time) => {
const parsedTime = Cypress.dayjs(time);
const expectedLabel = `At ${parsedTime.format('h:mm A dddd, MMMM D')}, ${username} ${labelSuffix}`;
cy.wrap(el).should('have.attr', 'aria-label', expectedLabel);
});
});

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

@@ -26,7 +26,9 @@ describe('Archived channels', () => {
it('MM-T1721 Archive channel posts menu should have copy link and reply options', () => {
// # Click to add a channel description
cy.findByRoleExtended('button', {name: 'Set header'}).should('be.visible').click();
// Note that it is invisible until the mouse hovers it, which is unfeasible in Cypress
// https://docs.cypress.io/api/commands/hover
cy.findByText('Add a channel header').click({force: true});
// # Add channel header for system message
const header = 'this is a header!';

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

@@ -35,6 +35,9 @@ describe('Bot display name', () => {
});
cy.visit(`/${team.name}/channels/off-topic`);
cy.wait('@resources');
// # Wait for the page to fully load before continuing
cy.get('#sidebar-header-container').should('be.visible').and('have.text', team.display_name);
});
});
});

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

@@ -31,6 +31,8 @@ describe('MM-T4063 Custom status expiry', () => {
const waitingTime = 30; //minutes
let expiresAt = dayjs();
let expiresAtAcceptableValues = [''];
let expiresAtRegexp: RegExp;
const expiryTimeFormat = 'h:mm A';
it('MM-T4063_1 should open status dropdown', () => {
// # Click on the sidebar header to open status dropdown
@@ -77,7 +79,12 @@ describe('MM-T4063 Custom status expiry', () => {
cy.get('#custom_status_modal').should('not.exist');
// # Setting the time at which the custom status should be expired
// # Note that we need to be flexible around accepted values, as this calculation and the server-side one may differ slightly
expiresAt = dayjs().add(waitingTime, 'minute');
expiresAtAcceptableValues = [-1, 0, 1].map((el) =>
expiresAt.add(el, 'minute').format(expiryTimeFormat),
);
expiresAtRegexp = new RegExp(`(${expiresAtAcceptableValues.join('|')})`);
// * Status should be set and the emoji should be visible in the sidebar header
cy.uiGetProfileHeader().
@@ -97,7 +104,7 @@ describe('MM-T4063 Custom status expiry', () => {
cy.get('.status-dropdown-menu .custom_status__row span.emoticon').invoke('attr', 'data-emoticon').should('contain', customStatus.emoji);
// * Correct clear time should be displayed in the status dropdown
cy.get('.status-dropdown-menu .custom_status__expiry time').should('have.text', expiresAt.format(expiryTimeFormat));
cy.get('.status-dropdown-menu .custom_status__expiry time').invoke('text').should('match', expiresAtRegexp);
});
it('MM-T4063_6 custom status should be cleared after duration of set custom status', () => {
@@ -116,7 +123,7 @@ describe('MM-T4063 Custom status expiry', () => {
// * Should show expiry time of status when current status is selected
cy.get('#custom_status_modal .statusSuggestion__content').contains('span', customStatus.text).click();
cy.get('#custom_status_modal .expiry-value').should('have.text', expiresAt.format(expiryTimeFormat));
cy.get('#custom_status_modal .expiry-value').invoke('text').should('match', expiresAtRegexp);
// # Close custom status modal
cy.get('#custom_status_modal .modal-header .close').click();

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

@@ -142,7 +142,7 @@ describe('Verify Accessibility Support in Modals & Dialogs', () => {
});
}
// # Visit the test channel
// # Visit the test channel, and wait for the page to fully load
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Open Add Members Dialog
@@ -160,6 +160,7 @@ describe('Verify Accessibility Support in Modals & Dialogs', () => {
// # Search for a text and then check up and down arrow
cy.findByRole('textbox', {name: 'Search for people or groups'}).
wait(TIMEOUTS.HALF_SEC).
typeWithForce('u').
wait(TIMEOUTS.HALF_SEC).
typeWithForce('{downarrow}{downarrow}{downarrow}{uparrow}');

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

@@ -10,6 +10,8 @@
// Stage: @prod
// Group: @channels @files_and_attachments
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('YouTube Video', () => {
before(() => {
// # Enable Link Previews
@@ -27,10 +29,12 @@ describe('YouTube Video', () => {
it('MM-T2258 YouTube Video play, collapse', () => {
// # Post message
cy.postMessage('https://www.youtube.com/watch?v=gLNmtUEvI5A');
const youtubeUrl = 'https://www.youtube.com/watch?v=gLNmtUEvI5A';
cy.postMessage(youtubeUrl);
cy.uiWaitUntilMessagePostedIncludes(youtubeUrl);
cy.getLastPost().within(() => {
// # Click play button
cy.get('.play-button').click();
cy.get('.play-button', {timeout: TIMEOUTS.TEN_SEC}).click();
// * Video should be loaded in the iframe
cy.get('.video-div > iframe').should('exist');

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

@@ -87,8 +87,7 @@ describe('Integrations', () => {
// # Type "/echo message 3"
cy.uiGetPostTextBox().clear().type(`/echo ${message} 3{enter}`);
// * Verify that post is not shown after 1 second
cy.wait(TIMEOUTS.ONE_SEC);
// * Verify that post is not shown after pressing enter
cy.getLastPost().within(() => {
cy.findByText(message).should('not.exist');
});

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

@@ -84,7 +84,8 @@ describe('Integrations', () => {
loginAndVisitChannel(testUser, testChannelUrl);
// # In a GM use the /invite command to invite a user to a channel you have permission to add them to but place extra white space before the username
cy.postMessage(`/groupmsg @${member1.username} @${member2.username} `);
cy.postMessage(`/groupmsg @${member1.username},@${member2.username} `);
cy.uiGetChannelHeaderButton().contains(member1.username).contains(member2.username);
cy.postMessage(`/invite @${userToInviteGM.username} ~${testChannel.name} `);
// * User added to channel as expected
@@ -133,7 +134,9 @@ describe('Integrations', () => {
loginAndVisitChannel(testUser, testChannelUrl);
// # In a GM Use the /invite command to invite a channel to another channel (e.g., /invite @[channel name])
cy.postMessage(`/groupmsg @${member1.username} @${member2.username} `);
cy.postMessage(`/groupmsg @${member1.username},@${member2.username} `);
cy.uiGetChannelHeaderButton().contains(member1.username).contains(member2.username);
cy.reload(); // Required for Cypress to write in the right channel
cy.postMessage(`/invite @${testChannel.name} `);
// * Error appears: "We couldn't find the user. They may have been deactivated by the System Administrator."
@@ -159,7 +162,9 @@ describe('Integrations', () => {
loginAndVisitChannel(testUser, testChannelUrl);
// # In a GM use the /invite command to invite someone to a channel they're already a member of
cy.postMessage(`/groupmsg @${member1.username} @${member2.username} `);
cy.postMessage(`/groupmsg @${member1.username},@${member2.username} `);
cy.uiGetChannelHeaderButton().contains(member1.username).contains(member2.username);
cy.reload(); // Required for Cypress to write in the right channel
cy.postMessage(`/invite @${userToInvite.username} ~${testChannel.name} `);
// * Error appears: "[username] is already in the channel"

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

@@ -67,6 +67,7 @@ describe('Integrations', () => {
click();
// * Verify that only "Hello World" is posted in off-topic channel
cy.uiWaitUntilMessagePostedIncludes('Hello World');
cy.getLastPostId().then((postId) => {
cy.get(`#postMessageText_${postId}`).should('be.visible').and('have.text', 'Hello World');
});
@@ -103,6 +104,7 @@ describe('Integrations', () => {
click();
// * Verify that both messages are posted in off-topic channel
cy.uiWaitUntilMessagePostedIncludes('Hello World');
cy.getLastPostId().then((postId) => {
cy.get(`#postMessageText_${postId}`).should('be.visible').and('have.text', 'Hello World');
});

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

@@ -11,6 +11,7 @@
// Group: @channels @mark_as_unread
import {markAsUnreadFromPost, switchToChannel} from './helpers';
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Verify unread toast appears after repeated manual marking post as unread', () => {
let firstPost;
@@ -33,7 +34,10 @@ describe('Verify unread toast appears after repeated manual marking post as unre
cy.visit(`/${team.name}/channels/${testChannel.name}`);
switchToChannel(offTopicChannel);
cy.postMessageAs({
// Ensure that the Off-Topic channel has loaded successfully, before posting messages in the other channel
cy.get('#channelHeaderTitle').should('be.visible').and('contain.text', offTopicChannel.display_name);
cy.wait(TIMEOUTS.ONE_SEC).postMessageAs({
sender: otherUser,
message: 'First message',
channelId: testChannel.id,

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

@@ -21,6 +21,9 @@ describe('Message Reply', () => {
cy.apiInitSetup({loginAfter: true}).then(({team, channel}) => {
newChannel = channel;
cy.visit(`/${team.name}/channels/${channel.name}`);
// # Wait for the page to fully load before continuing
cy.get('#sidebar-header-container').should('be.visible').and('have.text', team.display_name);
});
});
@@ -43,9 +46,11 @@ describe('Message Reply', () => {
cy.clickPostCommentIcon(postId);
// # Reply with the attachment
cy.postMessageReplyInRHS('A reply to an older post with attachment');
const replyText = 'A reply to an older post with attachment';
cy.postMessageReplyInRHS(replyText);
// # Get the latest reply post
cy.uiWaitUntilMessagePostedIncludes(replyText);
cy.getLastPostId().then((replyId) => {
// * Verify that the reply is in the channel view with matching text
cy.get(`#post_${replyId}`).within(() => {

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

@@ -41,6 +41,10 @@ describe('Notifications', () => {
// # Login as receiver and visit off-topic channel
cy.apiLogin(receiver);
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// # Wait for the page to fully load before continuing
cy.get('#channelHeaderDropdownButton').should('be.visible').and('have.text', testChannel.display_name);
cy.get(`#sidebarItem_${otherChannel.name}`).click();
cy.get('#sidebarItem_off-topic').click();
});
@@ -284,4 +288,5 @@ function setNotificationSettings(desiredSettings = {first: true, username: true,
// # Navigate to a channel we are NOT going to post to
cy.get(`#sidebarItem_${channelName}`).scrollIntoView().click({force: true});
cy.get('#loadingSpinner').should('not.exist');
}

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

@@ -11,6 +11,7 @@
// Group: @channels @not_cloud @system_console
import {fileSizeToString} from '../../../utils';
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Unsaved Changes', () => {
let defaultMaxFileSize;
@@ -26,7 +27,7 @@ describe('Unsaved Changes', () => {
it('MM-T955 Warning leaving changed page without saving: Leave page, discard changes', () => {
// # Make a change on any page.
cy.visit('/admin_console/environment/file_storage');
cy.findByTestId('FileSettings.MaxFileSizenumber').clear().type('150');
cy.findByTestId('FileSettings.MaxFileSizenumber', {timeout: TIMEOUTS.FIVE_SEC}).clear().type('150');
// # Click a navigation item in left nav.
cy.findByText('Database').click();
@@ -38,7 +39,7 @@ describe('Unsaved Changes', () => {
// * Opens other page, changes discarded.
cy.url().should('include', '/environment/database');
cy.visit('/admin_console/environment/file_storage');
cy.findByTestId('FileSettings.MaxFileSizenumber').should('have.value', fileSizeToString(defaultMaxFileSize).replace('MB', ''));
cy.findByTestId('FileSettings.MaxFileSizenumber', {timeout: TIMEOUTS.FIVE_SEC}).should('have.value', fileSizeToString(defaultMaxFileSize).replace('MB', ''));
});
it('MM-T956 Warning leaving changed page without saving: Cancel leaving page', () => {
@@ -46,7 +47,7 @@ describe('Unsaved Changes', () => {
// # Make a change on any page.
cy.visit('/admin_console/environment/file_storage');
cy.findByTestId('FileSettings.MaxFileSizenumber').clear().type(draftValue);
cy.findByTestId('FileSettings.MaxFileSizenumber', {timeout: TIMEOUTS.FIVE_SEC}).clear().type(draftValue);
// # Click a navigation item in left nav.
cy.findByText('Database').click();
@@ -57,7 +58,7 @@ describe('Unsaved Changes', () => {
// * Stays on current page, changes kept.
cy.url().should('include', '/environment/file_storage');
cy.findByTestId('FileSettings.MaxFileSizenumber').should('have.value', draftValue);
cy.findByTestId('FileSettings.MaxFileSizenumber', {timeout: TIMEOUTS.FIVE_SEC}).should('have.value', draftValue);
});
});

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

@@ -68,6 +68,7 @@ describe('System Console > User Management > Users', () => {
it('MM-T932 Users - Change a user\'s password', () => {
// # Search for the user.
cy.findByPlaceholderText('Search users').type(testUser.email).wait(TIMEOUTS.HALF_SEC);
cy.get('#systemUsersTable-cell-0_emailColumn').should('contain', testUser.email);
// # Open the actions menu.
cy.get('#systemUsersTable-cell-0_actionsColumn').click().wait(TIMEOUTS.HALF_SEC);

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

@@ -156,6 +156,7 @@ describe('User Management', () => {
// # Search for the user.
cy.get('#input_searchTerm').clear().type(user.email, {delay: TIMEOUTS.ONE_HUNDRED_MILLIS}).wait(TIMEOUTS.HALF_SEC);
cy.get('#systemUsersTable-cell-0_emailColumn').should('contain', user.email);
cy.get('#actionMenuButton-systemUsersTable-0').click().wait(TIMEOUTS.HALF_SEC);

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

@@ -185,6 +185,7 @@ describe('User Management', () => {
// # Search for the user.
cy.get('#input_searchTerm').clear().type(gitlabUser.email).wait(TIMEOUTS.HALF_SEC);
cy.get('#systemUsersTable-cell-0_emailColumn').should('contain', gitlabUser.email);
// # Open actions menu.
cy.get('#systemUsersTable-cell-0_actionsColumn').click().wait(TIMEOUTS.HALF_SEC);
@@ -255,6 +256,7 @@ describe('User Management', () => {
// # Search for the user.
cy.get('#input_searchTerm').clear().type(oldEmail).wait(TIMEOUTS.HALF_SEC);
cy.get('#systemUsersTable-cell-0_emailColumn').should('contain', oldEmail);
cy.get('#systemUsersTable-cell-0_actionsColumn').click().wait(TIMEOUTS.HALF_SEC);
cy.findByText('Update email').click().wait(TIMEOUTS.HALF_SEC);

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

@@ -38,6 +38,7 @@ describe('unread_with_bottom_start_toast', () => {
cy.apiCreateChannel(testTeam.id, 'channel-a', 'ChannelA').then(({channel}) => {
cy.apiAddUserToChannel(channel.id, otherUser.id).then(() => {
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
cy.get('#loadingSpinner').should('not.exist'); // The channel should fully load once, before it can mark messages as "new"
cy.uiClickSidebarItem('off-topic');
cy.postMessage('hi');
@@ -73,6 +74,7 @@ describe('unread_with_bottom_start_toast', () => {
cy.apiCreateChannel(testTeam.id, 'channel-b', 'ChannelB').then(({channel}) => {
cy.apiAddUserToChannel(channel.id, otherUser.id).then(() => {
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
cy.get('#loadingSpinner').should('not.exist'); // The channel should fully load once, before it can mark messages as "new"
cy.uiClickSidebarItem('off-topic');
cy.postMessage('hi');
@@ -114,6 +116,10 @@ describe('unread_with_bottom_start_toast', () => {
cy.postMessageAs({sender: otherUser, message: `test message ${index}`, channelId: channel.id}).wait(50);
}
// # Switch channel and back
cy.uiClickSidebarItem('off-topic');
cy.uiClickSidebarItem(channel.name);
cy.wait(TIMEOUTS.ONE_SEC);
// # Scroll to the top to find the oldest message
@@ -123,6 +129,7 @@ describe('unread_with_bottom_start_toast', () => {
// # Mark post as unread
cy.uiClickPostDropdownMenu(postId, 'Mark as Unread');
});
cy.get('div.toast').should('be.visible').contains('30 new messages'); // The toast message should appear right away
// # Visit off-topic channel and switch back to test channel
cy.uiClickSidebarItem('off-topic');

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

@@ -73,7 +73,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
describe('post update dialog', () => {
it('renders description correctly', () => {
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -84,7 +84,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
it('description link navigates to run overview', () => {
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -101,7 +101,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
it('prevents posting an update message with only whitespace', () => {
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -157,7 +157,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
cy.visit(`/${testTeam.name}/channels/${channelName}`);
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -183,7 +183,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
const reminderTime = '1 day';
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get the dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -249,7 +249,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
describe('prevents user from losing changes', () => {
it('cancel, go back and save', () => {
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -279,7 +279,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
it('click overview link, go back and save', () => {
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -310,7 +310,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
it('cancel and discard explicitly', () => {
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -333,7 +333,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
it('click overview link and discard explicitly', () => {
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -364,7 +364,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
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');
cy.uiPostMessageQuickly('/playbook update ');
// # Get the dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -383,7 +383,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
cy.updateStatus(firstMessage);
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get the dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -399,7 +399,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
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');
cy.uiPostMessageQuickly('/playbook update ');
// # Get the dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -418,7 +418,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
cy.updateStatus(firstMessage, '15 minutes');
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get the dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -437,7 +437,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
cy.updateStatus(firstMessage, '90 minutes');
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get the dialog modal.
cy.getStatusUpdateDialog().within(() => {
@@ -456,7 +456,7 @@ describe('channels > rhs > status update', {testIsolation: true}, () => {
cy.updateStatus(firstMessage, '7 days');
// # Run the `/playbook update` slash command.
cy.uiPostMessageQuickly('/playbook update');
cy.uiPostMessageQuickly('/playbook update ');
// # Get the dialog modal.
cy.getStatusUpdateDialog().within(() => {

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

@@ -90,7 +90,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook check 1 1');
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');
@@ -98,7 +98,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('check add', () => {
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkadd 1 new-task');
cy.uiPostMessageQuickly('/playbook checkadd 1 new-task ');
// * Verify the task was added
cy.get('[data-rbd-droppable-id="1"]').contains('new-task');
@@ -106,7 +106,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('check remove', () => {
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkremove 1 1');
cy.uiPostMessageQuickly('/playbook checkremove 1 1 ');
// * Verify the task was added
cy.get('[data-rbd-droppable-id="1"]').contains('Step 2').should('not.exist');
@@ -114,7 +114,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('owner', () => {
// # Run a slash command
cy.uiPostMessageQuickly('/playbook owner');
cy.uiPostMessageQuickly('/playbook owner ');
// * Verify the message.
cy.verifyEphemeralMessage(`@${testUser.username} is the current owner for this playbook run.`);
@@ -123,13 +123,13 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
cy.uiPostMessageQuickly(`/playbook owner @${testUser2.username}`);
// * Verify that the owner was set.
cy.uiPostMessageQuickly('/playbook owner');
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');
cy.uiPostMessageQuickly('/playbook timeline ');
// * Verify the message.
cy.verifyEphemeralMessage(`Timeline for ${playbookRunName}`);
@@ -137,7 +137,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('finish', () => {
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook finish');
cy.uiPostMessageQuickly('/playbook finish ');
// * Verify confirm modal is visible.
cy.get('#interactiveDialogModalLabel').should('exist');
@@ -274,19 +274,19 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('check', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook check 1 1');
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');
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');
cy.uiPostMessageQuickly('/playbook check 0 1 1 ');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Become a participant to interact with this run');
@@ -301,7 +301,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook check 1 1 1');
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);
@@ -316,19 +316,19 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('check add', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook checkadd 1');
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');
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');
cy.uiPostMessageQuickly('/playbook checkadd 0 1 new-task ');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Become a participant to interact with this run');
@@ -343,7 +343,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkadd 1 1 new-task');
cy.uiPostMessageQuickly('/playbook checkadd 1 1 new-task ');
cy.get('#rhsContainer').within(() => {
// * Verify number of runs
@@ -359,19 +359,19 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('check remove', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook checkremove 1 1');
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');
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');
cy.uiPostMessageQuickly('/playbook checkremove 0 1 0 ');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Become a participant to interact with this run');
@@ -386,7 +386,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook checkremove 1 1 1');
cy.uiPostMessageQuickly('/playbook checkremove 1 1 1 ');
cy.get('#rhsContainer').within(() => {
// * Verify number of runs
@@ -402,19 +402,19 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('owner', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook owner');
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');
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');
cy.uiPostMessageQuickly('/playbook owner 0 ');
// * Verify the message.
cy.verifyEphemeralMessage(`@${testUser.username} is the current owner for this playbook run.`);
@@ -429,34 +429,34 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
cy.findByTestId('post_textbox').clear();
// # Run a slash command on a run with view access
cy.uiPostMessageQuickly(`/playbook owner 0 @${testUser2.username}`);
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}`);
cy.uiPostMessageQuickly(`/playbook owner 1 @${testUser2.username} `);
// * Verify that the owner was set.
cy.uiPostMessageQuickly('/playbook owner 1');
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');
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');
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');
cy.uiPostMessageQuickly('/playbook finish 0 ');
// * Verify the message.
cy.verifyEphemeralMessage(`userID ${testUser2.id} is not an admin or channel member`);
@@ -479,7 +479,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
});
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook finish 1');
cy.uiPostMessageQuickly('/playbook finish 1 ');
// * Verify confirm modal is visible.
cy.get('#interactiveDialogModalLabel').should('exist');
@@ -493,19 +493,19 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('timeline', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook timeline');
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');
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');
cy.uiPostMessageQuickly('/playbook timeline 0 ');
// * Verify the message.
cy.verifyEphemeralMessage(`Timeline for ${playbookRuns[1].name}`);
@@ -513,13 +513,13 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
it('update', () => {
// # Run a slash command with not enough parameters
cy.uiPostMessageQuickly('/playbook update');
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');
cy.uiPostMessageQuickly('/playbook update 2 ');
// * Verify the expected error message.
cy.verifyEphemeralMessage('Invalid run number');
@@ -534,7 +534,7 @@ describe('channels > slash command > owner', {testIsolation: true}, () => {
cy.findByTestId('post_textbox').clear();
// # Run a slash command with correct parameters
cy.uiPostMessageQuickly('/playbook update 1');
cy.uiPostMessageQuickly('/playbook update 1 ');
// # Get dialog modal.
cy.getStatusUpdateDialog().within(() => {

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

@@ -85,6 +85,7 @@ describe('channels > slash command > test', {testIsolation: true}, () => {
EnableTesting: true,
},
});
cy.apiReloadConfig();
});
beforeEach(() => {
@@ -132,6 +133,7 @@ describe('channels > slash command > test', {testIsolation: true}, () => {
EnableTesting: false,
},
});
cy.apiReloadConfig();
});
beforeEach(() => {
@@ -178,6 +180,7 @@ describe('channels > slash command > test', {testIsolation: true}, () => {
EnableTesting: true,
},
});
cy.apiReloadConfig();
});
beforeEach(() => {

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

@@ -175,6 +175,7 @@ describe('playbooks > list', {testIsolation: true}, () => {
// # 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.