]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/cypress/integration/page-helper.po.ts
07d772cc2188dee08a3333871c4a28ff18d6954b
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / cypress / integration / page-helper.po.ts
1 interface Page {
2 url: string;
3 id: string;
4 }
5
6 export abstract class PageHelper {
7 pages: Record<string, Page>;
8
9 /**
10 * Decorator to be used on Helper methods to restrict access to one particular URL. This shall
11 * help developers to prevent and highlight mistakes. It also reduces boilerplate code and by
12 * thus, increases readability.
13 */
14 static restrictTo(page: string): Function {
15 return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
16 const fn: Function = descriptor.value;
17 descriptor.value = function (...args: any) {
18 cy.location('hash').should((url) => {
19 expect(url).to.eq(
20 page,
21 `Method ${target.constructor.name}::${propertyKey} is supposed to be ` +
22 `run on path "${page}", but was run on URL "${url}"`
23 );
24 });
25 fn.apply(this, args);
26 };
27 };
28 }
29
30 /**
31 * Navigates to the given page or to index.
32 * Waits until the page component is loaded
33 */
34 navigateTo(name: string = null) {
35 name = name || 'index';
36 const page = this.pages[name];
37
38 cy.visit(page.url);
39 cy.get(page.id);
40 }
41
42 /**
43 * Navigates back and waits for the hash to change
44 */
45 navigateBack() {
46 cy.location('hash').then((hash) => {
47 cy.go('back');
48 cy.location('hash').should('not.be', hash);
49 });
50 }
51
52 /**
53 * Navigates to the edit page
54 */
55 navigateEdit(name: string, select = true) {
56 if (select) {
57 this.navigateTo();
58 this.getFirstTableCell(name).click();
59 }
60 cy.contains('button', 'Edit').click();
61 this.expectBreadcrumbText('Edit');
62 }
63
64 /**
65 * Checks the active breadcrumb value.
66 */
67 expectBreadcrumbText(text: string) {
68 cy.get('.breadcrumb-item.active').should('have.text', text);
69 }
70
71 getTabText(index: number) {
72 return cy.get('.nav.nav-tabs li').its(index).text();
73 }
74
75 getTabsCount(): any {
76 return cy.get('.nav.nav-tabs li').its('length');
77 }
78
79 /**
80 * Helper method to select an option inside a select element.
81 * This method will also expect that the option was set.
82 * @param option The option text (not value) to be selected.
83 */
84 selectOption(selectionName: string, option: string) {
85 cy.get(`select[name=${selectionName}]`).select(option);
86 return this.expectSelectOption(selectionName, option);
87 }
88
89 /**
90 * Helper method to expect a set option inside a select element.
91 * @param option The selected option text (not value) that is to
92 * be expected.
93 */
94 expectSelectOption(selectionName: string, option: string) {
95 return cy.get(`select[name=${selectionName}] option:checked`).contains(option);
96 }
97
98 getLegends() {
99 return cy.get('legend');
100 }
101
102 getToast() {
103 return cy.get('.ngx-toastr');
104 }
105
106 /**
107 * Waits for the table to load its data
108 * Should be used in all methods that access the datatable
109 */
110 private waitDataTableToLoad() {
111 cy.get('cd-table').should('exist');
112 cy.get('datatable-scroller, .empty-row');
113 }
114
115 getDataTables() {
116 this.waitDataTableToLoad();
117
118 return cy.get('cd-table .dataTables_wrapper');
119 }
120
121 getTableTotalCount() {
122 this.waitDataTableToLoad();
123
124 return cy.get('.datatable-footer-inner .page-count span').then(($elem) => {
125 const text = $elem
126 .filter((_i, e) => e.innerText.includes('total'))
127 .first()
128 .text();
129
130 return Number(text.match(/(\d+)\s+total/)[1]);
131 });
132 }
133
134 getTableSelectedCount() {
135 this.waitDataTableToLoad();
136
137 return cy.get('.datatable-footer-inner .page-count span').then(($elem) => {
138 const text = $elem
139 .filter((_i, e) => e.innerText.includes('selected'))
140 .first()
141 .text();
142
143 return Number(text.match(/(\d+)\s+selected/)[1]);
144 });
145 }
146
147 getTableFoundCount() {
148 this.waitDataTableToLoad();
149
150 return cy.get('.datatable-footer-inner .page-count span').then(($elem) => {
151 const text = $elem
152 .filter((_i, e) => e.innerText.includes('found'))
153 .first()
154 .text();
155
156 return Number(text.match(/(\d+)\s+found/)[1]);
157 });
158 }
159
160 getTableRow(content: string) {
161 this.waitDataTableToLoad();
162
163 this.seachTable(content);
164 return cy.contains('.datatable-body-row', content);
165 }
166
167 getTableRows() {
168 this.waitDataTableToLoad();
169
170 return cy.get('datatable-row-wrapper');
171 }
172
173 /**
174 * Returns the first table cell.
175 * Optionally, you can specify the content of the cell.
176 */
177 getFirstTableCell(content?: string) {
178 this.waitDataTableToLoad();
179
180 if (content) {
181 this.seachTable(content);
182 return cy.contains('.datatable-body-cell-label', content);
183 } else {
184 return cy.get('.datatable-body-cell-label').first();
185 }
186 }
187
188 getExpandCollapseElement(content?: string) {
189 this.waitDataTableToLoad();
190
191 if (content) {
192 return cy.contains('.datatable-body-row', content).find('.tc_expand-collapse');
193 } else {
194 return cy.get('.tc_expand-collapse').first();
195 }
196 }
197 /**
198 * Gets column headers of table
199 */
200 getDataTableHeaders(index = 0) {
201 this.waitDataTableToLoad();
202
203 return cy.get('.datatable-header').its(index).find('.datatable-header-cell-label');
204 }
205
206 /**
207 * Grabs striped tables
208 */
209 getStatusTables() {
210 return cy.get('.table.table-striped');
211 }
212
213 filterTable(name: string, option: string) {
214 this.waitDataTableToLoad();
215
216 cy.get('.tc_filter_name > a').click();
217 cy.contains(`.tc_filter_name .dropdown-item`, name).click();
218
219 cy.get('.tc_filter_option > a').click();
220 cy.contains(`.tc_filter_option .dropdown-item`, option).click();
221 }
222
223 seachTable(text: string) {
224 this.waitDataTableToLoad();
225
226 cy.get('cd-table .dataTables_paginate input').first().clear().type('10');
227 cy.get('cd-table .search input').first().clear().type(text);
228 }
229
230 clearTableSearchInput() {
231 this.waitDataTableToLoad();
232
233 return cy.get('cd-table .search button').click();
234 }
235
236 /**
237 * This is a generic method to delete table rows.
238 * It will select the first row that contains the provided name and delete it.
239 * After that it will wait until the row is no longer displayed.
240 */
241 delete(name: string) {
242 // Selects row
243 this.getFirstTableCell(name).click();
244
245 // Clicks on table Delete button
246 cy.get('.table-actions button.dropdown-toggle').first().click(); // open submenu
247 cy.get('li.delete a').click(); // click on "delete" menu item
248
249 // Confirms deletion
250 cy.get('.custom-control-label').click();
251 cy.contains('button', 'Delete').click();
252
253 // Wait for modal to close
254 cy.get('cd-modal').should('not.exist');
255
256 // Waits for item to be removed from table
257 this.getFirstTableCell(name).should('not.exist');
258 }
259 }