Move /e2e -> /e2e-tests
Этот коммит содержится в:
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @interactive_dialog
|
||||
|
||||
/**
|
||||
* Note: This test requires webhook server running. Initiate `npm run start:webhook` to start.
|
||||
*/
|
||||
|
||||
const webhookUtils = require('../../../../utils/webhook_utils');
|
||||
|
||||
let createdCommand;
|
||||
let simpleDialog;
|
||||
|
||||
describe('Interactive Dialog', () => {
|
||||
before(() => {
|
||||
// # Ensure that teammate name display setting is set to default 'username'
|
||||
cy.apiSaveTeammateNameDisplayPreference('username');
|
||||
|
||||
cy.requireWebhookServer();
|
||||
|
||||
// # Create new team and create command on it
|
||||
cy.apiCreateTeam('test-team', 'Test Team').then(({team}) => {
|
||||
cy.visit(`/${team.name}`);
|
||||
|
||||
const webhookBaseUrl = Cypress.env().webhookBaseUrl;
|
||||
|
||||
const command = {
|
||||
auto_complete: false,
|
||||
description: 'Test for boolean dialog',
|
||||
display_name: 'Simple Dialog with boolean element',
|
||||
icon_url: '',
|
||||
method: 'P',
|
||||
team_id: team.id,
|
||||
trigger: 'boolean_dialog',
|
||||
url: `${webhookBaseUrl}/boolean_dialog_request`,
|
||||
username: '',
|
||||
};
|
||||
|
||||
cy.apiCreateCommand(command).then(({data}) => {
|
||||
createdCommand = data;
|
||||
simpleDialog = webhookUtils.getBooleanDialog(createdCommand.id, webhookBaseUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2502 - Boolean element check', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible').within(() => {
|
||||
// * Verify that the header of modal contains icon URL, title and close button
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.get('#interactiveDialogIconUrl').should('be.visible').and('have.attr', 'src', simpleDialog.dialog.icon_url);
|
||||
cy.get('#interactiveDialogModalLabel').should('be.visible').and('have.text', simpleDialog.dialog.title);
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').and('contain', '×').and('contain', 'Close');
|
||||
});
|
||||
|
||||
// * Verify that the body contains the boolean element
|
||||
cy.get('.modal-body').should('be.visible').children().should('have.length', 1).each(($elForm, index) => {
|
||||
const element = simpleDialog.dialog.elements[index];
|
||||
|
||||
cy.wrap($elForm).find('label.control-label').scrollIntoView().should('be.visible').and('have.text', `${element.display_name} ${element.optional ? '(optional)' : '*'}`);
|
||||
|
||||
expect(element.name).to.equal('boolean_input');
|
||||
|
||||
cy.wrap($elForm).find('.checkbox').should('be.visible').within(() => {
|
||||
cy.get('#boolean_input').
|
||||
should('be.visible').
|
||||
and('be.checked');
|
||||
|
||||
cy.get('span').should('have.text', element.placeholder);
|
||||
});
|
||||
|
||||
if (element.help_text) {
|
||||
cy.wrap($elForm).find('.help-text').should('be.visible').and('have.text', element.help_text);
|
||||
}
|
||||
});
|
||||
|
||||
// * Verify that the footer contains cancel and submit buttons
|
||||
cy.get('.modal-footer').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('#interactiveDialogCancel').should('be.visible').and('have.text', 'Cancel');
|
||||
cy.wrap($elForm).find('#interactiveDialogSubmit').should('be.visible').and('have.text', simpleDialog.dialog.submit_label);
|
||||
});
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function closeInteractiveDialog() {
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').click();
|
||||
});
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Group: @channels @interactive_dialog @plugin
|
||||
|
||||
// If the contents of the interactive dialog from the demo plugin change, please update the demoPluginDialogElements object.
|
||||
|
||||
import {demoPlugin} from '../../../utils/plugins';
|
||||
|
||||
describe('Interactive Dialogs', () => {
|
||||
let testTeam;
|
||||
let testChannel;
|
||||
|
||||
// # The format of the elements in the interactive dialog from the demo plugin:
|
||||
const demoPluginDialogElements = [
|
||||
{
|
||||
display_name: 'Display Name',
|
||||
name: 'realname',
|
||||
type: 'text',
|
||||
default: 'default text',
|
||||
placeholder: 'placeholder',
|
||||
help_text: 'This a regular input in an interactive dialog triggered by a test integration.',
|
||||
}, {
|
||||
display_name: 'Email',
|
||||
name: 'someemail',
|
||||
type: 'text',
|
||||
subtype: 'email',
|
||||
placeholder: 'placeholder@bladekick.com',
|
||||
help_text: 'This a regular email input in an interactive dialog triggered by a test integration.',
|
||||
}, {
|
||||
display_name: 'Password',
|
||||
name: 'somepassword',
|
||||
type: 'text',
|
||||
subtype: 'password',
|
||||
placeholder: 'Password',
|
||||
help_text: 'This a password input in an interactive dialog triggered by a test integration.',
|
||||
}, {
|
||||
display_name: 'Number',
|
||||
name: 'somenumber',
|
||||
type: 'text',
|
||||
subtype: 'number',
|
||||
}, {
|
||||
display_name: 'Display Name Long Text Area',
|
||||
name: 'realnametextarea',
|
||||
type: 'textarea',
|
||||
placeholder: 'placeholder',
|
||||
optional: true,
|
||||
min_length: 5,
|
||||
max_length: 100,
|
||||
}, {
|
||||
display_name: 'User Selector',
|
||||
name: 'someuserselector',
|
||||
type: 'select',
|
||||
placeholder: 'Select a user...',
|
||||
help_text: 'Choose a user from the list.',
|
||||
optional: true,
|
||||
min_length: 5,
|
||||
max_length: 100,
|
||||
data_source: 'users',
|
||||
}, {
|
||||
display_name: 'Channel Selector',
|
||||
name: 'somechannelselector',
|
||||
type: 'select',
|
||||
placeholder: 'Select a channel...',
|
||||
help_text: 'Choose a channel from the list.',
|
||||
optional: true,
|
||||
min_length: 5,
|
||||
max_length: 100,
|
||||
data_source: 'channels',
|
||||
}, {
|
||||
display_name: 'Option Selector',
|
||||
name: 'someoptionselector',
|
||||
type: 'select',
|
||||
placeholder: 'Select an option...',
|
||||
help_text: 'Choose an option from the list.',
|
||||
options: [{
|
||||
text: 'Option1',
|
||||
value: 'opt1',
|
||||
}, {
|
||||
text: 'Option2',
|
||||
value: 'opt2',
|
||||
}, {
|
||||
text: 'Option3',
|
||||
value: 'opt3',
|
||||
}],
|
||||
}, {
|
||||
display_name: 'Option Selector with default',
|
||||
name: 'someoptionselector2',
|
||||
type: 'select',
|
||||
default: 'opt2',
|
||||
placeholder: 'Select an option...',
|
||||
help_text: 'Choose an option from the list.',
|
||||
options: [{
|
||||
text: 'Option1',
|
||||
value: 'opt1',
|
||||
}, {
|
||||
text: 'Option2',
|
||||
value: 'opt2',
|
||||
}, {
|
||||
text: 'Option3',
|
||||
value: 'opt3',
|
||||
}],
|
||||
}, {
|
||||
display_name: 'Boolean Selector',
|
||||
name: 'someboolean',
|
||||
type: 'bool',
|
||||
placeholder: 'Agree to the terms of service',
|
||||
help_text: 'You must agree to the terms of service to proceed.',
|
||||
}, {
|
||||
display_name: 'Boolean Selector',
|
||||
name: 'someboolean_optional',
|
||||
type: 'bool',
|
||||
placeholder: 'Sign up for monthly emails?',
|
||||
help_text: "It's up to you if you want to get monthly emails.",
|
||||
optional: true,
|
||||
}, {
|
||||
display_name: 'Boolean Selector (default true)',
|
||||
name: 'someboolean_default_true',
|
||||
type: 'bool',
|
||||
placeholder: 'Enable secure login',
|
||||
help_text: 'You must enable secure login to proceed.',
|
||||
default: 'true',
|
||||
}, {
|
||||
display_name: 'Boolean Selector (default true)',
|
||||
name: 'someboolean_default_true_optional',
|
||||
type: 'bool',
|
||||
placeholder: 'Enable painfully secure login',
|
||||
help_text: 'You may optionally enable painfully secure login.',
|
||||
default: 'true',
|
||||
optional: true,
|
||||
}, {
|
||||
display_name: 'Boolean Selector (default false)',
|
||||
name: 'someboolean_default_false',
|
||||
type: 'bool',
|
||||
placeholder: 'Agree to the annoying terms of service',
|
||||
help_text: 'You must also agree to the annoying terms of service to proceed.',
|
||||
default: 'false',
|
||||
}, {
|
||||
display_name: 'Boolean Selector (default false)',
|
||||
name: 'someboolean_default_false_optional',
|
||||
type: 'bool',
|
||||
placeholder: 'Throw-away account',
|
||||
help_text: 'A throw-away account will be deleted after 24 hours.',
|
||||
default: 'false',
|
||||
optional: true,
|
||||
}, {
|
||||
display_name: 'Radio Option Selector',
|
||||
name: 'someradiooptionselector',
|
||||
type: 'radio',
|
||||
help_text: 'Choose an option from the list.',
|
||||
options: [{
|
||||
text: 'Option1',
|
||||
value: 'opt1',
|
||||
}, {
|
||||
text: 'Option2',
|
||||
value: 'opt2',
|
||||
}, {
|
||||
text: 'Option3',
|
||||
value: 'opt3',
|
||||
}],
|
||||
},
|
||||
];
|
||||
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.shouldHavePluginUploadEnabled();
|
||||
|
||||
// # Set plugin settings
|
||||
const newSettings = {
|
||||
PluginSettings: {
|
||||
Enable: true,
|
||||
},
|
||||
};
|
||||
cy.apiUpdateConfig(newSettings);
|
||||
|
||||
cy.apiInitSetup().then(({team, channel}) => {
|
||||
testTeam = team;
|
||||
testChannel = channel;
|
||||
|
||||
// # Install demo plugin by file
|
||||
cy.apiUploadAndEnablePlugin(demoPlugin);
|
||||
|
||||
// # Visit the test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2503 Boolean value check', () => {
|
||||
// # Post the /dialog slash command message
|
||||
cy.uiGetPostTextBox().type('/dialog {enter}');
|
||||
|
||||
// * Check that the interactive dialog modal from the plugin opens up
|
||||
cy.get('#interactiveDialogModal').should('be.visible').within(() => {
|
||||
// * Verify that the body is visible
|
||||
cy.get('.modal-body').should('be.visible').children().each(($elForm, index) => {
|
||||
const element = demoPluginDialogElements[index];
|
||||
|
||||
// * Verify that when the element comes into view the proper display name is showing
|
||||
cy.wrap($elForm).find('label.control-label').scrollIntoView().should('be.visible').and('have.text', `${element.display_name} ${element.optional ? '(optional)' : '*'}`);
|
||||
|
||||
if (element.name.includes('someboolean')) {
|
||||
// * Verify that the checkbox for a boolean element is visible
|
||||
cy.wrap($elForm).find('.checkbox').should('be.visible').within(() => {
|
||||
// * Verify that if the element default is true, it should be checked, and vice versa.
|
||||
let checked = true;
|
||||
if (element.default === 'true') {
|
||||
cy.get(`#${element.name}`).
|
||||
should('be.visible').
|
||||
and('be.checked');
|
||||
} else {
|
||||
cy.get(`#${element.name}`).
|
||||
should('be.visible').
|
||||
not('be.checked');
|
||||
checked = false;
|
||||
}
|
||||
|
||||
// * Verify that the checkbox has the proper text.
|
||||
cy.get('span').should('have.text', element.placeholder);
|
||||
|
||||
// # Click on the checkbox.
|
||||
if (checked === false) {
|
||||
cy.get(`#${element.name}`).check();
|
||||
}
|
||||
});
|
||||
} else if (element.name === 'someemail') {
|
||||
cy.get(`#${element.name}`).scrollIntoView().clear().type('test@test.com');
|
||||
} else if (element.name === 'somepassword') {
|
||||
cy.get(`#${element.name}`).scrollIntoView().clear().type('test');
|
||||
} else if (element.name === 'somenumber') {
|
||||
cy.get(`#${element.name}`).scrollIntoView().clear().type('42');
|
||||
} else if (element.name === 'someoptionselector') {
|
||||
cy.wrap($elForm).find('input').click();
|
||||
cy.wrap($elForm).find('#suggestionList').scrollIntoView().should('be.visible').click();
|
||||
} else if (element.name === 'someradiooptionselector') {
|
||||
cy.wrap($elForm).find('input').first().click();
|
||||
}
|
||||
});
|
||||
|
||||
// # Submit the form of the interactive dialog.
|
||||
cy.intercept('/api/v4/actions/dialogs/submit').as('submitAction');
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
});
|
||||
|
||||
// * The interactive dialog should not be visible anymore.
|
||||
cy.get('#interactiveDialogModal').not('be.visible');
|
||||
|
||||
// * Verify that submitted values are boolean and not strings.
|
||||
cy.wait('@submitAction').should('include.all.keys', ['request', 'response']).then((result) => {
|
||||
const boolQuestions = Object.entries(result.request.body.submission).filter((element) => element[0].includes('someboolean'));
|
||||
for (let i = 0; i < boolQuestions.length; i++) {
|
||||
assert.isBoolean(boolQuestions[i][1]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,303 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @interactive_dialog
|
||||
|
||||
/**
|
||||
* Note: This test requires webhook server running. Initiate `npm run start:webhook` to start.
|
||||
*/
|
||||
|
||||
const webhookUtils = require('../../../../utils/webhook_utils');
|
||||
|
||||
describe('Interactive Dialog', () => {
|
||||
const inputTypes = {
|
||||
realname: 'input',
|
||||
someemail: 'email',
|
||||
somenumber: 'number',
|
||||
somepassword: 'password',
|
||||
};
|
||||
|
||||
const optionsLength = {
|
||||
someuserselector: 25, // default number of users in autocomplete
|
||||
somechannelselector: 2, // town-square and off-topic for new team
|
||||
someoptionselector: 3, // number of defined basic options
|
||||
someradiooptions: 2, // number of defined basic options
|
||||
};
|
||||
|
||||
let createdCommand;
|
||||
let fullDialog;
|
||||
|
||||
before(() => {
|
||||
cy.requireWebhookServer();
|
||||
|
||||
// # Ensure that teammate name display setting is set to default 'username'
|
||||
cy.apiSaveTeammateNameDisplayPreference('username');
|
||||
|
||||
// # Create new team and create command on it
|
||||
cy.apiCreateTeam('test-team', 'Test Team').then(({team}) => {
|
||||
cy.visit(`/${team.name}`);
|
||||
|
||||
const webhookBaseUrl = Cypress.env().webhookBaseUrl;
|
||||
|
||||
const command = {
|
||||
auto_complete: false,
|
||||
description: 'Test for dialog',
|
||||
display_name: 'Dialog',
|
||||
icon_url: '',
|
||||
method: 'P',
|
||||
team_id: team.id,
|
||||
trigger: 'dialog',
|
||||
url: `${webhookBaseUrl}/dialog_request`,
|
||||
username: '',
|
||||
};
|
||||
|
||||
cy.apiCreateCommand(command).then(({data}) => {
|
||||
createdCommand = data;
|
||||
fullDialog = webhookUtils.getFullDialog(createdCommand.id, webhookBaseUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// # Reload current page after each test to close any dialogs left open
|
||||
cy.reload();
|
||||
});
|
||||
|
||||
it('MM-T2491 - UI check', () => {
|
||||
// # Post a slash command
|
||||
cy.get('#postListContent').should('be.visible');
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible').within(() => {
|
||||
// * Verify that the header of modal contains icon URL, title and close button
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.get('#interactiveDialogIconUrl').should('be.visible').and('have.attr', 'src', fullDialog.dialog.icon_url);
|
||||
cy.get('#interactiveDialogModalLabel').should('be.visible').and('have.text', fullDialog.dialog.title);
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').and('contain', '×').and('contain', 'Close');
|
||||
|
||||
cy.get('#interactiveDialogModalLabel').should('be.visible').and('have.text', fullDialog.dialog.title);
|
||||
});
|
||||
|
||||
// * Verify that the body contains all the elements
|
||||
cy.get('.modal-body').should('be.visible').children().each(($elForm, index) => {
|
||||
const element = fullDialog.dialog.elements[index];
|
||||
|
||||
cy.wrap($elForm).find('label.control-label').scrollIntoView().should('exist').and('have.text', `${element.display_name} ${element.optional ? '(optional)' : '*'}`);
|
||||
|
||||
if (['someuserselector', 'somechannelselector', 'someoptionselector'].includes(element.name)) {
|
||||
cy.wrap($elForm).find('input').should('be.visible').and('have.attr', 'autocomplete', 'off').and('have.attr', 'placeholder', element.placeholder);
|
||||
|
||||
// * Verify that the suggestion list or autocomplete open up on click of input element
|
||||
cy.wrap($elForm).find('#suggestionList').should('not.exist');
|
||||
cy.wrap($elForm).find('input').click();
|
||||
cy.wrap($elForm).find('#suggestionList').scrollIntoView().should('be.visible');
|
||||
|
||||
// # Click field label to close any opened drop-downs
|
||||
cy.wrap($elForm).find('label.control-label').scrollIntoView().click();
|
||||
} else if (element.name === 'someradiooptions') {
|
||||
cy.wrap($elForm).find('input').should('be.visible').and('have.length', optionsLength[element.name]);
|
||||
|
||||
// * Verify that no option is selected by default
|
||||
cy.wrap($elForm).find('input').each(($elInput) => {
|
||||
cy.wrap($elInput).should('not.be.checked');
|
||||
});
|
||||
} else if (element.name === 'boolean_input') {
|
||||
cy.wrap($elForm).find('.checkbox').should('be.visible').within(() => {
|
||||
cy.get('#boolean_input').
|
||||
should('be.visible').
|
||||
and('be.checked');
|
||||
|
||||
cy.get('span').should('have.text', element.placeholder);
|
||||
});
|
||||
} else {
|
||||
cy.wrap($elForm).find(`#${element.name}`).should('be.visible').and('have.value', element.default).and('have.attr', 'placeholder', element.placeholder);
|
||||
}
|
||||
|
||||
// * Verify that input element are given with the correct type of "input", "email", "number" and "password".
|
||||
// * To take advantage of supported built-in validation.
|
||||
if (inputTypes[element.name]) {
|
||||
cy.wrap($elForm).find(`#${element.name}`).should('have.attr', 'type', inputTypes[element.name]);
|
||||
}
|
||||
|
||||
if (element.help_text) {
|
||||
cy.wrap($elForm).find('.help-text').should('exist').and('have.text', element.help_text);
|
||||
}
|
||||
});
|
||||
|
||||
// * Verify that the footer contains cancel and submit buttons
|
||||
cy.get('.modal-footer').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('#interactiveDialogCancel').should('be.visible').and('have.text', 'Cancel');
|
||||
cy.wrap($elForm).find('#interactiveDialogSubmit').should('be.visible').and('have.text', fullDialog.dialog.submit_label);
|
||||
});
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2492 - Cancel button works', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Click cancel from the modal
|
||||
cy.get('#interactiveDialogCancel').click();
|
||||
|
||||
// * Verify that the interactive dialog modal is closed
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T2493 - "X" closes the dialog', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Click "X" button from the modal
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').click();
|
||||
});
|
||||
|
||||
// * Verify that the interactive dialog modal is closed
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T2494 - Correct error messages displayed if empty form is submitted', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Click submit button from the modal
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
|
||||
// * Verify that the interactive dialog modal is still open
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// * Verify that not optional element without text value shows an error and vice versa
|
||||
cy.get('.modal-body').should('be.visible').children().each(($elForm, index) => {
|
||||
const element = fullDialog.dialog.elements[index];
|
||||
|
||||
if (!element.optional && !element.default) {
|
||||
cy.wrap($elForm).find('div.error-text').scrollIntoView().should('be.visible').and('have.text', 'This field is required.').and('have.css', 'color', 'rgb(210, 75, 78)');
|
||||
} else {
|
||||
cy.wrap($elForm).find('div.error-text').should('not.exist');
|
||||
}
|
||||
});
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
|
||||
it('MM-T2495_1 - Email validation for invalid input', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Enter invalid and valid email
|
||||
// * Verify that error is: shown for invalid email and not shown for valid email.
|
||||
const invalidEmail = 'invalid-email';
|
||||
cy.get('#someemail').scrollIntoView().clear().type(invalidEmail);
|
||||
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
|
||||
cy.get('input:invalid').should('have.length', 1);
|
||||
cy.get('#someemail').then(($input) => {
|
||||
expect($input[0].validationMessage).to.eq(`Please include an '@' in the email address. '${invalidEmail}' is missing an '@'.`);
|
||||
});
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
|
||||
it('MM-T2495_2 - Email validation for valid input', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Enter valid email
|
||||
// * Verify that error is not shown for valid email.
|
||||
const validEmail = 'test@mattermost.com';
|
||||
cy.get('#someemail').scrollIntoView().clear().type(validEmail);
|
||||
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
|
||||
cy.get('input:invalid').should('have.length', 0);
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
|
||||
it('MM-T2496_1 - Number validation for invalid input', () => {
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Enter invalid number
|
||||
// * Verify that error is shown for invalid number.
|
||||
const invalidNumber = 'invalid-number';
|
||||
cy.get('#somenumber').scrollIntoView().clear().type(invalidNumber);
|
||||
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
|
||||
cy.get('.modal-body').should('be.visible').children().eq(2).within(($elForm) => {
|
||||
cy.wrap($elForm).find('div.error-text').should('be.visible').and('have.text', 'This field is required.').and('have.css', 'color', 'rgb(210, 75, 78)');
|
||||
});
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
|
||||
it('MM-T2496_2 - Number validation for valid input', () => {
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Enter a valid number
|
||||
// * Verify that error is not shown for valid number.
|
||||
const validNumber = 12;
|
||||
cy.get('#somenumber').scrollIntoView().clear().type(validNumber);
|
||||
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
|
||||
cy.get('.modal-body').should('be.visible').children().eq(2).within(($elForm) => {
|
||||
cy.wrap($elForm).find('div.error-text').should('not.exist');
|
||||
});
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
|
||||
it('MM-T2501 - Password element check', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// * Verify that the password text area is visible
|
||||
cy.get('#somepassword').should('be.visible');
|
||||
|
||||
// * Verify that the password is masked on enter of text
|
||||
cy.get('#somepassword').should('have.attr', 'type', 'password');
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
});
|
||||
|
||||
function closeInteractiveDialog() {
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').click();
|
||||
});
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @interactive_dialog
|
||||
|
||||
/**
|
||||
* Note: This test requires webhook server running. Initiate `npm run start:webhook` to start.
|
||||
*/
|
||||
|
||||
const webhookUtils = require('../../../../utils/webhook_utils');
|
||||
|
||||
let createdCommand;
|
||||
let userAndChannelDialog;
|
||||
|
||||
describe('Interactive Dialog', () => {
|
||||
before(() => {
|
||||
cy.requireWebhookServer();
|
||||
|
||||
// # Ensure that teammate name display setting is set to default 'username'
|
||||
cy.apiSaveTeammateNameDisplayPreference('username');
|
||||
|
||||
// # Create new team and create command on it
|
||||
cy.apiCreateTeam('test-team', 'Test Team').then(({team}) => {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
cy.apiCreateChannel(team.id, `channel-${i}`, `Channel ${i}`);
|
||||
}
|
||||
|
||||
cy.visit(`/${team.name}`);
|
||||
|
||||
const webhookBaseUrl = Cypress.env().webhookBaseUrl;
|
||||
|
||||
const command = {
|
||||
auto_complete: false,
|
||||
description: 'Test for user and channel dialog',
|
||||
display_name: 'Dialog with user and channel',
|
||||
icon_url: '',
|
||||
method: 'P',
|
||||
team_id: team.id,
|
||||
trigger: 'user_and_channel_dialog',
|
||||
url: `${webhookBaseUrl}/user_and_channel_dialog_request`,
|
||||
username: '',
|
||||
};
|
||||
|
||||
cy.apiCreateCommand(command).then(({data}) => {
|
||||
createdCommand = data;
|
||||
userAndChannelDialog = webhookUtils.getUserAndChannelDialog(createdCommand.id, webhookBaseUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2498 - Individual "User" and "Channel" screens are scrollable', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible').within(() => {
|
||||
// * Verify that the header of modal contains icon URL, title and close button
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.get('#interactiveDialogIconUrl').should('be.visible').and('have.attr', 'src', userAndChannelDialog.dialog.icon_url);
|
||||
cy.get('#interactiveDialogModalLabel').should('be.visible').and('have.text', userAndChannelDialog.dialog.title);
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').and('contain', '×').and('contain', 'Close');
|
||||
});
|
||||
|
||||
// * Verify that the body contains the both elements
|
||||
cy.get('.modal-body').should('be.visible').children().should('have.length', 2).each(($elForm, index) => {
|
||||
const element = userAndChannelDialog.dialog.elements[index];
|
||||
|
||||
cy.wrap($elForm).find('label.control-label').scrollIntoView().should('be.visible').and('have.text', `${element.display_name} ${element.optional ? '(optional)' : '*'}`);
|
||||
|
||||
cy.wrap($elForm).find('input').should('be.visible').and('have.attr', 'autocomplete', 'off').and('have.attr', 'placeholder', element.placeholder);
|
||||
|
||||
// * Verify that the suggestion list or autocomplete open up on click of input element
|
||||
cy.wrap($elForm).find('#suggestionList').should('not.exist');
|
||||
cy.wrap($elForm).find('input').click();
|
||||
cy.wrap($elForm).find('#suggestionList').scrollIntoView().should('be.visible').children();
|
||||
|
||||
if (index === 0) {
|
||||
expect(element.name).to.equal('someuserselector');
|
||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||
cy.wrap($elForm).find('.form-control').type('{downarrow}'.repeat(10));
|
||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('not.be.visible');
|
||||
cy.wrap($elForm).find('.form-control').type('{uparrow}'.repeat(10));
|
||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||
} else if (index === 1) {
|
||||
expect(element.name).to.equal('somechannelselector');
|
||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||
cy.wrap($elForm).find('.form-control').type('{downarrow}'.repeat(10));
|
||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('not.be.visible');
|
||||
cy.wrap($elForm).find('.form-control').type('{uparrow}'.repeat(10));
|
||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||
}
|
||||
|
||||
// # Select one element to close the dropdown
|
||||
cy.wrap($elForm).find('.suggestion-list__item').first().click();
|
||||
|
||||
if (element.help_text) {
|
||||
cy.wrap($elForm).find('.help-text').should('be.visible').and('have.text', element.help_text);
|
||||
}
|
||||
});
|
||||
|
||||
// * Verify that the footer contains cancel and submit buttons
|
||||
cy.get('.modal-footer').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('#interactiveDialogCancel').should('be.visible').and('have.text', 'Cancel');
|
||||
cy.wrap($elForm).find('#interactiveDialogSubmit').should('be.visible').and('have.text', userAndChannelDialog.dialog.submit_label);
|
||||
});
|
||||
|
||||
// # Close interactive dialog
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').click();
|
||||
});
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @not_cloud @interactive_dialog
|
||||
|
||||
/**
|
||||
* Note: This test requires webhook server running. Initiate `npm run start:webhook` to start.
|
||||
*/
|
||||
|
||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
|
||||
const webhookUtils = require('../../../../utils/webhook_utils');
|
||||
|
||||
let createdCommand;
|
||||
let simpleDialog;
|
||||
|
||||
describe('Interactive Dialog without element', () => {
|
||||
before(() => {
|
||||
cy.shouldNotRunOnCloudEdition();
|
||||
cy.requireWebhookServer();
|
||||
|
||||
// # Ensure that teammate name display setting is set to default 'username'
|
||||
cy.apiSaveTeammateNameDisplayPreference('username');
|
||||
|
||||
// # Create new team and create command on it
|
||||
cy.apiCreateTeam('test-team', 'Test Team').then(({team}) => {
|
||||
cy.visit(`/${team.name}`);
|
||||
|
||||
const webhookBaseUrl = Cypress.env().webhookBaseUrl;
|
||||
|
||||
const command = {
|
||||
auto_complete: false,
|
||||
description: 'Test for simple dialog - no element',
|
||||
display_name: 'Simple Dialog without element',
|
||||
icon_url: '',
|
||||
method: 'P',
|
||||
team_id: team.id,
|
||||
trigger: 'simple_dialog',
|
||||
url: `${webhookBaseUrl}/simple_dialog_request`,
|
||||
username: '',
|
||||
};
|
||||
|
||||
cy.apiCreateCommand(command).then(({data}) => {
|
||||
createdCommand = data;
|
||||
simpleDialog = webhookUtils.getSimpleDialog(createdCommand.id, webhookBaseUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2500_1 UI check', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible').within(() => {
|
||||
// * Verify that the header of modal contains icon URL, title and close button
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.get('#interactiveDialogIconUrl').should('be.visible').and('have.attr', 'src', simpleDialog.dialog.icon_url);
|
||||
cy.get('#interactiveDialogModalLabel').should('be.visible').and('have.text', simpleDialog.dialog.title);
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').and('contain', '×').and('contain', 'Close');
|
||||
});
|
||||
|
||||
// * Verify that the body is not present
|
||||
cy.get('.modal-body').should('not.exist');
|
||||
|
||||
// * Verify that the footer contains cancel and submit buttons
|
||||
cy.get('.modal-footer').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('#interactiveDialogCancel').should('be.visible').and('have.text', 'Cancel');
|
||||
cy.wrap($elForm).find('#interactiveDialogSubmit').should('be.visible').and('have.text', simpleDialog.dialog.submit_label);
|
||||
});
|
||||
|
||||
closeInteractiveDialog();
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T2500_2 "X" closes the dialog', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Click "X" button from the modal
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').click().wait(TIMEOUTS.FIVE_SEC);
|
||||
});
|
||||
|
||||
// * Verify that the interactive dialog modal is closed
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
|
||||
// * Verify that the last post states that the dialog is cancelled
|
||||
cy.getLastPost().should('contain', 'Dialog cancelled');
|
||||
});
|
||||
|
||||
it('MM-T2500_3 Cancel button works', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Click cancel from the modal
|
||||
cy.get('#interactiveDialogCancel').click().wait(TIMEOUTS.FIVE_SEC);
|
||||
|
||||
// * Verify that the interactive dialog modal is closed
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
|
||||
// * Verify that the last post states that the dialog is cancelled
|
||||
cy.getLastPost().should('contain', 'Dialog cancelled');
|
||||
});
|
||||
|
||||
it('MM-T2500_4 Submit button works', () => {
|
||||
// # Post a slash command
|
||||
cy.postMessage(`/${createdCommand.trigger} `);
|
||||
|
||||
// * Verify that the interactive dialog modal open up
|
||||
cy.get('#interactiveDialogModal').should('be.visible');
|
||||
|
||||
// # Click submit from the modal
|
||||
cy.get('#interactiveDialogSubmit').click();
|
||||
|
||||
// * Verify that the interactive dialog modal is closed
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
|
||||
// * Verify that the last post states that the dialog is submitted
|
||||
cy.getLastPost().should('contain', 'Dialog submitted');
|
||||
});
|
||||
});
|
||||
|
||||
function closeInteractiveDialog() {
|
||||
cy.get('.modal-header').should('be.visible').within(($elForm) => {
|
||||
cy.wrap($elForm).find('button.close').should('be.visible').click();
|
||||
});
|
||||
cy.get('#interactiveDialogModal').should('not.exist');
|
||||
}
|
||||
Ссылка в новой задаче
Block a user