@anddone/coretestautomation 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/npm-release.yml +102 -0
- package/dist/api/base.api.d.ts +32 -0
- package/dist/api/base.api.d.ts.map +1 -0
- package/dist/api/base.api.js +7 -0
- package/dist/api/base.api.js.map +1 -0
- package/dist/api/headers.d.ts +6 -0
- package/dist/api/headers.d.ts.map +1 -0
- package/dist/api/headers.js +23 -0
- package/dist/api/headers.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/pages/basepage.d.ts +6 -0
- package/dist/pages/basepage.d.ts.map +1 -0
- package/dist/pages/basepage.js +10 -0
- package/dist/pages/basepage.js.map +1 -0
- package/dist/testData/api.data.json +6 -0
- package/dist/utils/apiUtils.d.ts +123 -0
- package/dist/utils/apiUtils.d.ts.map +1 -0
- package/dist/utils/apiUtils.js +264 -0
- package/dist/utils/apiUtils.js.map +1 -0
- package/dist/utils/assertionUtils.d.ts +223 -0
- package/dist/utils/assertionUtils.d.ts.map +1 -0
- package/dist/utils/assertionUtils.js +400 -0
- package/dist/utils/assertionUtils.js.map +1 -0
- package/dist/utils/commonUtils.d.ts +590 -0
- package/dist/utils/commonUtils.d.ts.map +1 -0
- package/dist/utils/commonUtils.js +1292 -0
- package/dist/utils/commonUtils.js.map +1 -0
- package/dist/utils/fakerStaticData.d.ts +16 -0
- package/dist/utils/fakerStaticData.d.ts.map +1 -0
- package/dist/utils/fakerStaticData.js +88 -0
- package/dist/utils/fakerStaticData.js.map +1 -0
- package/dist/utils/fileCommonUtils.d.ts +22 -0
- package/dist/utils/fileCommonUtils.d.ts.map +1 -0
- package/dist/utils/fileCommonUtils.js +243 -0
- package/dist/utils/fileCommonUtils.js.map +1 -0
- package/dist/utils/generationUtils.d.ts +424 -0
- package/dist/utils/generationUtils.d.ts.map +1 -0
- package/dist/utils/generationUtils.js +869 -0
- package/dist/utils/generationUtils.js.map +1 -0
- package/dist/utils/pageUtils.d.ts +90 -0
- package/dist/utils/pageUtils.d.ts.map +1 -0
- package/dist/utils/pageUtils.js +214 -0
- package/dist/utils/pageUtils.js.map +1 -0
- package/dist/utils/tableUtils.d.ts +304 -0
- package/dist/utils/tableUtils.d.ts.map +1 -0
- package/dist/utils/tableUtils.js +555 -0
- package/dist/utils/tableUtils.js.map +1 -0
- package/dist/utils/validationUtils.d.ts +80 -0
- package/dist/utils/validationUtils.d.ts.map +1 -0
- package/dist/utils/validationUtils.js +172 -0
- package/dist/utils/validationUtils.js.map +1 -0
- package/package.json +23 -0
- package/playwright.config.ts +79 -0
- package/src/api/base.api.ts +39 -0
- package/src/api/headers.ts +17 -0
- package/src/index.ts +12 -0
- package/src/pages/basepage.ts +11 -0
- package/src/testData/api.data.json +6 -0
- package/src/types/pdf-parse.d.ts +6 -0
- package/src/utils/apiUtils.ts +307 -0
- package/src/utils/assertionUtils.ts +455 -0
- package/src/utils/commonUtils.ts +1544 -0
- package/src/utils/fakerStaticData.ts +91 -0
- package/src/utils/fileCommonUtils.ts +239 -0
- package/src/utils/generationUtils.ts +929 -0
- package/src/utils/pageUtils.ts +224 -0
- package/src/utils/tableUtils.ts +715 -0
- package/src/utils/validationUtils.ts +179 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
import type { Locator } from '@playwright/test';
|
|
2
|
+
import { CommonUtils } from './commonUtils';
|
|
3
|
+
|
|
4
|
+
export type TableOptions = {
|
|
5
|
+
headerExpression?: string;
|
|
6
|
+
rowLocator?: string;
|
|
7
|
+
cellLocator?: string;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
ellipsisLocator?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
dateInputLocator?: string;
|
|
12
|
+
inputLocator?: string;
|
|
13
|
+
clearButtonLocator?: Locator;
|
|
14
|
+
applyButtonLocator?: Locator;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class TableUtils extends CommonUtils {
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Resolves options by applying defaults.
|
|
21
|
+
*
|
|
22
|
+
* @param options - User-provided options
|
|
23
|
+
* @param defaults - Default values for the options
|
|
24
|
+
* @returns Complete options object with defaults applied
|
|
25
|
+
*/
|
|
26
|
+
private static resolveTableOptions<T extends object>(options: Partial<T> = {}, defaults: T): T {
|
|
27
|
+
return { ...defaults, ...options };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Gets the text values of table headers.
|
|
32
|
+
*
|
|
33
|
+
* @param table - Locator of the table element
|
|
34
|
+
* @param options - Optional configuration for header locators and timeout
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const headers = await CommonUtils.getTableHeaders(table);
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const headers = await CommonUtils.getTableHeaders(table, {
|
|
41
|
+
* headerExpression: 'thead tr th',
|
|
42
|
+
* timeout: 5000
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* @returns Array of trimmed header texts, or empty array if not found
|
|
46
|
+
*/
|
|
47
|
+
static async getTableHeaders(table: Locator, options: TableOptions = {}
|
|
48
|
+
): Promise<string[]> {
|
|
49
|
+
|
|
50
|
+
const { headerExpression = 'tr th', timeout = 15000
|
|
51
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const headers = table.locator(headerExpression);
|
|
55
|
+
await this.waitForVisible(headers.first(), { timeout });
|
|
56
|
+
|
|
57
|
+
const count = await headers.count();
|
|
58
|
+
const results: string[] = [];
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < count; i++) {
|
|
61
|
+
results.push((await headers.nth(i).innerText()).trim());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return results;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.warn('⚠ Unable to get table headers:', (error as Error).message);
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Returns the zero-based index of a column based on the column header name.
|
|
73
|
+
*
|
|
74
|
+
* If the column header is not found or an error occurs, `-1` is returned.
|
|
75
|
+
* @param table - Locator pointing to the table element
|
|
76
|
+
* @param columnName - Visible header text to search for
|
|
77
|
+
* @param options - Optional configuration for header locators and timeout
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* const headers = await CommonUtils.getColumnIndex(table,'columnName');
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const headers = await CommonUtils.getColumnIndex(table,
|
|
84
|
+
* 'columnName',{ headerExpression: 'thead tr th',
|
|
85
|
+
* timeout: 5000
|
|
86
|
+
* });
|
|
87
|
+
* @returns Promise<number> - Zero-based column index if found, otherwise -1
|
|
88
|
+
*/
|
|
89
|
+
static async getColumnIndex(table: Locator, columnName: string, options: TableOptions = {}): Promise<number> {
|
|
90
|
+
const { headerExpression = "tr th" } = this.resolveTableOptions<TableOptions>(options, {});
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const headers = table.locator(headerExpression);
|
|
94
|
+
await this.waitForVisible(headers.first());
|
|
95
|
+
|
|
96
|
+
const count = await headers.count();
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < count; i++) {
|
|
99
|
+
const header = headers.nth(i);
|
|
100
|
+
|
|
101
|
+
const headerText = (await header.innerText()).trim();
|
|
102
|
+
|
|
103
|
+
if (headerText === columnName.trim()) {
|
|
104
|
+
return i;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return -1;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return -1;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Gets the text value of a specific cell by row and column index.
|
|
116
|
+
*
|
|
117
|
+
* @param table - Locator representing the table
|
|
118
|
+
* @param rowIndex - 1 - based index of the row
|
|
119
|
+
* @param columnIndex - 0 -based index of the column
|
|
120
|
+
* @param options - Optional table settings
|
|
121
|
+
* @param options.rowLocator - Locator for table rows (default: '//tr[contains(@class,"row")]')
|
|
122
|
+
* @param options.cellLocator - Locator for table cells (default: 'td')
|
|
123
|
+
* @param options.timeout - Maximum wait time for elements (default: 15000)
|
|
124
|
+
*
|
|
125
|
+
* @returns Cell value as string or empty string if not found
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* const value = await CommonUtils.getCellValueByIndex(table, 2, 1);
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* const value = await CommonUtils.getCellValueByIndex(table, 2, 1, {
|
|
132
|
+
* rowLocator: '//tbody/tr',
|
|
133
|
+
* cellLocator: 'td',
|
|
134
|
+
* timeout: 8000
|
|
135
|
+
* });
|
|
136
|
+
*/
|
|
137
|
+
static async getCellValueByIndex(table: Locator, rowIndex: number, columnIndex: number,
|
|
138
|
+
options: TableOptions = {}
|
|
139
|
+
): Promise<string> {
|
|
140
|
+
|
|
141
|
+
const {
|
|
142
|
+
rowLocator = '//tr[contains(@class,"row")]',
|
|
143
|
+
cellLocator = 'td',
|
|
144
|
+
timeout = 15000
|
|
145
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
if (rowIndex < 1) {
|
|
149
|
+
console.error(`Row index must be >= 1. Received: ${rowIndex}`);
|
|
150
|
+
return '';
|
|
151
|
+
}
|
|
152
|
+
if (columnIndex < 0) {
|
|
153
|
+
console.error(`Column index must be >= 0. Received: ${columnIndex}`);
|
|
154
|
+
return '';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const rows = table.locator(rowLocator);
|
|
158
|
+
await this.waitForVisible(rows.first(), { timeout });
|
|
159
|
+
|
|
160
|
+
const rowCount = await rows.count();
|
|
161
|
+
if (rowIndex > rowCount) {
|
|
162
|
+
console.error(`Row index ${rowIndex} exceeds total rows ${rowCount}`);
|
|
163
|
+
return '';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const row = rows.nth(rowIndex - 1);
|
|
167
|
+
const cells = row.locator(cellLocator);
|
|
168
|
+
|
|
169
|
+
const cellCount = await cells.count();
|
|
170
|
+
if (columnIndex >= cellCount) {
|
|
171
|
+
console.error(`Column index ${columnIndex} exceeds total columns ${cellCount}`);
|
|
172
|
+
return '';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const cell = cells.nth(columnIndex);
|
|
176
|
+
const value = (await cell.innerText()).trim();
|
|
177
|
+
|
|
178
|
+
return value;
|
|
179
|
+
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error(
|
|
182
|
+
`⚠ Failed to get cell value at row ${rowIndex}, column ${columnIndex}: ${(error as Error).message}`
|
|
183
|
+
);
|
|
184
|
+
return '';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Retrieves all cell values from a specific column of a table using a zero-based column index.
|
|
191
|
+
*
|
|
192
|
+
* If the column index is invalid (< 0), or if an error occurs,
|
|
193
|
+
* an empty array is returned.
|
|
194
|
+
*
|
|
195
|
+
* @param table - Locator pointing to the table element
|
|
196
|
+
* @param columnIndex - Zero-based index of the column
|
|
197
|
+
* @param options - Optional table settings
|
|
198
|
+
* @param options.rowLocator - Selector for table rows (default: '//tr[contains(@class,"row")]')
|
|
199
|
+
* @param options.cellLocator - Selector for cells inside a row (default: 'td')
|
|
200
|
+
* @param options.timeout - Maximum wait time for the elements (default: 15000)
|
|
201
|
+
*
|
|
202
|
+
* @returns Promise<string[]> - Array of cell values from the specified column
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* const values = await CommonUtils.getColumnValuesByIndex(table, 1);
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* const values = await CommonUtils.getColumnValuesByIndex(table, 2, {
|
|
209
|
+
* rowLocator: '//tbody/tr',
|
|
210
|
+
* cellLocator: 'td',
|
|
211
|
+
* timeout: 8000
|
|
212
|
+
* });
|
|
213
|
+
*/
|
|
214
|
+
static async getColumnValuesByIndex(table: Locator, columnIndex: number,
|
|
215
|
+
options: TableOptions = {}
|
|
216
|
+
): Promise<string[]> {
|
|
217
|
+
|
|
218
|
+
const {
|
|
219
|
+
rowLocator = '//tr[contains(@class,"row")]',
|
|
220
|
+
cellLocator = 'td',
|
|
221
|
+
timeout = 15000
|
|
222
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
223
|
+
|
|
224
|
+
const values: string[] = [];
|
|
225
|
+
|
|
226
|
+
if (columnIndex < 0) return values;
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
const rows = table.locator(rowLocator);
|
|
230
|
+
await this.waitForVisible(rows.first(), { timeout });
|
|
231
|
+
const rowCount = await rows.count();
|
|
232
|
+
|
|
233
|
+
for (let i = 0; i < rowCount; i++) {
|
|
234
|
+
const row = rows.nth(i);
|
|
235
|
+
const cells = row.locator(cellLocator);
|
|
236
|
+
|
|
237
|
+
const cellCount = await cells.count();
|
|
238
|
+
if (cellCount <= columnIndex) continue;
|
|
239
|
+
|
|
240
|
+
const cell = cells.nth(columnIndex);
|
|
241
|
+
const value = (await cell.innerText()).trim();
|
|
242
|
+
values.push(value);
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.warn(`⚠ Failed to get column values for column index ${columnIndex}: ${(error as Error).message}`);
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return values;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Returns all cell values from a table for the given column header.
|
|
255
|
+
*
|
|
256
|
+
* If the header is not found, an empty array is returned.
|
|
257
|
+
*
|
|
258
|
+
* @param table - Locator for the table element
|
|
259
|
+
* @param columnName - Exact column header text to search
|
|
260
|
+
* @param options - Optional table settings
|
|
261
|
+
* @param options.headerExpression - Locator for headers (default: 'tr th')
|
|
262
|
+
* @param options.rowLocator - Locator for rows (default: '//tr[contains(@class,"row")]')
|
|
263
|
+
* @param options.cellLocator - Locator for cells (default: 'td')
|
|
264
|
+
* @param options.timeout - Maximum wait time for elements (default: 15000)
|
|
265
|
+
*
|
|
266
|
+
* @returns Promise<string[]> - Array of cell values under the specified column
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* const values = await CommonUtils.getColumnValuesByHeader(table, 'Name');
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* const values = await CommonUtils.getColumnValuesByHeader(table, 'Name', {
|
|
273
|
+
* headerExpression: 'thead tr th',
|
|
274
|
+
* rowLocator: '//tbody/tr',
|
|
275
|
+
* cellLocator: 'td',
|
|
276
|
+
* timeout: 8000
|
|
277
|
+
* });
|
|
278
|
+
*/
|
|
279
|
+
static async getColumnValuesByHeader(table: Locator, columnName: string,
|
|
280
|
+
options: TableOptions = {}
|
|
281
|
+
): Promise<string[]> {
|
|
282
|
+
|
|
283
|
+
const {
|
|
284
|
+
headerExpression = 'tr th',
|
|
285
|
+
rowLocator = '//tr[contains(@class,"row")]',
|
|
286
|
+
cellLocator = 'td',
|
|
287
|
+
timeout = 15000
|
|
288
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
// Get the column index for the header
|
|
292
|
+
const columnIndex = await this.getColumnIndex(table, columnName, { headerExpression, timeout });
|
|
293
|
+
|
|
294
|
+
if (columnIndex === -1) {
|
|
295
|
+
console.error(`⚠ Column header not found: "${columnName}"`);
|
|
296
|
+
return [];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Return all cell values from that column
|
|
300
|
+
return await this.getColumnValuesByIndex(table, columnIndex, { rowLocator, cellLocator, timeout });
|
|
301
|
+
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error(`⚠ Failed to get column values for header "${columnName}": ${(error as Error).message}`);
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Clicks a table row based on its row index (1-based).
|
|
310
|
+
*
|
|
311
|
+
* The row index is **1-based** for ease of use:
|
|
312
|
+
* - 1 → first row
|
|
313
|
+
* - 2 → second row
|
|
314
|
+
*
|
|
315
|
+
* If the index is invalid or out of range, an error is logged
|
|
316
|
+
* and the action is safely skipped.
|
|
317
|
+
*
|
|
318
|
+
* @param page - Playwright Page object
|
|
319
|
+
* @param table - Locator pointing to the table element
|
|
320
|
+
* @param rowIndex - Row index to click on (1-based)
|
|
321
|
+
* @param options - Optional table settings
|
|
322
|
+
* @param options.rowLocator - Selector used to locate rows (default: '//tr[contains(@class,"row")]')
|
|
323
|
+
* @param options.timeout - Maximum wait time for elements (default: 15000)
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* await CommonUtils.clickOnTableRowByIndex(page, table, 1);
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* await CommonUtils.clickOnTableRowByIndex(page, table, 2, {
|
|
330
|
+
* rowLocator: '//tbody/tr',
|
|
331
|
+
* timeout: 8000
|
|
332
|
+
* });
|
|
333
|
+
*/
|
|
334
|
+
static async clickOnTableRowByIndex(table: Locator, rowIndex: number,
|
|
335
|
+
options: TableOptions = {}
|
|
336
|
+
): Promise<void> {
|
|
337
|
+
|
|
338
|
+
const {
|
|
339
|
+
rowLocator = '//tr[contains(@class,"row")]',
|
|
340
|
+
timeout = 15000
|
|
341
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
if (rowIndex < 1) {
|
|
345
|
+
console.error(`⚠ Row index must be >= 1. Received: ${rowIndex}`);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const rows = table.locator(rowLocator);
|
|
350
|
+
await this.waitForVisible(rows.first(), { timeout });
|
|
351
|
+
|
|
352
|
+
const rowCount = await rows.count();
|
|
353
|
+
if (rowIndex > rowCount) {
|
|
354
|
+
console.error(`⚠ Row index ${rowIndex} is out of range. Total rows available: ${rowCount}`);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const row = rows.nth(rowIndex - 1);
|
|
359
|
+
await this.click(row, { timeout });
|
|
360
|
+
|
|
361
|
+
} catch (error) {
|
|
362
|
+
console.error(`⚠ Failed to click table row at index ${rowIndex}: ${(error as Error).message}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Clicks a table column header based on the given column name.
|
|
368
|
+
*
|
|
369
|
+
* @param table - Locator pointing to the table element
|
|
370
|
+
* @param columnName - Visible column header name to click
|
|
371
|
+
* @param options - Optional table settings
|
|
372
|
+
* @param options.headerExpression - Locator expression for table headers
|
|
373
|
+
* (default: 'tr th button')
|
|
374
|
+
* @param options.timeout - Maximum wait time for elements (default: 15000)
|
|
375
|
+
*
|
|
376
|
+
* @returns Locator of the clicked header or null if not found
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* await CommonUtils.clickOnTableColumnHeader(table, 'Name');
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
* await CommonUtils.clickOnTableColumnHeader(table, 'Amount', {
|
|
383
|
+
* headerExpression: 'thead tr th',
|
|
384
|
+
* timeout: 8000
|
|
385
|
+
* });
|
|
386
|
+
*/
|
|
387
|
+
static async clickOnTableColumnHeader(table: Locator, columnName: string,
|
|
388
|
+
options: TableOptions = {}
|
|
389
|
+
): Promise<Locator | null> {
|
|
390
|
+
|
|
391
|
+
const {
|
|
392
|
+
headerExpression = 'tr th button',
|
|
393
|
+
timeout = 15000
|
|
394
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
395
|
+
|
|
396
|
+
try {
|
|
397
|
+
if (!columnName || columnName.trim() === '') {
|
|
398
|
+
console.error('⚠ Column name must be a non-empty string');
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const headers = table.locator(headerExpression);
|
|
403
|
+
await this.waitForVisible(headers.first(), { timeout });
|
|
404
|
+
|
|
405
|
+
const count = await headers.count();
|
|
406
|
+
|
|
407
|
+
for (let i = 0; i < count; i++) {
|
|
408
|
+
const header = headers.nth(i);
|
|
409
|
+
const text = (await header.innerText())
|
|
410
|
+
.replace(/\s+/g, ' ')
|
|
411
|
+
.replace(/\u00A0/g, ' ')
|
|
412
|
+
.trim();
|
|
413
|
+
|
|
414
|
+
if (text.toLowerCase().includes(columnName.toLowerCase())) {
|
|
415
|
+
await header.scrollIntoViewIfNeeded();
|
|
416
|
+
await this.click(header, { timeout });
|
|
417
|
+
return header;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
console.error(`⚠ Column header "${columnName}" not found`);
|
|
422
|
+
return null;
|
|
423
|
+
|
|
424
|
+
} catch (error) {
|
|
425
|
+
console.error(
|
|
426
|
+
`⚠ Failed to click column header "${columnName}": ${(error as Error).message}`
|
|
427
|
+
);
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Clicks a specific table cell using row and column indexes.
|
|
434
|
+
*
|
|
435
|
+
* Indexes are **1-based**:
|
|
436
|
+
* - rowIndex: 1 → first row
|
|
437
|
+
* - columnIndex: 1 → first column
|
|
438
|
+
*
|
|
439
|
+
* @param table - Locator for the table element
|
|
440
|
+
* @param rowIndex - 1-based index of the row to click
|
|
441
|
+
* @param columnIndex - 1-based index of the column to click
|
|
442
|
+
* @param options - Optional table settings
|
|
443
|
+
* @param options.rowLocator - Locator for table rows
|
|
444
|
+
* (default: '//tr[contains(@class,"row")]')
|
|
445
|
+
* @param options.cellLocator - Locator for table cells (default: 'td')
|
|
446
|
+
* @param options.timeout - Maximum wait time (default: 15000)
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* await CommonUtils.clickTableCell(table, 2, 3);
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* await CommonUtils.clickTableCell(table, 1, 1, {
|
|
453
|
+
* rowLocator: '//tbody/tr',
|
|
454
|
+
* cellLocator: 'td',
|
|
455
|
+
* timeout: 8000
|
|
456
|
+
* });
|
|
457
|
+
*/
|
|
458
|
+
static async clickTableCell(table: Locator, rowIndex: number, columnIndex: number,
|
|
459
|
+
options: TableOptions = {}
|
|
460
|
+
): Promise<void> {
|
|
461
|
+
|
|
462
|
+
const {
|
|
463
|
+
rowLocator = '//tr[contains(@class,"row")]',
|
|
464
|
+
cellLocator = 'td',
|
|
465
|
+
timeout = 15000
|
|
466
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
467
|
+
|
|
468
|
+
try {
|
|
469
|
+
if (rowIndex < 1 || columnIndex < 1) {
|
|
470
|
+
console.error(`⚠ Row and column indexes must be >= 1`);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const rows = table.locator(rowLocator);
|
|
475
|
+
await this.waitForVisible(rows.first(), { timeout });
|
|
476
|
+
|
|
477
|
+
const row = rows.nth(rowIndex - 1);
|
|
478
|
+
const cell = row.locator(cellLocator).nth(columnIndex - 1);
|
|
479
|
+
|
|
480
|
+
await cell.scrollIntoViewIfNeeded();
|
|
481
|
+
await this.click(cell, { timeout });
|
|
482
|
+
|
|
483
|
+
} catch (err) {
|
|
484
|
+
console.error(
|
|
485
|
+
`⚠ clickTableCell failed at row ${rowIndex}, column ${columnIndex}: ${(err as Error).message}`
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Clicks the ellipsis (actions) button in the specified table row.
|
|
492
|
+
*
|
|
493
|
+
* Row index is **1-based**:
|
|
494
|
+
* - 1 → first row
|
|
495
|
+
* - 2 → second row
|
|
496
|
+
*
|
|
497
|
+
* If the row index is invalid, ellipsis is not found,
|
|
498
|
+
* or any error occurs, the action is skipped safely.
|
|
499
|
+
*
|
|
500
|
+
* @param table - Table locator
|
|
501
|
+
* @param rowIndex - 1-based row index
|
|
502
|
+
* @param options - Optional table settings
|
|
503
|
+
* @param options.ellipsisLocator - Selector for the ellipsis button
|
|
504
|
+
* (default: 'button#detailsDropdown')
|
|
505
|
+
* @param options.rowLocator - Selector for table rows
|
|
506
|
+
* (default: '//tr[contains(@class,"row")]')
|
|
507
|
+
* @param options.timeout - Maximum wait time (default: 15000)
|
|
508
|
+
*
|
|
509
|
+
* @returns true if clicked successfully, otherwise false
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* const clicked = await CommonUtils.clickEllipsisByRowIndex(table, 1);
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* const clicked = await CommonUtils.clickEllipsisByRowIndex(table, 2, {
|
|
516
|
+
* ellipsisLocator: 'button.more-actions',
|
|
517
|
+
* rowLocator: '//tbody/tr',
|
|
518
|
+
* timeout: 8000
|
|
519
|
+
* });
|
|
520
|
+
*/
|
|
521
|
+
static async clickEllipsisByRowIndex(table: Locator, rowIndex: number,
|
|
522
|
+
options: TableOptions = {}
|
|
523
|
+
): Promise<boolean> {
|
|
524
|
+
|
|
525
|
+
const {
|
|
526
|
+
ellipsisLocator = 'button#detailsDropdown',
|
|
527
|
+
rowLocator = '//tr[contains(@class,"row")]',
|
|
528
|
+
timeout = 15000
|
|
529
|
+
} = this.resolveTableOptions<TableOptions>(options, {});
|
|
530
|
+
|
|
531
|
+
try {
|
|
532
|
+
if (rowIndex < 1) {
|
|
533
|
+
console.error('⚠ Row index must be >= 1');
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const rows = table.locator(rowLocator);
|
|
538
|
+
await this.waitForVisible(rows.first(), { timeout });
|
|
539
|
+
|
|
540
|
+
const row = rows.nth(rowIndex - 1);
|
|
541
|
+
await row.scrollIntoViewIfNeeded();
|
|
542
|
+
|
|
543
|
+
const ellipsis = row.locator(ellipsisLocator);
|
|
544
|
+
|
|
545
|
+
if (await ellipsis.count() === 0) {
|
|
546
|
+
console.warn('⚠ Ellipsis button not found in the specified row');
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
await this.click(ellipsis.first(), { timeout });
|
|
551
|
+
return true;
|
|
552
|
+
|
|
553
|
+
} catch (error) {
|
|
554
|
+
console.error(
|
|
555
|
+
`⚠ Failed to click ellipsis at row ${rowIndex}: ${(error as Error).message}`
|
|
556
|
+
);
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Clicks the ellipsis for a given table row and selects
|
|
563
|
+
* a filter/action option from the displayed options list.
|
|
564
|
+
*
|
|
565
|
+
* @param table - Locator representing the table element
|
|
566
|
+
* @param rowIndex - 1-based index of the row
|
|
567
|
+
* @param optionsList - Locator representing the list of filter options
|
|
568
|
+
* @param optionText - Visible text of the option to select
|
|
569
|
+
* @param options - Optional table/action configuration
|
|
570
|
+
*/
|
|
571
|
+
static async clickEllipsisAndSelectFilterOption(table: Locator, rowIndex: number, optionsList: Locator,
|
|
572
|
+
optionText: string, options: TableOptions = {}
|
|
573
|
+
): Promise<boolean> {
|
|
574
|
+
|
|
575
|
+
const { timeout = 15000 } =
|
|
576
|
+
this.resolveTableOptions<TableOptions>(options, {});
|
|
577
|
+
|
|
578
|
+
const ellipsisClicked = await this.clickEllipsisByRowIndex(table, rowIndex, options
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
if (!ellipsisClicked) {
|
|
582
|
+
console.warn('⚠ Unable to click ellipsis');
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return await this.clickOnFilterOptionFromList(optionsList, optionText, { timeout }
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Clicks the Apply button inside a visible dropdown container.
|
|
591
|
+
*
|
|
592
|
+
* @param filterPopupBox - Locator representing the dropdown container
|
|
593
|
+
* @param options - TableOptions options (timeout, description, applyButtonLocator -
|
|
594
|
+
* default- a.filter-button.apply)
|
|
595
|
+
* @returns boolean - true if clicked successfully, otherwise false
|
|
596
|
+
*/
|
|
597
|
+
static async clickApplyButton(filterPopupBox: Locator,options: TableOptions = {}
|
|
598
|
+
): Promise<boolean> {
|
|
599
|
+
const {
|
|
600
|
+
timeout = 15000,
|
|
601
|
+
description = 'Apply button',
|
|
602
|
+
applyButtonLocator = 'a.filter-button.apply'
|
|
603
|
+
} = this.resolveTableOptions<TableOptions>(options, { timeout: 15000 });
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
const applyButton = filterPopupBox.locator(applyButtonLocator);
|
|
607
|
+
await this.click(applyButton, { timeout, description });
|
|
608
|
+
return true;
|
|
609
|
+
} catch (error) {
|
|
610
|
+
console.error(`⚠ Failed to click ${description}: ${(error as Error).message}`);
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Clicks the "Clear" button inside a dropdown container.
|
|
617
|
+
*
|
|
618
|
+
* @param filterPopupBox - Locator representing the dropdown container
|
|
619
|
+
* @param options - TableOptions options (timeout, description, clearButtonLocator)
|
|
620
|
+
* @returns boolean - true if clicked successfully, otherwise false
|
|
621
|
+
*/
|
|
622
|
+
static async clickClearButton(filterPopupBox: Locator, options: TableOptions = {}
|
|
623
|
+
): Promise<boolean> {
|
|
624
|
+
const {
|
|
625
|
+
timeout = 15000,
|
|
626
|
+
description = 'Clear button',
|
|
627
|
+
clearButtonLocator = 'a.filter-button.clear'
|
|
628
|
+
} = this.resolveTableOptions<TableOptions>(options, { timeout: 15000 });
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
const clearButton = filterPopupBox.locator(clearButtonLocator);
|
|
632
|
+
await this.waitForVisible(clearButton);
|
|
633
|
+
await this.click(clearButton, { timeout, description });
|
|
634
|
+
return true;
|
|
635
|
+
} catch (error) {
|
|
636
|
+
console.error(`⚠ Failed to click ${description}: ${(error as Error).message}`);
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Enters a "From" date into the date filter input inside a dropdown.
|
|
642
|
+
*
|
|
643
|
+
* @param filterPopupBox - Locator for the filter dropdown/popup
|
|
644
|
+
* @param fromDate - Date string to enter into the input
|
|
645
|
+
* @param options - Optional settings from TableOptions:
|
|
646
|
+
* - dateInputLocator: custom locator for the "From" date input (defualt - input#inputFromDate)
|
|
647
|
+
*/
|
|
648
|
+
static async enterFromDate(filterPopupBox: Locator, fromDate: string,
|
|
649
|
+
options: TableOptions = {}
|
|
650
|
+
): Promise<void> {
|
|
651
|
+
const { timeout = 15000, description = 'From Date Input',
|
|
652
|
+
dateInputLocator = 'input#inputFromDate'
|
|
653
|
+
} = this.resolveTableOptions<TableOptions>(options, { timeout: 15000 });
|
|
654
|
+
|
|
655
|
+
try {
|
|
656
|
+
const fromInput = filterPopupBox.locator(dateInputLocator).first();
|
|
657
|
+
await this.waitForVisible(fromInput, { timeout });
|
|
658
|
+
await this.fill(fromInput, fromDate, { timeout, description });
|
|
659
|
+
} catch (error) {
|
|
660
|
+
console.error(`⚠ Failed to enter From Date "${fromDate}": ${(error as Error).message}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Enters a "To" date into the date filter input inside a dropdown.
|
|
666
|
+
* *
|
|
667
|
+
* @param filterPopupBox - Locator for the filter dropdown/popup
|
|
668
|
+
* @param toDate - Date string to enter into the input
|
|
669
|
+
* @param options - Optional settings from TableOptions:
|
|
670
|
+
* - dateInputLocator: custom locator for the "To" date input (defualt - input#inputToDate)
|
|
671
|
+
*/
|
|
672
|
+
static async enterToDate(filterPopupBox: Locator, toDate: string,
|
|
673
|
+
options: TableOptions = {}
|
|
674
|
+
): Promise<void> {
|
|
675
|
+
const { timeout = 15000, description = 'To Date Input',
|
|
676
|
+
dateInputLocator = 'input#inputToDate'
|
|
677
|
+
} = this.resolveTableOptions<TableOptions>(options, { timeout: 15000 });
|
|
678
|
+
|
|
679
|
+
try {
|
|
680
|
+
const toInput = filterPopupBox.locator(dateInputLocator).first();
|
|
681
|
+
await this.waitForVisible(toInput, { timeout });
|
|
682
|
+
await this.fill(toInput, toDate, { timeout, description });
|
|
683
|
+
} catch (error) {
|
|
684
|
+
console.error(`⚠ Failed to enter To Date "${toDate}": ${(error as Error).message}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Enters a value into an input field inside a filter/dropdown container.
|
|
690
|
+
*
|
|
691
|
+
* @param filterPopupBox - Locator for the dropdown/filter container
|
|
692
|
+
* @param value - Text value to enter
|
|
693
|
+
* @param options - Optional TableOptions:
|
|
694
|
+
* - inputLocator: selector for the input field (default: 'input')
|
|
695
|
+
* - timeout: max wait time (default: 15000)
|
|
696
|
+
* - description: description used in logs (default: 'Filter Input')
|
|
697
|
+
*/
|
|
698
|
+
static async enterInputValue(filterPopupBox: Locator, value: string,
|
|
699
|
+
options: TableOptions = {}
|
|
700
|
+
): Promise<void> {
|
|
701
|
+
const {
|
|
702
|
+
inputLocator = 'input',
|
|
703
|
+
timeout = 15000,
|
|
704
|
+
description = 'Filter Input'
|
|
705
|
+
} = this.resolveTableOptions<TableOptions>(options, { timeout: 15000 });
|
|
706
|
+
|
|
707
|
+
try {
|
|
708
|
+
const input = filterPopupBox.locator(inputLocator).first();
|
|
709
|
+
await this.waitForVisible(input, { timeout });
|
|
710
|
+
await this.fill(input, value, { timeout, description });
|
|
711
|
+
} catch (error) {
|
|
712
|
+
console.error(`⚠ Failed to enter value "${value}" in ${description}: ${(error as Error).message}`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|