Skip to content

Commit 46fb33c

Browse files
Added automated tests with cypress for Schedule form under Application-Settings
1 parent 19686b9 commit 46fb33c

File tree

2 files changed

+343
-1
lines changed

2 files changed

+343
-1
lines changed
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
/* eslint-disable no-undef */
2+
3+
function selectConfigMenu(configuration = 'Add a new Schedule') {
4+
cy.get('#miq_schedule_vmdb_choice').click();
5+
cy.get(`ul[aria-label="Configuration"] [title="${configuration}"]`).click();
6+
}
7+
8+
function addSchedule() {
9+
selectConfigMenu();
10+
// Checks if Save button is disabled initially
11+
cy.contains(
12+
'#main-content .bx--btn-set button[type="submit"]',
13+
'Save'
14+
).should('be.disabled');
15+
// Adding data
16+
cy.get('input#name').type('Test name');
17+
cy.get('input#description').type('Test description');
18+
cy.get('input[type="checkbox"]#enabled').check({ force: true });
19+
cy.get('select#action_typ').select('VM Analysis');
20+
cy.get('select#filter_typ').select('A single VM');
21+
cy.get('select#timer_typ').select('Hourly');
22+
cy.get('select#timer_value').select('1 Hour');
23+
cy.get('input[role="combobox"]#time_zone').click();
24+
cy.contains('[role="option"]', '(GMT-10:00) Hawaii')
25+
.should('be.visible')
26+
.click();
27+
cy.get('input#start_date').type('06/30/2025');
28+
cy.get('input#start_time').type('11:23');
29+
// Checks if Save button is enabled once all required fields are filled
30+
cy.contains('#main-content .bx--btn-set button[type="submit"]', 'Save')
31+
.should('be.enabled')
32+
.click();
33+
}
34+
35+
function deleteSchedule(scheduleName = 'Test name') {
36+
// Selecting the schedule
37+
cy.contains('li.list-group-item', scheduleName).click();
38+
cy.on('window:confirm', (text) => {
39+
expect(text).to.eq(
40+
'Warning: This Schedule and ALL of its components will be permanently removed!'
41+
);
42+
return true;
43+
});
44+
selectConfigMenu('Delete this Schedule from the Database');
45+
cy.get('#main_div #flash_msg_div .alert-success').contains(
46+
`Schedule "${scheduleName}": Delete successful`
47+
);
48+
}
49+
50+
function invokeCleanupDeletion() {
51+
// Iterate and clean up any leftover schedules created during the test
52+
cy.get('li.list-group-item').each(($el) => {
53+
const text = $el?.text()?.trim();
54+
if (text === 'Test name') {
55+
deleteSchedule();
56+
return false;
57+
}
58+
if (text === 'Dummy name') {
59+
deleteSchedule('Dummy name');
60+
return false;
61+
}
62+
return true;
63+
});
64+
}
65+
66+
function verifyFilterTypeDropdownExists() {
67+
cy.get('label[for="filter_typ"]').should('exist');
68+
cy.get('select#filter_typ').should('exist');
69+
}
70+
71+
function verifyTimerDropdownExists() {
72+
cy.get('label[for="timer_value"]').should('exist');
73+
cy.get('select#timer_value').should('exist');
74+
}
75+
76+
describe('Automate Schedule form operations: Settings > Application Settings > Settings > Schedules > Configuration > Add a new schedule', () => {
77+
beforeEach(() => {
78+
cy.login();
79+
cy.menu(settingsMenuOption, appSettingsMenuOption);
80+
cy.intercept('POST', '/ops/tree_select?id=xx-msc&text=Schedules').as(
81+
'getSchedules'
82+
);
83+
cy.get('[title="Schedules"]').click();
84+
cy.wait('@getSchedules');
85+
});
86+
87+
it('Validate visibility of elements based on dropdown selections', () => {
88+
selectConfigMenu();
89+
90+
/* ===== Selecting any option other than "Automation Tasks" from "Action" dropdown does not hide the Filter dropdown ===== */
91+
92+
cy.get('select#action_typ').select('VM Analysis');
93+
cy.get('select#action_typ').should('have.value', 'vm');
94+
// Checking for Filter type dropdown
95+
cy.get('label[for="filter_typ"]').should('exist');
96+
cy.get('select#filter_typ').should('exist');
97+
98+
cy.get('select#action_typ').select('Template Analysis');
99+
cy.get('select#action_typ').should('have.value', 'miq_template');
100+
// Checking for Filter type dropdown
101+
cy.get('label[for="filter_typ"]').should('exist');
102+
cy.get('select#filter_typ').should('exist');
103+
104+
cy.get('select#action_typ').select('Host Analysis');
105+
cy.get('select#action_typ').should('have.value', 'host');
106+
// Checking for Filter type dropdown
107+
cy.get('label[for="filter_typ"]').should('exist');
108+
cy.get('select#filter_typ').should('exist');
109+
110+
cy.get('select#action_typ').select('Container Image Analysis');
111+
cy.get('select#action_typ').should('have.value', 'container_image');
112+
// Checking for Filter type dropdown
113+
cy.get('label[for="filter_typ"]').should('exist');
114+
cy.get('select#filter_typ').should('exist');
115+
116+
cy.get('select#action_typ').select('Cluster Analysis');
117+
cy.get('select#action_typ').should('have.value', 'emscluster');
118+
// Checking for Filter type dropdown
119+
cy.get('label[for="filter_typ"]').should('exist');
120+
cy.get('select#filter_typ').should('exist');
121+
122+
cy.get('select#action_typ').select('Datastore Analysis');
123+
cy.get('select#action_typ').should('have.value', 'storage');
124+
// Checking for Filter type dropdown
125+
cy.get('label[for="filter_typ"]').should('exist');
126+
cy.get('select#filter_typ').should('exist');
127+
128+
cy.get('select#action_typ').select('VM Compliance Check');
129+
cy.get('select#action_typ').should('have.value', 'vm_check_compliance');
130+
// Checking for Filter type dropdown
131+
cy.get('label[for="filter_typ"]').should('exist');
132+
cy.get('select#filter_typ').should('exist');
133+
134+
cy.get('select#action_typ').select('Host Compliance Check');
135+
cy.get('select#action_typ').should('have.value', 'host_check_compliance');
136+
// Checking for Filter type dropdown
137+
cy.get('label[for="filter_typ"]').should('exist');
138+
cy.get('select#filter_typ').should('exist');
139+
140+
cy.get('select#action_typ').select('Container Image Compliance Check');
141+
cy.get('select#action_typ').should(
142+
'have.value',
143+
'container_image_check_compliance'
144+
);
145+
// Checking for Filter type dropdown
146+
cy.get('label[for="filter_typ"]').should('exist');
147+
cy.get('select#filter_typ').should('exist');
148+
149+
/* ===== Selecting "Automation Tasks" option from "Action" dropdown shows Zone, Object details & Object fields ===== */
150+
151+
cy.get('select#action_typ').select('Automation Tasks');
152+
cy.get('select#action_typ').should('have.value', 'automation_request');
153+
154+
// Checking for Zone dropdown
155+
cy.get('label[for="zone_id"]').should('exist');
156+
cy.get('select#zone_id').should('exist');
157+
158+
// Checking for Object Details
159+
cy.get('h3[name="object_details"]').should('exist');
160+
// Checking for System/Process dropdown
161+
cy.get('label[for="instance_name"]').should('exist');
162+
cy.get('select#instance_name').should('exist');
163+
// Checking for Messsage textfield
164+
cy.get('label[for="message"]').should('exist');
165+
cy.get('input#message').should('exist');
166+
// Checking for Request textfield
167+
cy.get('label[for="request"]').should('exist');
168+
cy.get('input#request').should('exist');
169+
170+
// Checking for Object
171+
cy.get('h3[name="object_attributes"]').should('exist');
172+
// Checking for Type Combobox
173+
cy.get('label[for="target_class"]').should('exist');
174+
cy.get('input[role="combobox"]#target_class').should('exist');
175+
// Checking for Object Combobox
176+
cy.get('label[for="target_id"]').should('exist');
177+
cy.get('input[role="combobox"]#target_id').should('exist');
178+
179+
// Checking for Attribute/Value pairs
180+
cy.contains('h3', 'Attribute/Value Pairs').should('exist');
181+
// Checking for 5 attribute-value pairs text fields
182+
cy.get('input#attribute_1').should('exist');
183+
cy.get('input#value_1').should('exist');
184+
cy.get('input#attribute_2').should('exist');
185+
cy.get('input#value_2').should('exist');
186+
cy.get('input#attribute_3').should('exist');
187+
cy.get('input#value_3').should('exist');
188+
cy.get('input#attribute_4').should('exist');
189+
cy.get('input#value_4').should('exist');
190+
cy.get('input#attribute_5').should('exist');
191+
cy.get('input#value_5').should('exist');
192+
193+
/* ===== Selecting "Once" option from "Run" dropdown does not show the "Every" dropdown ===== */
194+
195+
cy.get('select#timer_typ').select('Once');
196+
// Checking whether the Every dropdown is hidden
197+
cy.get('input#timer_value').should('not.exist');
198+
199+
/* ===== Selecting any other option other than "Once" from "Run" dropdown shows the "Every" dropdown ===== */
200+
201+
cy.get('select#timer_typ').select('Hours');
202+
// Checking whether the "Every" dropdown exist
203+
cy.get('label[for="timer_value"]').should('exist');
204+
cy.get('select#timer_value').should('exist');
205+
206+
cy.get('select#timer_typ').select('Days');
207+
// Checking whether the "Every" dropdown exist
208+
cy.get('label[for="timer_value"]').should('exist');
209+
cy.get('select#timer_value').should('exist');
210+
211+
cy.get('select#timer_typ').select('Weeks');
212+
// Checking whether the "Every" dropdown exist
213+
cy.get('label[for="timer_value"]').should('exist');
214+
cy.get('select#timer_value').should('exist');
215+
216+
cy.get('select#timer_typ').select('Months');
217+
// Checking whether the "Every" dropdown exist
218+
cy.get('label[for="timer_value"]').should('exist');
219+
cy.get('select#timer_value').should('exist');
220+
});
221+
222+
it('Checking whether Cancel button works on the Add form', () => {
223+
selectConfigMenu();
224+
cy.contains('#main-content .bx--btn-set button[type="button"]', 'Cancel')
225+
.should('be.enabled')
226+
.click();
227+
cy.get('#main_div #flash_msg_div .alert-success').contains(
228+
'Add was cancelled by the user'
229+
);
230+
});
231+
232+
it('Checking whether add, edit & delete schedule works', () => {
233+
/* ===== Adding a schedule ===== */
234+
addSchedule();
235+
cy.get('#main_div #flash_msg_div .alert-success').contains(
236+
'Schedule "Test name" was saved'
237+
);
238+
239+
/* ===== Editing a schedule ===== */
240+
// Selecting the created schedule
241+
cy.contains('li.list-group-item', 'Test name').click();
242+
selectConfigMenu('Edit this Schedule');
243+
// Editing name and description
244+
cy.get('input#name').clear().type('Dummy name');
245+
cy.get('input#description').clear().type('Dummy description');
246+
// Confirms Save button is enabled after making edits
247+
cy.contains('#main-content .bx--btn-set button[type="submit"]', 'Save')
248+
.should('be.enabled')
249+
.click();
250+
cy.get('#main_div #flash_msg_div .alert-success').contains(
251+
'Schedule "Dummy name" was saved'
252+
);
253+
254+
/* ===== Delete is already handled from afterEach hook ===== */
255+
});
256+
257+
it('Checking whether Cancel & Reset buttons work fine in the Edit form', () => {
258+
/* ===== Adding a schedule ===== */
259+
addSchedule();
260+
261+
/* ===== Checking whether Cancel button works ===== */
262+
// Selecting the created schedule
263+
cy.contains('li.list-group-item', 'Test name').click();
264+
selectConfigMenu('Edit this Schedule');
265+
cy.contains('#main-content .bx--btn-set button[type="button"]', 'Cancel')
266+
.should('be.enabled')
267+
.click();
268+
cy.get('#main_div #flash_msg_div .alert-success').contains(
269+
'Edit of "Test name" was cancelled by the user'
270+
);
271+
272+
/* ===== Checking whether Reset button works ===== */
273+
// Selecting the created schedule
274+
cy.contains('li.list-group-item', 'Test name').click();
275+
selectConfigMenu('Edit this Schedule');
276+
// Editing description and start date
277+
cy.get('input#description').clear().type('Dummy description');
278+
cy.get('input#start_date').clear().type('07/21/2025');
279+
cy.contains('#main-content .bx--btn-set button[type="button"]', 'Reset')
280+
.should('be.enabled')
281+
.click();
282+
cy.get('#main_div #flash_msg_div .alert-warning').contains(
283+
'All changes have been reset'
284+
);
285+
// Confirming the edited fields contain the old values after resetting
286+
cy.get('input#description').should('have.value', 'Test description');
287+
cy.get('input#start_date').should('have.value', '06/30/2025');
288+
289+
// Selecting Schedules menu item to bypass a bug, can be removed once #9505 is merged
290+
cy.get('[title="Schedules"]').click();
291+
});
292+
293+
it('Checking whether creating a duplicate record is restricted', () => {
294+
/* ===== Adding schedule ===== */
295+
addSchedule();
296+
297+
/* ===== Trying to add the same schedule again ===== */
298+
addSchedule();
299+
cy.get('#main_div #flash_msg_div .alert-danger').contains(
300+
'Error when adding a new schedule: Validation failed: MiqSchedule: Name has already been taken'
301+
);
302+
});
303+
304+
it('Checking whether Disabling, Enabling & Queueing up the schedule works', () => {
305+
/* ===== Adding a schedule ===== */
306+
addSchedule();
307+
// Selecting the created schedule
308+
cy.contains('li.list-group-item', 'Test name').click();
309+
310+
/* ===== Disabling the schedule ===== */
311+
selectConfigMenu('Disable this Schedule');
312+
cy.get('#main_div #flash_msg_div .alert-info').contains(
313+
'The selected Schedules were disabled'
314+
);
315+
316+
/* ===== Enabling the schedule ===== */
317+
selectConfigMenu('Enable this Schedule');
318+
cy.get('#main_div #flash_msg_div .alert-info').contains(
319+
'The selected Schedules were enabled'
320+
);
321+
322+
/* ===== Queueing-up the schedule ===== */
323+
selectConfigMenu('Queue up this Schedule to run now');
324+
cy.get('#main_div #flash_msg_div .alert-success').contains(
325+
'The selected Schedule has been queued to run'
326+
);
327+
});
328+
329+
afterEach(() => {
330+
cy?.url()?.then((url) => {
331+
// Ensures navigation to Settings -> Application-Settings in the UI
332+
if (url?.includes('/ops/explorer')) {
333+
invokeCleanupDeletion();
334+
} else {
335+
// Navigate to Settings -> Application-Settings before looking out for Schedules created during test
336+
cy.menu('Settings', 'Application Settings');
337+
invokeCleanupDeletion();
338+
}
339+
});
340+
});
341+
});

cypress/support/e2e.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ import './assertions/expect_text.js'
5959
// Network and aborted errors are exlusive to firefox when cypress navigates to a new page before the api calls for the last page are fullly loaded
6060
Cypress.on('uncaught:exception', (err, runnable) => {
6161
console.log(err.message);
62-
if (err.message.includes(`Cannot read properties of undefined (reading 'received')`) || // Error handler for Chrome
62+
if (err.message.includes(`Cannot read properties of undefined (reading 'received')`) || // Error handler for Chrome
63+
err.message.includes(`Cannot read properties of undefined (reading '0')`) || // Error handler for Chrome
6364
err.message.includes('subscription is undefined') || // Error handler for Firefox
6465
err.message.includes('NetworkError when attempting to fetch resource.') || // Error handler for Firefox
6566
err.message.includes('The operation was aborted.')) // Error handler for Firefox

0 commit comments

Comments
 (0)