diff --git a/cypress/e2e/ui/Services/Requests/service_requests.cy.js b/cypress/e2e/ui/Services/Requests/service_requests.cy.js new file mode 100644 index 00000000000..de69239a3d7 --- /dev/null +++ b/cypress/e2e/ui/Services/Requests/service_requests.cy.js @@ -0,0 +1,416 @@ +/* eslint-disable no-undef */ +import { + LABEL_CONFIG_KEYS, + FIELD_CONFIG_KEYS, + FIELD_TYPES, + BUTTON_CONFIG_KEYS, +} from '../../../../support/commands/constants/command_constants'; + +// Menu options +const SERVICES_MENU_OPTION = 'Services'; +const REQUESTS_MENU_OPTION = 'Requests'; + +// Field labels +const FORM_HEADER = 'Requests'; +const REQUESTER_LABEL = 'Requester'; +const APPROVAL_STATE_HEADER = 'Approval State'; +const TYPE_LABEL = 'Type'; +const REQUEST_DATE_LABEL = 'Request Date'; +const REASON_LABEL = 'Reason'; + +// Field values +const SELECT_OPTION_ALL = 'all'; +const TYPE_VM_RECONFIGURE = 'vm_reconfigure'; +const REQUEST_DATE_LAST_7_DAYS = '7'; +const REQUEST_DATE_LAST_30_DAYS = '30'; + +// Checkbox labels +const PENDING_APPROVAL_LABEL = 'Pending Approval'; +const APPROVED_LABEL = 'Approved'; +const DENIED_LABEL = 'Denied'; + +// Button texts +const APPLY_BUTTON_TEXT = 'Apply'; +const RESET_BUTTON_TEXT = 'Reset'; + +/** + * Converts a JavaScript Date object to a database-compatible timestamp string. + * @param {Date} [dateObject=new Date()] - The date to convert. Defaults to current date/time. + * @returns {string} Formatted timestamp string in format: "YYYY-MM-DD HH:MM:SS.mmmmmm" like "2025-11-06 05:30:45.123000" + */ +function getDateStringInDbFormat(dateObject = new Date()) { + const year = dateObject.getFullYear(); + const month = String(dateObject.getMonth() + 1).padStart(2, '0'); + const day = String(dateObject.getDate()).padStart(2, '0'); + const hours = String(dateObject.getHours()).padStart(2, '0'); + const minutes = String(dateObject.getMinutes()).padStart(2, '0'); + const seconds = String(dateObject.getSeconds()).padStart(2, '0'); + const millis = String(dateObject.getMilliseconds()).padStart(3, '0'); + // JS only gives milliseconds (3 digits) so converting it to 6 digits like ".812169" + const micros = millis + '000'; + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${micros}`; +} + +describe('Automate Service Requests form operations: Services > Requests', () => { + beforeEach(() => { + cy.login(); + }); + + describe('Verify form fields', () => { + it('Verify form’s initial UI state', () => { + cy.menu(SERVICES_MENU_OPTION, REQUESTS_MENU_OPTION); + cy.contains('#main-content h1', FORM_HEADER); + cy.getFormLegendByText({ legendText: APPROVAL_STATE_HEADER }); + cy.validateFormLabels([ + { + [LABEL_CONFIG_KEYS.FOR_VALUE]: 'selectedUser', + [LABEL_CONFIG_KEYS.EXPECTED_TEXT]: REQUESTER_LABEL, + }, + { + [LABEL_CONFIG_KEYS.FOR_VALUE]: 'types', + [LABEL_CONFIG_KEYS.EXPECTED_TEXT]: TYPE_LABEL, + }, + { + [LABEL_CONFIG_KEYS.FOR_VALUE]: 'selectedPeriod', + [LABEL_CONFIG_KEYS.EXPECTED_TEXT]: REQUEST_DATE_LABEL, + }, + { + [LABEL_CONFIG_KEYS.FOR_VALUE]: 'reasonText', + [LABEL_CONFIG_KEYS.EXPECTED_TEXT]: REASON_LABEL, + }, + { + [LABEL_CONFIG_KEYS.FOR_VALUE]: 'approvalStates-pending_approval', + [LABEL_CONFIG_KEYS.EXPECTED_TEXT]: PENDING_APPROVAL_LABEL, + }, + { + [LABEL_CONFIG_KEYS.FOR_VALUE]: 'approvalStates-approved', + [LABEL_CONFIG_KEYS.EXPECTED_TEXT]: APPROVED_LABEL, + }, + { + [LABEL_CONFIG_KEYS.FOR_VALUE]: 'approvalStates-denied', + [LABEL_CONFIG_KEYS.EXPECTED_TEXT]: DENIED_LABEL, + }, + ]); + cy.validateFormFields([ + { + [FIELD_CONFIG_KEYS.ID]: 'selectedUser', + [FIELD_CONFIG_KEYS.FIELD_TYPE]: FIELD_TYPES.SELECT, + [FIELD_CONFIG_KEYS.EXPECTED_VALUE]: SELECT_OPTION_ALL, + }, + { + [FIELD_CONFIG_KEYS.ID]: 'approvalStates-pending_approval', + [FIELD_CONFIG_KEYS.INPUT_FIELD_TYPE]: 'checkbox', + [FIELD_CONFIG_KEYS.SHOULD_BE_CHECKED]: true, + }, + { + [FIELD_CONFIG_KEYS.ID]: 'approvalStates-approved', + [FIELD_CONFIG_KEYS.INPUT_FIELD_TYPE]: 'checkbox', + [FIELD_CONFIG_KEYS.SHOULD_BE_CHECKED]: true, + }, + { + [FIELD_CONFIG_KEYS.ID]: 'approvalStates-denied', + [FIELD_CONFIG_KEYS.INPUT_FIELD_TYPE]: 'checkbox', + [FIELD_CONFIG_KEYS.SHOULD_BE_CHECKED]: true, + }, + { + [FIELD_CONFIG_KEYS.ID]: 'types', + [FIELD_CONFIG_KEYS.FIELD_TYPE]: FIELD_TYPES.SELECT, + [FIELD_CONFIG_KEYS.EXPECTED_VALUE]: SELECT_OPTION_ALL, + }, + { + [FIELD_CONFIG_KEYS.ID]: 'selectedPeriod', + [FIELD_CONFIG_KEYS.FIELD_TYPE]: FIELD_TYPES.SELECT, + [FIELD_CONFIG_KEYS.EXPECTED_VALUE]: REQUEST_DATE_LAST_7_DAYS, + }, + { + [FIELD_CONFIG_KEYS.ID]: 'reasonText', + }, + ]); + cy.validateFormButtons([ + { + [BUTTON_CONFIG_KEYS.BUTTON_TEXT]: APPLY_BUTTON_TEXT, + [BUTTON_CONFIG_KEYS.BUTTON_TYPE]: 'submit', + }, + { + [BUTTON_CONFIG_KEYS.BUTTON_TEXT]: RESET_BUTTON_TEXT, + }, + ]); + cy.expect_gtl_no_records_with_text(); + }); + }); + + describe('Validate button click actions', () => { + beforeEach(() => { + const tenDaysAgo = new Date( + new Date().getTime() - 10 * 24 * 60 * 60 * 1000 + ); + + cy.appFactories([ + [ + 'create', + 'service_template_provision_request', + { + description: 'Cypress mock data for approval state: Approved', + approval_state: 'approved', + type: 'ServiceTemplateProvisionRequest', + fulfilled_on: getDateStringInDbFormat(), + request_type: 'clone_to_service', + request_state: 'finished', + message: 'Cypress mock data for approval state: Approved', + status: 'Ok', + }, + ], + [ + 'create', + 'service_template_provision_request', + { + description: 'Cypress mock data for approval state: Denied', + approval_state: 'denied', + type: 'ServiceTemplateProvisionRequest', + fulfilled_on: getDateStringInDbFormat(), + request_type: 'clone_to_service', + request_state: 'finished', + message: 'Cypress mock data for approval state: Denied', + status: 'Ok', + }, + ], + [ + 'create', + 'vm_reconfigure_request', + { + description: + 'Cypress mock data for approval state: Pending-Approval', + approval_state: 'pending_approval', + type: 'VmReconfigureRequest', + request_type: TYPE_VM_RECONFIGURE, + request_state: 'pending', + message: 'Cypress mock data for approval state: Pending-Approval', + status: 'Ok', + }, + ], + // This record is used to filter data for requests made in the last 30 days + [ + 'create', + 'service_template_provision_request', + { + description: + 'Cypress mock data for request made in the last 30 days', + approval_state: 'approved', + type: 'ServiceTemplateProvisionRequest', + created_on: getDateStringInDbFormat(tenDaysAgo), + fulfilled_on: getDateStringInDbFormat(), + request_type: 'clone_to_service', + request_state: 'finished', + message: 'Cypress mock data for request made in the last 30 days', + status: 'Ok', + }, + ], + ]); + }); + + it('Validate reset & apply buttons', () => { + cy.menu(SERVICES_MENU_OPTION, REQUESTS_MENU_OPTION); + /* Reset */ + cy.getFormSelectFieldById({ selectId: 'selectedUser' }).select( + 'Test User 1' + ); + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-pending_approval', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-pending_approval', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-approved', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-approved', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-denied', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-denied', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormSelectFieldById({ selectId: 'types' }).select( + TYPE_VM_RECONFIGURE + ); + cy.getFormSelectFieldById({ selectId: 'selectedPeriod' }).select( + 'Last 30 Days' + ); + cy.getFormInputFieldByIdAndType({ inputId: 'reasonText' }).type( + 'Testing' + ); + cy.getFormButtonByTypeWithText({ + buttonText: RESET_BUTTON_TEXT, + }).click(); + cy.getFormSelectFieldById({ selectId: 'selectedUser' }).should( + 'have.value', + SELECT_OPTION_ALL + ); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-pending_approval', + inputType: 'checkbox', + }).should('be.checked'); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-approved', + inputType: 'checkbox', + }).should('be.checked'); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-denied', + inputType: 'checkbox', + }).should('be.checked'); + cy.getFormSelectFieldById({ selectId: 'types' }).should( + 'have.value', + SELECT_OPTION_ALL + ); + cy.getFormSelectFieldById({ selectId: 'selectedPeriod' }).should( + 'have.value', + REQUEST_DATE_LAST_7_DAYS + ); + cy.getFormInputFieldByIdAndType({ inputId: 'reasonText' }).should( + 'have.value', + '' + ); + /* Apply */ + // Filter data with approval state: Denied + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-pending_approval', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-pending_approval', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-approved', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-approved', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormButtonByTypeWithText({ + buttonText: APPLY_BUTTON_TEXT, + buttonType: 'submit', + }).click(); + cy.gtlGetRows([7]).then((data) => { + expect(data.length).to.equal(1); + expect(data[0][0]).to.equal(DENIED_LABEL); + }); + cy.getFormButtonByTypeWithText({ + buttonText: RESET_BUTTON_TEXT, + }).click(); + cy.gtlGetRows([0]).then((data) => { + expect(data.length).to.equal(3); + }); + // Filter data with approval state: Approved + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-pending_approval', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-pending_approval', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-denied', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-denied', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormButtonByTypeWithText({ + buttonText: APPLY_BUTTON_TEXT, + buttonType: 'submit', + }).click(); + cy.gtlGetRows([7]).then((data) => { + expect(data.length).to.equal(1); + expect(data[0][0]).to.equal(APPROVED_LABEL); + }); + cy.getFormButtonByTypeWithText({ + buttonText: RESET_BUTTON_TEXT, + }).click(); + cy.gtlGetRows([0]).then((data) => { + expect(data.length).to.equal(3); + }); + // Filter data with approval state: Pending approval + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-approved', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-approved', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormLabelByForAttribute({ + forValue: 'approvalStates-denied', + }).click(); + cy.getFormInputFieldByIdAndType({ + inputId: 'approvalStates-denied', + inputType: 'checkbox', + }).should('not.be.checked'); + cy.getFormButtonByTypeWithText({ + buttonText: APPLY_BUTTON_TEXT, + buttonType: 'submit', + }).click(); + cy.gtlGetRows([7]).then((data) => { + expect(data.length).to.equal(1); + expect(data[0][0]).to.equal(PENDING_APPROVAL_LABEL); + }); + cy.getFormButtonByTypeWithText({ + buttonText: RESET_BUTTON_TEXT, + }).click(); + cy.gtlGetRows([0]).then((data) => { + expect(data.length).to.equal(3); + }); + // Filter data with type: VM Reconfigure + cy.getFormSelectFieldById({ selectId: 'types' }).select( + TYPE_VM_RECONFIGURE + ); + cy.getFormButtonByTypeWithText({ + buttonText: APPLY_BUTTON_TEXT, + buttonType: 'submit', + }).click(); + cy.gtlGetRows([4]).then((data) => { + expect(data.length).to.equal(1); + expect(data[0][0]).to.equal('VM Reconfigure'); + }); + cy.getFormButtonByTypeWithText({ + buttonText: RESET_BUTTON_TEXT, + }).click(); + cy.gtlGetRows([0]).then((data) => { + expect(data.length).to.equal(3); + }); + // Filter data with request date: last 30 days + cy.getFormSelectFieldById({ selectId: 'selectedPeriod' }).select( + REQUEST_DATE_LAST_30_DAYS + ); + cy.getFormButtonByTypeWithText({ + buttonText: APPLY_BUTTON_TEXT, + buttonType: 'submit', + }).click(); + cy.gtlGetRows([6]).then((data) => { + expect(data.length).to.equal(4); + expect(data[0][0]).to.include('request made in the last 30 days'); + }); + // Filter data with reason text + cy.getFormInputFieldByIdAndType({ inputId: 'reasonText' }).type('r@ndOm'); + cy.getFormButtonByTypeWithText({ + buttonText: APPLY_BUTTON_TEXT, + buttonType: 'submit', + }).click(); + cy.expect_gtl_no_records_with_text(); + cy.getFormButtonByTypeWithText({ + buttonText: RESET_BUTTON_TEXT, + }).click(); + cy.gtlGetRows([0]).then((data) => { + expect(data.length).to.equal(3); + }); + }); + + afterEach(() => { + cy.appDbState('restore'); + }); + }); +});