From cc78e0dbaded37d865e6f59d2682d8a28d825e5b Mon Sep 17 00:00:00 2001 From: asirvadAbrahamVarghese Date: Fri, 22 Aug 2025 10:29:24 +0530 Subject: [PATCH 1/4] Code refactoring on schedule form cypress tests --- .../Application-Settings/schedule.cy.js | 771 ++++++++++-------- 1 file changed, 432 insertions(+), 339 deletions(-) diff --git a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js index ae7a932e724..002c81c38a8 100644 --- a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js +++ b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js @@ -1,124 +1,98 @@ /* eslint-disable no-undef */ import { flashClassMap } from '../../../../support/assertions/assertion_constants'; -const textConstants = { - // List items - schedulesAccordionItem: 'Schedules', - - // Field values - initialScheduleName: 'Test-name', - editedScheduleName: 'Dummy-name', - initialDescription: 'Test description', - editedDescription: 'Dummy description', - actionTypeVmAnalysis: 'vm', - actionTypeTemplateAnalysis: 'miq_template', - actionTypeHostAnalysis: 'host', - actionTypeContainerAnalysis: 'container_image', - actionTypeClusterAnalysis: 'emscluster', - actionTypeDataStoreAnalysis: 'storage', - actionTypeVmCompilanceCheck: 'vm_check_compliance', - actionTypeHostCompilanceCheck: 'host_check_compliance', - actionTypeContainerCompilanceCheck: 'container_image_check_compliance', - actionTypeAutomationTasks: 'automation_request', - filterTypeVmCluster: 'cluster', - timerTypeOnce: 'Once', - timerTypeHourly: 'Hourly', - timerTypeDaily: 'Daily', - timerTypeWeekly: 'Weekly', - timerTypeMonthly: 'Monthly', - frequencyTypeHour: '1 Hour', - timezoneTypeHawaii: '(GMT-10:00) Hawaii', - initialStartDate: '06/30/2025', - editedStartDate: '07/21/2025', - startTime: '11:23', - - // Buttons - saveButton: 'Save', - cancelButton: 'Cancel', - resetButton: 'Reset', - - // Config options - configToolbarButton: 'Configuration', - addScheduleConfigOption: 'Add a new Schedule', - deleteScheduleConfigOption: 'Delete this Schedule from the Database', - editScheduleConfigOption: 'Edit this Schedule', - disableScheduleConfigOption: 'Disable this Schedule', - enableScheduleConfigOption: 'Enable this Schedule', - queueScheduleConfigOption: 'Queue up this Schedule to run now', - - // Menu options - settingsMenuOption: 'Settings', - appSettingsMenuOption: 'Application Settings', - - // Flash message text snippets - flashMessageScheduleQueued: 'queued to run', - flashMessageOperationCanceled: 'cancelled', - flashMessageScheduleDisabled: 'disabled', - flashMessageScheduleEnabled: 'enabled', - flashMessageScheduleSaved: 'saved', - flashMessageResetSchedule: 'reset', - flashMessageScheduleDeleted: 'delete successful', - flashMessageFailedToAddSchedule: 'failed', - - // Browser alert text snippets - browserAlertDeleteConfirmText: 'will be permanently removed', -}; - -const { - settingsMenuOption, - appSettingsMenuOption, - actionTypeVmAnalysis, - actionTypeTemplateAnalysis, - actionTypeHostAnalysis, - actionTypeContainerAnalysis, - actionTypeClusterAnalysis, - actionTypeDataStoreAnalysis, - actionTypeVmCompilanceCheck, - actionTypeHostCompilanceCheck, - actionTypeContainerCompilanceCheck, - actionTypeAutomationTasks, - timerTypeOnce, - timerTypeHourly, - timerTypeDaily, - timerTypeWeekly, - timerTypeMonthly, - cancelButton, - saveButton, - initialScheduleName, - editScheduleConfigOption, - editedScheduleName, - editedDescription, - editedStartDate, - resetButton, - initialDescription, - initialStartDate, - disableScheduleConfigOption, - enableScheduleConfigOption, - queueScheduleConfigOption, - addScheduleConfigOption, - frequencyTypeHour, - timezoneTypeHawaii, - startTime, - deleteScheduleConfigOption, - schedulesAccordionItem, - configToolbarButton, - flashMessageScheduleQueued, - flashMessageOperationCanceled, - flashMessageScheduleDisabled, - flashMessageScheduleEnabled, - flashMessageScheduleSaved, - flashMessageResetSchedule, - flashMessageScheduleDeleted, - flashMessageFailedToAddSchedule, - browserAlertDeleteConfirmText, -} = textConstants; - -function selectConfigMenu(menuOption = addScheduleConfigOption) { - return cy.toolbar(configToolbarButton, menuOption); +// Component route url +const COMPONENT_ROUTE_URL = '/ops/explorer'; + +// List items +const SCHEDULES_ACCORDION_ITEM = 'Schedules'; +const MANAGEIQ_REGION_ACCORDION_ITEM = /^ManageIQ Region:/; + +// Field values +const BASIC_INFO_SUB_HEADER = 'Basic Information'; +const NAME_FIELD_LABEL = 'Name'; +const DESCRIPTION_FIELD_LABEL = 'Description'; +const ACTIVE_CHECKBOX_FIELD_LABEL = 'Active'; +const ACTION_TYPE_FIELD_LABEL = 'Action'; +const FILTER_TYPE_FIELD_LABEL = 'Filter'; +const ZONE_FIELD_LABEL = 'Zone'; +const OBJECT_DETAILS_SUB_HEADER = 'Object Details'; +const SYSTEM_FIELD_LABEL = 'System/Process'; +const MESSAGE_FIELD_LABEL = 'Message'; +const REQUEST_FIELD_LABEL = 'Request'; +const OBJECT_LABEL_TEXT = 'Object'; +const OBJECT_TYPE_FIELD_LABEL = 'Type'; +const OBJECT_TYPE_CLOUD_NETWORK = 'Cloud Network'; +const ATTRIBUTE_PAIRS_SUB_HEADER = 'Attribute/Value Pairs'; +const TIMER_TYPE_FIELD_LABEL = 'Run'; +const TIMER_VALUE_FIELD_LABEL = 'Every'; +const TIME_ZONE_FIELD_LABEL = 'Time Zone'; +const START_DATE_FIELD_LABEL = 'Starting Date'; +const START_TIME_FIELD_LABEL = 'Starting Time'; +const INITIAL_SCHEDULE_NAME = 'Test-name'; +const EDITED_SCHEDULE_NAME = 'Dummy-name'; +const INITIAL_DESCRIPTION = 'Test description'; +const EDITED_DESCRIPTION = 'Dummy description'; +const ACTION_TYPE_VM_ANALYSIS = 'vm'; +const ACTION_TYPE_TEMPLATE_ANALYSIS = 'miq_template'; +const ACTION_TYPE_HOST_ANALYSIS = 'host'; +const ACTION_TYPE_CONTAINER_ANALYSIS = 'container_image'; +const ACTION_TYPE_CLUSTER_ANALYSIS = 'emscluster'; +const ACTION_TYPE_DATA_STORE_ANALYSIS = 'storage'; +const ACTION_TYPE_VM_COMPILANCE_CHECK = 'vm_check_compliance'; +const ACTION_TYPE_HOST_COMPILANCE_CHECK = 'host_check_compliance'; +const ACTION_TYPE_CONTAINER_COMPILANCE_CHECK = + 'container_image_check_compliance'; +const ACTION_TYPE_AUTOMATION_TASKS = 'automation_request'; +const TIMER_TYPE_ONCE = 'Once'; +const TIMER_TYPE_HOURLY = 'Hourly'; +const TIMER_TYPE_DAILY = 'Daily'; +const TIMER_TYPE_WEEKLY = 'Weekly'; +const TIMER_TYPE_MONTHLY = 'Monthly'; +const FREQUENCY_TYPE_HOUR = '1 Hour'; +const TIME_ZONE_TYPE_HAWAII = '(GMT-10:00) Hawaii'; +const INITIAL_START_DATE = '06/30/2025'; +const EDITED_START_DATE = '07/21/2025'; +const START_TIME = '11:23'; + +// Buttons +const SAVE_BUTTON_TEXT = 'Save'; +const CANCEL_BUTTON_TEXT = 'Cancel'; +const RESET_BUTTON_TEXT = 'Reset'; + +// Config options +const CONFIG_TOOLBAR_BUTTON = 'Configuration'; +const ADD_SCHEDULE_CONFIG_OPTION = 'Add a new Schedule'; +const DELETE_SCHEDULE_CONFIG_OPTION = 'Delete this Schedule from the Database'; +const EDIT_SCHEDULE_CONFIG_OPTION = 'Edit this Schedule'; +const DISABLE_SCHEDULE_CONFIG_OPTION = 'Disable this Schedule'; +const ENABLE_SCHEDULE_CONFIG_OPTION = 'Enable this Schedule'; +const QUEUE_SCHEDULE_CONFIG_OPTION = 'Queue up this Schedule to run now'; + +// Menu options +const SETTINGS_OPTION = 'Settings'; +const APP_SETTINGS_OPTION = 'Application Settings'; + +// Flash message text snippets +const FLASH_MESSAGE_SCHEDULE_QUEUED = 'queued'; +const FLASH_MESSAGE_OPERATION_CANCELED = 'cancel'; +const FLASH_MESSAGE_SCHEDULE_DISABLED = 'disabled'; +const FLASH_MESSAGE_SCHEDULE_ENABLED = 'enabled'; +const FLASH_MESSAGE_SCHEDULE_SAVED = 'saved'; +const FLASH_MESSAGE_RESET_SCHEDULE = 'reset'; +const FLASH_MESSAGE_SCHEDULE_DELETED = 'delete'; +const FLASH_MESSAGE_FAILED_TO_ADD_SCHEDULE = 'failed'; + +// Browser alert text snippets +const BROWSER_ALERT_DELETE_CONFIRM_TEXT = 'removed'; + +function selectConfigMenu(menuOption) { + return cy.toolbar(CONFIG_TOOLBAR_BUTTON, menuOption); } function addSchedule() { - selectConfigMenu(); + // Open add schedule form + selectConfigMenu(ADD_SCHEDULE_CONFIG_OPTION); // Checks if Save button is disabled initially cy.contains( '#main-content .bx--btn-set button[type="submit"]', @@ -137,35 +111,23 @@ function addSchedule() { // Select Every option: '1 Hour' cy.get('select#timer_value').select(frequencyTypeHour); // Select Time zone option: '(GMT-10:00) Hawaii' - cy.get('input[role="combobox"]#time_zone').click(); - cy.contains('[role="option"]', timezoneTypeHawaii) - .should('be.visible') - .click(); - cy.get('input#start_date').type(initialStartDate); - cy.get('input#start_time').type(startTime); + cy.getFormInputFieldById('time_zone').click(); + cy.contains('[role="option"]', TIME_ZONE_TYPE_HAWAII).click(); + cy.getFormInputFieldById('start_date').type(INITIAL_START_DATE); + cy.getFormInputFieldById('start_time').type(START_TIME); // Intercepting the API call for adding a new schedule - cy.intercept('POST', '/ops/schedule_edit/new?button=save').as( - 'addScheduleApi' - ); - cy.contains('#main-content .bx--btn-set button[type="submit"]', saveButton) - .should('be.enabled') // Checks if Save button is enabled once all required fields are filled - .click(); - // Wait for the API call to complete - cy.wait('@addScheduleApi'); -} - -function deleteSchedule(scheduleName = initialScheduleName) { - // Selecting the schedule and intercepting the API call to get schedule details - interceptGetScheduleDetailsApi(scheduleName); - // Listening for the browser confirm alert and confirming deletion - cy.expect_browser_confirm_with_text({ - confirmTriggerFn: () => selectConfigMenu(deleteScheduleConfigOption), - containsText: browserAlertDeleteConfirmText, + cy.interceptApi({ + alias: 'addScheduleApi', + urlPattern: '/ops/schedule_edit/new?button=save', + triggerFn: () => + cy.contains('#main-content .bx--btn-set button[type="submit"]', saveButton) + .should('be.enabled') // Checks if Save button is enabled once all required fields are filled + .click(), }); - cy.expect_flash(flashClassMap.success, flashMessageScheduleDeleted); } -function interceptGetScheduleDetailsApi(scheduleName = initialScheduleName) { +function clickScheduleItem(scheduleName) { + // TODO: Replace with cy.interceptApi after it's enhanced to wait conditionally on request trigger // Flag to check if the request is fired let requestFired = false; // Intercepting the API call @@ -192,204 +154,344 @@ function interceptGetScheduleDetailsApi(scheduleName = initialScheduleName) { }); } +function deleteSchedule(scheduleName) { + // Selecting the schedule and intercepting the API call to get schedule details + clickScheduleItem(scheduleName); + // Listening for the browser confirm alert and confirming deletion + cy.expect_browser_confirm_with_text({ + confirmTriggerFn: () => selectConfigMenu(DELETE_SCHEDULE_CONFIG_OPTION), + containsText: BROWSER_ALERT_DELETE_CONFIRM_TEXT, + }); + cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_SCHEDULE_DELETED); +} + function invokeCleanupDeletion() { // Iterate and clean up any leftover schedules created during the test - cy.get('li.list-group-item').each(($el) => { - const text = $el?.text()?.trim(); - if (text === initialScheduleName) { - deleteSchedule(); + cy.get('div.panel-collapse.collapse.in li.list-group-item').each((item) => { + const text = item?.text()?.trim(); + if (text === INITIAL_SCHEDULE_NAME) { + deleteSchedule(INITIAL_SCHEDULE_NAME); return false; } - if (text === editedScheduleName) { - deleteSchedule(editedScheduleName); - return false; + if (text === EDITED_SCHEDULE_NAME) { + deleteSchedule(EDITED_SCHEDULE_NAME); + return false; // exit iteration } - return true; + return null; // has no impact, just to get rid of eslint warning }); } -function verifyFilterTypeDropdownExists() { - cy.get('label[for="filter_typ"]').should('exist'); - cy.get('select#filter_typ').should('exist'); -} - -function verifyTimerDropdownExists() { - cy.get('label[for="timer_value"]').should('exist'); - cy.get('select#timer_value').should('exist'); -} - describe('Automate Schedule form operations: Settings > Application Settings > Settings > Schedules > Configuration > Add a new schedule', () => { beforeEach(() => { cy.login(); - cy.menu(settingsMenuOption, appSettingsMenuOption); - cy.intercept( - { - method: 'POST', - pathname: '/ops/tree_select', - query: { text: schedulesAccordionItem }, - }, - ).as('getSchedules'); - cy.accordionItem(schedulesAccordionItem); - cy.wait('@getSchedules'); + // Navigate to Application-Settings + cy.menu(SETTINGS_OPTION, APP_SETTINGS_OPTION); + // Expand Settings accordion panel + cy.accordion(SETTINGS_OPTION); + // Select Schedules accordion item + cy.interceptApi({ + alias: 'treeSelectApi', + urlPattern: /\/ops\/tree_select\?id=.*&text=.*/, + triggerFn: () => + cy.selectAccordionItem([ + MANAGEIQ_REGION_ACCORDION_ITEM, + SCHEDULES_ACCORDION_ITEM, + ]), + }); }); - it('Validate visibility of elements based on dropdown selections', () => { - selectConfigMenu(); + it('Validate visibility of elements and dynamic rendering based on dropdown changes', () => { + // Open add schedule form + selectConfigMenu(ADD_SCHEDULE_CONFIG_OPTION); + + // Assert basic info header is visible + cy.contains('h3', BASIC_INFO_SUB_HEADER).should('be.visible'); + // Assert name input field is visible & enabled + cy.getFormLabelByInputId('name') + .should('be.visible') + .and('contain.text', NAME_FIELD_LABEL); + cy.getFormInputFieldById('name').should('be.visible').and('be.enabled'); + // Assert description input field is visible & enabled + cy.getFormLabelByInputId('description') + .should('be.visible') + .and('contain.text', DESCRIPTION_FIELD_LABEL); + cy.getFormInputFieldById('description') + .should('be.visible') + .and('be.enabled'); + // Assert active checkbox field is visible & enabled + cy.getFormLabelByInputId('enabled') + .should('be.visible') + .and('contain.text', ACTIVE_CHECKBOX_FIELD_LABEL); + cy.getFormInputFieldById('enabled', 'checkbox') + .should('be.visible') + .and('be.enabled'); /* ===== Selecting any option other than "Automation Tasks" from "Action" dropdown does not hide the Filter dropdown ===== */ - - cy.get('select#action_typ').select(actionTypeVmAnalysis); - cy.get('select#action_typ').should('have.value', actionTypeVmAnalysis); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeTemplateAnalysis); - cy.get('select#action_typ').should( - 'have.value', - actionTypeTemplateAnalysis + // Assert action type dropdown is visible & enabled and then selecting "Vm Analysis" to verify filter type dropdown is visible & enabled + cy.getFormLabelByInputId('action_typ') + .should('be.visible') + .and('contain.text', ACTION_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('action_typ') + .should('be.visible') + .and('be.enabled') + .select(ACTION_TYPE_VM_ANALYSIS); + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "Template Analysis" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_TEMPLATE_ANALYSIS ); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeHostAnalysis); - cy.get('select#action_typ').should('have.value', actionTypeHostAnalysis); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeContainerAnalysis); - cy.get('select#action_typ').should( - 'have.value', - actionTypeContainerAnalysis + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "Host Analysis" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select(ACTION_TYPE_HOST_ANALYSIS); + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "Container Analysis" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_CONTAINER_ANALYSIS ); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeClusterAnalysis); - cy.get('select#action_typ').should('have.value', actionTypeClusterAnalysis); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeDataStoreAnalysis); - cy.get('select#action_typ').should( - 'have.value', - actionTypeDataStoreAnalysis + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "Cluster Analysis" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_CLUSTER_ANALYSIS ); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeVmCompilanceCheck); - cy.get('select#action_typ').should( - 'have.value', - actionTypeVmCompilanceCheck + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "DataStore Analysis" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_DATA_STORE_ANALYSIS ); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeHostCompilanceCheck); - cy.get('select#action_typ').should( - 'have.value', - actionTypeHostCompilanceCheck + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "Vm Compilance Check" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_VM_COMPILANCE_CHECK ); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); - - cy.get('select#action_typ').select(actionTypeContainerCompilanceCheck); - cy.get('select#action_typ').should( - 'have.value', - actionTypeContainerCompilanceCheck + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "Host Compilance Check" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_HOST_COMPILANCE_CHECK ); - // Checking for Filter type dropdown - verifyFilterTypeDropdownExists(); + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); + // Selecting "Container Compilance Check" to verify filter type dropdown is visible & enabled + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_CONTAINER_COMPILANCE_CHECK + ); + cy.getFormLabelByInputId('filter_typ') + .should('be.visible') + .and('contain.text', FILTER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('filter_typ') + .should('be.visible') + .and('be.enabled'); /* ===== Selecting "Automation Tasks" option from "Action" dropdown shows Zone, Object details & Object fields ===== */ - - cy.get('select#action_typ').select(actionTypeAutomationTasks); - cy.get('select#action_typ').should('have.value', actionTypeAutomationTasks); - - // Checking for Zone dropdown - cy.get('label[for="zone_id"]').should('exist'); - cy.get('select#zone_id').should('exist'); - - // Checking for Object Details - cy.get('h3[name="object_details"]').should('exist'); - // Checking for System/Process dropdown - cy.get('label[for="instance_name"]').should('exist'); - cy.get('select#instance_name').should('exist'); - // Checking for Messsage textfield - cy.get('label[for="message"]').should('exist'); - cy.get('input#message').should('exist'); - // Checking for Request textfield - cy.get('label[for="request"]').should('exist'); - cy.get('input#request').should('exist'); - - // Checking for Object - cy.get('h3[name="object_attributes"]').should('exist'); - // Checking for Type Combobox - cy.get('label[for="target_class"]').should('exist'); - cy.get('input[role="combobox"]#target_class').should('exist'); - // Checking for Object Combobox - cy.get('label[for="target_id"]').should('exist'); - cy.get('input[role="combobox"]#target_id').should('exist'); - - // Checking for Attribute/Value pairs - cy.contains('h3', 'Attribute/Value Pairs').should('exist'); - // Checking for 5 attribute-value pairs text fields - cy.get('input#attribute_1').should('exist'); - cy.get('input#value_1').should('exist'); - cy.get('input#attribute_2').should('exist'); - cy.get('input#value_2').should('exist'); - cy.get('input#attribute_3').should('exist'); - cy.get('input#value_3').should('exist'); - cy.get('input#attribute_4').should('exist'); - cy.get('input#value_4').should('exist'); - cy.get('input#attribute_5').should('exist'); - cy.get('input#value_5').should('exist'); - - /* ===== Selecting "Once" option from "Run" dropdown does not show the "Every" dropdown ===== */ - - cy.get('select#timer_typ').select(timerTypeOnce); - // Checking whether the Every dropdown is hidden - cy.get('input#timer_value').should('not.exist'); - - /* ===== Selecting any other option other than "Once" from "Run" dropdown shows the "Every" dropdown ===== */ - - cy.get('select#timer_typ').select(timerTypeHourly); - // Checking whether the "Every" dropdown exist - verifyTimerDropdownExists(); - - cy.get('select#timer_typ').select(timerTypeDaily); - // Checking whether the "Every" dropdown exist - verifyTimerDropdownExists(); - - cy.get('select#timer_typ').select(timerTypeWeekly); - // Checking whether the "Every" dropdown exist - verifyTimerDropdownExists(); - - cy.get('select#timer_typ').select(timerTypeMonthly); - // Checking whether the "Every" dropdown exist - verifyTimerDropdownExists(); + cy.getFormSelectFieldById('action_typ').select( + ACTION_TYPE_AUTOMATION_TASKS + ); + // Assert Zone select field is visible & enabled + cy.getFormLabelByInputId('zone_id') + .should('be.visible') + .and('contain.text', ZONE_FIELD_LABEL); + cy.getFormSelectFieldById('zone_id').should('be.visible').and('be.enabled'); + + // Verifying Object Details fields + cy.contains('h3[name="object_details"]', OBJECT_DETAILS_SUB_HEADER).should( + 'be.visible' + ); + // Assert System/Process dropdown is visible & enabled + cy.getFormLabelByInputId('instance_name') + .should('be.visible') + .and('contain.text', SYSTEM_FIELD_LABEL); + cy.getFormSelectFieldById('instance_name') + .should('be.visible') + .and('be.enabled'); + // Assert Messsage input field is visible & enabled + cy.getFormLabelByInputId('message') + .should('be.visible') + .and('contain.text', MESSAGE_FIELD_LABEL); + cy.getFormInputFieldById('message').should('be.visible').and('be.enabled'); + // Assert Request input field is visible & enabled + cy.getFormLabelByInputId('request') + .should('be.visible') + .and('contain.text', REQUEST_FIELD_LABEL); + cy.getFormInputFieldById('request').should('be.visible').and('be.enabled'); + + // Verifying Object fields + cy.contains('h3[name="object_attributes"]', OBJECT_LABEL_TEXT).should( + 'be.visible' + ); + // Assert Type Combobox is visible & enabled and then selecting "Cloud Network" option + cy.getFormLabelByInputId('target_class') + .should('be.visible') + .and('contain.text', OBJECT_TYPE_FIELD_LABEL); + cy.getFormInputFieldById('target_class') + .should('be.visible') + .and('be.enabled') + .click(); + cy.contains('[role="option"]', OBJECT_TYPE_CLOUD_NETWORK).click(); + // Assert Object Combobox is visible & enabled, once Type is selected + cy.getFormLabelByInputId('target_id') + .should('be.visible') + .and('contain.text', OBJECT_LABEL_TEXT); + cy.getFormInputFieldById('target_id') + .should('be.visible') + .and('be.enabled'); + + // Verifying Attribute/Value pairs fields + cy.contains('h3', ATTRIBUTE_PAIRS_SUB_HEADER).should('be.visible'); + // Verifying 5 attribute-value pairs text fields are visible and enabled + cy.getFormInputFieldById('attribute_1') + .should('be.visible') + .and('be.enabled'); + cy.getFormInputFieldById('value_1').should('be.visible').and('be.enabled'); + cy.getFormInputFieldById('attribute_2') + .should('be.visible') + .and('be.enabled'); + cy.getFormInputFieldById('value_2').should('be.visible').and('be.enabled'); + cy.getFormInputFieldById('attribute_3') + .should('be.visible') + .and('be.enabled'); + cy.getFormInputFieldById('value_3').should('be.visible').and('be.enabled'); + cy.getFormInputFieldById('attribute_4') + .should('be.visible') + .and('be.enabled'); + cy.getFormInputFieldById('value_4').should('be.visible').and('be.enabled'); + cy.getFormInputFieldById('attribute_5') + .should('be.visible') + .and('be.enabled'); + cy.getFormInputFieldById('value_5').should('be.visible').and('be.enabled'); + + /* ===== Selecting "Once" option from "Run" dropdown should not show "Every" dropdown ===== */ + // Assert Run(timer type) dropdown is visible & enabled and then selecting "Once" option + cy.getFormLabelByInputId('timer_typ') + .should('be.visible') + .and('contain.text', TIMER_TYPE_FIELD_LABEL); + cy.getFormSelectFieldById('timer_typ') + .should('be.visible') + .and('be.enabled') + .select(TIMER_TYPE_ONCE); + // Assert "Every" dropdown is hidden + cy.getFormInputFieldById('timer_value').should('not.exist'); + + /* ===== Selecting any other option other than "Once" from "Run" dropdown should show "Every" dropdown ===== */ + // Selecting "Hourly" to verify timer dropdown is visible & enabled + cy.getFormSelectFieldById('timer_typ').select(TIMER_TYPE_HOURLY); + cy.getFormLabelByInputId('timer_value') + .should('be.visible') + .and('contain.text', TIMER_VALUE_FIELD_LABEL); + cy.getFormSelectFieldById('timer_value') + .should('be.visible') + .and('be.enabled'); + // Selecting "Daily" to verify timer dropdown is visible & enabled + cy.getFormSelectFieldById('timer_typ').select(TIMER_TYPE_DAILY); + cy.getFormLabelByInputId('timer_value') + .should('be.visible') + .and('contain.text', TIMER_VALUE_FIELD_LABEL); + cy.getFormSelectFieldById('timer_value') + .should('be.visible') + .and('be.enabled'); + // Selecting "Weekly" to verify timer dropdown is visible & enabled + cy.getFormSelectFieldById('timer_typ').select(TIMER_TYPE_WEEKLY); + cy.getFormLabelByInputId('timer_value') + .should('be.visible') + .and('contain.text', TIMER_VALUE_FIELD_LABEL); + cy.getFormSelectFieldById('timer_value') + .should('be.visible') + .and('be.enabled'); + // Selecting "Monthly" to verify timer dropdown is visible & enabled + cy.getFormSelectFieldById('timer_typ').select(TIMER_TYPE_MONTHLY); + cy.getFormLabelByInputId('timer_value') + .should('be.visible') + .and('contain.text', TIMER_VALUE_FIELD_LABEL); + cy.getFormSelectFieldById('timer_value') + .should('be.visible') + .and('be.enabled'); + + // Assert timezone dropdown is visible & enabled + cy.getFormLabelByInputId('time_zone') + .should('be.visible') + .and('contain.text', TIME_ZONE_FIELD_LABEL); + cy.getFormInputFieldById('time_zone') + .should('be.visible') + .and('be.enabled'); + // Assert starting date field is visible & enabled + cy.getFormLabelByInputId('start_date') + .should('be.visible') + .and('contain.text', START_DATE_FIELD_LABEL); + cy.getFormInputFieldById('start_date') + .should('be.visible') + .and('be.enabled'); + // Assert starting time field is visible & enabled + cy.getFormLabelByInputId('start_time') + .should('be.visible') + .and('contain.text', START_TIME_FIELD_LABEL); + cy.getFormInputFieldById('start_time') + .should('be.visible') + .and('be.enabled'); + // Assert save button is visible and disabled + cy.getFormFooterButtonByType(SAVE_BUTTON_TEXT, 'submit') + .should('be.visible') + .and('be.disabled'); + // Assert cancel button is visible and enabled + cy.getFormFooterButtonByType(CANCEL_BUTTON_TEXT) + .should('be.visible') + .and('be.enabled'); }); it('Checking whether Cancel button works on the Add form', () => { - selectConfigMenu(); - cy.contains( - '#main-content .bx--btn-set button[type="button"]', - cancelButton - ) - .should('be.enabled') - .click(); - cy.expect_flash(flashClassMap.success, flashMessageOperationCanceled); + // Open add schedule form + selectConfigMenu(ADD_SCHEDULE_CONFIG_OPTION); + // Cancel the form + cy.getFormFooterButtonByType(CANCEL_BUTTON_TEXT).click(); + cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_OPERATION_CANCELED); }); it('Checking whether add, edit & delete schedule works', () => { /* ===== Adding a schedule ===== */ addSchedule(); - cy.expect_flash(flashClassMap.success, flashMessageScheduleSaved); + cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_SCHEDULE_SAVED); /* ===== Editing a schedule ===== */ // Selecting the schedule and intercepting the API call to get schedule details - interceptGetScheduleDetailsApi(); - selectConfigMenu(editScheduleConfigOption); + clickScheduleItem(INITIAL_SCHEDULE_NAME); + // Open edit schedule form + selectConfigMenu(EDIT_SCHEDULE_CONFIG_OPTION); // Editing name and description cy.get('input#name').clear().type(editedScheduleName); cy.get('input#description').clear().type(editedDescription); @@ -397,7 +499,7 @@ describe('Automate Schedule form operations: Settings > Application Settings > S cy.contains('#main-content .bx--btn-set button[type="submit"]', saveButton) .should('be.enabled') .click(); - cy.expect_flash(flashClassMap.success, flashMessageScheduleSaved); + cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_SCHEDULE_SAVED); /* ===== Delete is already handled from afterEach hook ===== */ }); @@ -406,35 +508,25 @@ describe('Automate Schedule form operations: Settings > Application Settings > S /* ===== Adding a schedule ===== */ addSchedule(); - /* ===== Checking whether Cancel button works ===== */ - // Selecting the schedule and intercepting the API call to get schedule details - interceptGetScheduleDetailsApi(); - selectConfigMenu(editScheduleConfigOption); - cy.contains( - '#main-content .bx--btn-set button[type="button"]', - cancelButton - ) - .should('be.enabled') - .click(); - cy.expect_flash(flashClassMap.success, flashMessageOperationCanceled); - /* ===== Checking whether Reset button works ===== */ // Selecting the schedule and intercepting the API call to get schedule details - interceptGetScheduleDetailsApi(); - selectConfigMenu(editScheduleConfigOption); + clickScheduleItem(INITIAL_SCHEDULE_NAME); + // Open edit schedule form + selectConfigMenu(EDIT_SCHEDULE_CONFIG_OPTION); // Editing description and start date cy.get('input#description').clear().type(editedDescription); cy.get('input#start_date').clear().type(editedStartDate); cy.contains('#main-content .bx--btn-set button[type="button"]', resetButton) .should('be.enabled') .click(); - cy.expect_flash(flashClassMap.warning, flashMessageResetSchedule); + cy.expect_flash(flashClassMap.warning, FLASH_MESSAGE_RESET_SCHEDULE); // Confirming the edited fields contain the old values after resetting cy.get('input#description').should('have.value', initialDescription); cy.get('input#start_date').should('have.value', initialStartDate); - // Selecting Schedules menu item to bypass a bug, can be removed once #9505 is merged - cy.accordionItem(schedulesAccordionItem); + /* ===== Checking whether Cancel button works ===== */ + cy.getFormFooterButtonByType(CANCEL_BUTTON_TEXT).click(); + cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_OPERATION_CANCELED); }); it('Checking whether creating a duplicate record is restricted', () => { @@ -443,38 +535,39 @@ describe('Automate Schedule form operations: Settings > Application Settings > S /* ===== Trying to add the same schedule again ===== */ addSchedule(); - cy.expect_flash(flashClassMap.error, flashMessageFailedToAddSchedule); + cy.expect_flash(flashClassMap.error, FLASH_MESSAGE_FAILED_TO_ADD_SCHEDULE); }); it('Checking whether Disabling, Enabling & Queueing up the schedule works', () => { /* ===== Adding a schedule ===== */ addSchedule(); // Selecting the schedule and intercepting the API call to get schedule details - interceptGetScheduleDetailsApi(); + clickScheduleItem(INITIAL_SCHEDULE_NAME); /* ===== Disabling the schedule ===== */ - selectConfigMenu(disableScheduleConfigOption); - cy.expect_flash(flashClassMap.info, flashMessageScheduleDisabled); + selectConfigMenu(DISABLE_SCHEDULE_CONFIG_OPTION); + cy.expect_flash(flashClassMap.info, FLASH_MESSAGE_SCHEDULE_DISABLED); /* ===== Enabling the schedule ===== */ - selectConfigMenu(enableScheduleConfigOption); - cy.expect_flash(flashClassMap.info, flashMessageScheduleEnabled); + selectConfigMenu(ENABLE_SCHEDULE_CONFIG_OPTION); + cy.expect_flash(flashClassMap.info, FLASH_MESSAGE_SCHEDULE_ENABLED); /* ===== Queueing-up the schedule ===== */ - selectConfigMenu(queueScheduleConfigOption); - cy.expect_flash(flashClassMap.success, flashMessageScheduleQueued); + selectConfigMenu(QUEUE_SCHEDULE_CONFIG_OPTION); + cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_SCHEDULE_QUEUED); }); afterEach(() => { - cy?.url()?.then((url) => { - // Ensures navigation to Settings -> Application-Settings in the UI - if (url?.includes('/ops/explorer')) { + cy.url() + ?.then((url) => { + // Ensures navigation to Settings -> Application-Settings in the UI + if (!url?.includes(COMPONENT_ROUTE_URL)) { + // Navigate to Settings -> Application-Settings before looking out for Schedules created during test + cy.menu(SETTINGS_OPTION, APP_SETTINGS_OPTION); + } + }) + .then(() => { invokeCleanupDeletion(); - } else { - // Navigate to Settings -> Application-Settings before looking out for Schedules created during test - cy.menu(settingsMenuOption, appSettingsMenuOption); - invokeCleanupDeletion(); - } - }); + }); }); }); From 27f4830aa951801b12e644f6687633b37dc1f9c7 Mon Sep 17 00:00:00 2001 From: asirvadAbrahamVarghese Date: Fri, 22 Aug 2025 10:37:01 +0530 Subject: [PATCH 2/4] Replaced repeated form selectors with custom getter commands --- .../Application-Settings/schedule.cy.js | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js index 002c81c38a8..9e347232824 100644 --- a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js +++ b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js @@ -94,22 +94,22 @@ function addSchedule() { // Open add schedule form selectConfigMenu(ADD_SCHEDULE_CONFIG_OPTION); // Checks if Save button is disabled initially - cy.contains( - '#main-content .bx--btn-set button[type="submit"]', - saveButton - ).should('be.disabled'); + cy.getFormFooterButtonByType(SAVE_BUTTON_TEXT, 'submit').should( + 'be.disabled' + ); // Adding data - cy.get('input#name').type(initialScheduleName); - cy.get('input#description').type(initialDescription); - cy.get('input[type="checkbox"]#enabled').check({ force: true }); + cy.getFormInputFieldById('name').type(INITIAL_SCHEDULE_NAME); + cy.getFormInputFieldById('description').type(INITIAL_DESCRIPTION); + // Check "Active" checkbox using its associated label + cy.getFormLabelByInputId('enabled').click(); // Select Action type option: 'VM Analysis' - cy.get('select#action_typ').select(actionTypeVmAnalysis); + cy.getFormSelectFieldById('action_typ').select(ACTION_TYPE_VM_ANALYSIS); // Select Filter type option: 'A Single VM' - cy.get('select#filter_typ').select(actionTypeVmAnalysis); + cy.getFormSelectFieldById('filter_typ').select(ACTION_TYPE_VM_ANALYSIS); // Select Run option: 'Hours' - cy.get('select#timer_typ').select(timerTypeHourly); + cy.getFormSelectFieldById('timer_typ').select(TIMER_TYPE_HOURLY); // Select Every option: '1 Hour' - cy.get('select#timer_value').select(frequencyTypeHour); + cy.getFormSelectFieldById('timer_value').select(FREQUENCY_TYPE_HOUR); // Select Time zone option: '(GMT-10:00) Hawaii' cy.getFormInputFieldById('time_zone').click(); cy.contains('[role="option"]', TIME_ZONE_TYPE_HAWAII).click(); @@ -120,7 +120,8 @@ function addSchedule() { alias: 'addScheduleApi', urlPattern: '/ops/schedule_edit/new?button=save', triggerFn: () => - cy.contains('#main-content .bx--btn-set button[type="submit"]', saveButton) + cy + .getFormFooterButtonByType(SAVE_BUTTON_TEXT, 'submit') .should('be.enabled') // Checks if Save button is enabled once all required fields are filled .click(), }); @@ -192,11 +193,7 @@ describe('Automate Schedule form operations: Settings > Application Settings > S cy.interceptApi({ alias: 'treeSelectApi', urlPattern: /\/ops\/tree_select\?id=.*&text=.*/, - triggerFn: () => - cy.selectAccordionItem([ - MANAGEIQ_REGION_ACCORDION_ITEM, - SCHEDULES_ACCORDION_ITEM, - ]), + triggerFn: () => cy.accordionItem(SCHEDULES_ACCORDION_ITEM), }); }); @@ -493,10 +490,10 @@ describe('Automate Schedule form operations: Settings > Application Settings > S // Open edit schedule form selectConfigMenu(EDIT_SCHEDULE_CONFIG_OPTION); // Editing name and description - cy.get('input#name').clear().type(editedScheduleName); - cy.get('input#description').clear().type(editedDescription); + cy.getFormInputFieldById('name').clear().type(EDITED_SCHEDULE_NAME); + cy.getFormInputFieldById('description').clear().type(EDITED_DESCRIPTION); // Confirms Save button is enabled after making edits - cy.contains('#main-content .bx--btn-set button[type="submit"]', saveButton) + cy.getFormFooterButtonByType(SAVE_BUTTON_TEXT, 'submit') .should('be.enabled') .click(); cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_SCHEDULE_SAVED); @@ -514,15 +511,22 @@ describe('Automate Schedule form operations: Settings > Application Settings > S // Open edit schedule form selectConfigMenu(EDIT_SCHEDULE_CONFIG_OPTION); // Editing description and start date - cy.get('input#description').clear().type(editedDescription); - cy.get('input#start_date').clear().type(editedStartDate); - cy.contains('#main-content .bx--btn-set button[type="button"]', resetButton) + cy.getFormInputFieldById('description').clear().type(EDITED_DESCRIPTION); + cy.getFormInputFieldById('start_date').clear().type(EDITED_START_DATE); + // Resetting + cy.getFormFooterButtonByType(RESET_BUTTON_TEXT) .should('be.enabled') .click(); cy.expect_flash(flashClassMap.warning, FLASH_MESSAGE_RESET_SCHEDULE); // Confirming the edited fields contain the old values after resetting - cy.get('input#description').should('have.value', initialDescription); - cy.get('input#start_date').should('have.value', initialStartDate); + cy.getFormInputFieldById('description').should( + 'have.value', + INITIAL_DESCRIPTION + ); + cy.getFormInputFieldById('start_date').should( + 'have.value', + INITIAL_START_DATE + ); /* ===== Checking whether Cancel button works ===== */ cy.getFormFooterButtonByType(CANCEL_BUTTON_TEXT).click(); From 19634ce93d01c5abe342ba1e789fa6d4b9a2e46e Mon Sep 17 00:00:00 2001 From: asirvadAbrahamVarghese Date: Fri, 22 Aug 2025 10:38:01 +0530 Subject: [PATCH 3/4] Replaced accordionItem command with selectAccordionItem command --- .../ui/Settings/Application-Settings/schedule.cy.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js index 9e347232824..6f638102569 100644 --- a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js +++ b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js @@ -144,7 +144,11 @@ function clickScheduleItem(scheduleName) { ).as('getCreatedScheduleApi'); // Triggering the action that will fire the API call, // which is selecting the created schedule - cy.accordionItem(scheduleName); + cy.selectAccordionItem([ + MANAGEIQ_REGION_ACCORDION_ITEM, + SCHEDULES_ACCORDION_ITEM, + scheduleName, + ]); // Wait for the API call to complete if it was fired // This is to ensure that the test does not fail if the request was not fired cy.then(() => { @@ -193,7 +197,11 @@ describe('Automate Schedule form operations: Settings > Application Settings > S cy.interceptApi({ alias: 'treeSelectApi', urlPattern: /\/ops\/tree_select\?id=.*&text=.*/, - triggerFn: () => cy.accordionItem(SCHEDULES_ACCORDION_ITEM), + triggerFn: () => + cy.selectAccordionItem([ + MANAGEIQ_REGION_ACCORDION_ITEM, + SCHEDULES_ACCORDION_ITEM, + ]), }); }); From 664322eee44244d73603996b846c02acdaf3889c Mon Sep 17 00:00:00 2001 From: asirvadAbrahamVarghese Date: Wed, 27 Aug 2025 19:42:10 +0530 Subject: [PATCH 4/4] Updated addSchedule method to pass down created name via return --- .../Application-Settings/schedule.cy.js | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js index 6f638102569..161d2110853 100644 --- a/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js +++ b/cypress/e2e/ui/Settings/Application-Settings/schedule.cy.js @@ -125,6 +125,9 @@ function addSchedule() { .should('be.enabled') // Checks if Save button is enabled once all required fields are filled .click(), }); + return cy.then(() => { + return INITIAL_SCHEDULE_NAME; + }); } function clickScheduleItem(scheduleName) { @@ -489,12 +492,15 @@ describe('Automate Schedule form operations: Settings > Application Settings > S it('Checking whether add, edit & delete schedule works', () => { /* ===== Adding a schedule ===== */ - addSchedule(); - cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_SCHEDULE_SAVED); + addSchedule().then((createdScheduleName) => { + // createdScheduleName value will be "Test-name" + // Assert schedule saved flash message + cy.expect_flash(flashClassMap.success, FLASH_MESSAGE_SCHEDULE_SAVED); + // Selecting the schedule and intercepting the API call to get schedule details + clickScheduleItem(createdScheduleName); + }); /* ===== Editing a schedule ===== */ - // Selecting the schedule and intercepting the API call to get schedule details - clickScheduleItem(INITIAL_SCHEDULE_NAME); // Open edit schedule form selectConfigMenu(EDIT_SCHEDULE_CONFIG_OPTION); // Editing name and description @@ -511,11 +517,13 @@ describe('Automate Schedule form operations: Settings > Application Settings > S it('Checking whether Cancel & Reset buttons work fine in the Edit form', () => { /* ===== Adding a schedule ===== */ - addSchedule(); + addSchedule().then((createdScheduleName) => { + // createdScheduleName value will be "Test-name" + // Selecting the schedule and intercepting the API call to get schedule details + clickScheduleItem(createdScheduleName); + }); /* ===== Checking whether Reset button works ===== */ - // Selecting the schedule and intercepting the API call to get schedule details - clickScheduleItem(INITIAL_SCHEDULE_NAME); // Open edit schedule form selectConfigMenu(EDIT_SCHEDULE_CONFIG_OPTION); // Editing description and start date