@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.
Files changed (72) hide show
  1. package/.github/workflows/npm-release.yml +102 -0
  2. package/dist/api/base.api.d.ts +32 -0
  3. package/dist/api/base.api.d.ts.map +1 -0
  4. package/dist/api/base.api.js +7 -0
  5. package/dist/api/base.api.js.map +1 -0
  6. package/dist/api/headers.d.ts +6 -0
  7. package/dist/api/headers.d.ts.map +1 -0
  8. package/dist/api/headers.js +23 -0
  9. package/dist/api/headers.js.map +1 -0
  10. package/dist/index.d.ts +13 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +29 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/pages/basepage.d.ts +6 -0
  15. package/dist/pages/basepage.d.ts.map +1 -0
  16. package/dist/pages/basepage.js +10 -0
  17. package/dist/pages/basepage.js.map +1 -0
  18. package/dist/testData/api.data.json +6 -0
  19. package/dist/utils/apiUtils.d.ts +123 -0
  20. package/dist/utils/apiUtils.d.ts.map +1 -0
  21. package/dist/utils/apiUtils.js +264 -0
  22. package/dist/utils/apiUtils.js.map +1 -0
  23. package/dist/utils/assertionUtils.d.ts +223 -0
  24. package/dist/utils/assertionUtils.d.ts.map +1 -0
  25. package/dist/utils/assertionUtils.js +400 -0
  26. package/dist/utils/assertionUtils.js.map +1 -0
  27. package/dist/utils/commonUtils.d.ts +590 -0
  28. package/dist/utils/commonUtils.d.ts.map +1 -0
  29. package/dist/utils/commonUtils.js +1292 -0
  30. package/dist/utils/commonUtils.js.map +1 -0
  31. package/dist/utils/fakerStaticData.d.ts +16 -0
  32. package/dist/utils/fakerStaticData.d.ts.map +1 -0
  33. package/dist/utils/fakerStaticData.js +88 -0
  34. package/dist/utils/fakerStaticData.js.map +1 -0
  35. package/dist/utils/fileCommonUtils.d.ts +22 -0
  36. package/dist/utils/fileCommonUtils.d.ts.map +1 -0
  37. package/dist/utils/fileCommonUtils.js +243 -0
  38. package/dist/utils/fileCommonUtils.js.map +1 -0
  39. package/dist/utils/generationUtils.d.ts +424 -0
  40. package/dist/utils/generationUtils.d.ts.map +1 -0
  41. package/dist/utils/generationUtils.js +869 -0
  42. package/dist/utils/generationUtils.js.map +1 -0
  43. package/dist/utils/pageUtils.d.ts +90 -0
  44. package/dist/utils/pageUtils.d.ts.map +1 -0
  45. package/dist/utils/pageUtils.js +214 -0
  46. package/dist/utils/pageUtils.js.map +1 -0
  47. package/dist/utils/tableUtils.d.ts +304 -0
  48. package/dist/utils/tableUtils.d.ts.map +1 -0
  49. package/dist/utils/tableUtils.js +555 -0
  50. package/dist/utils/tableUtils.js.map +1 -0
  51. package/dist/utils/validationUtils.d.ts +80 -0
  52. package/dist/utils/validationUtils.d.ts.map +1 -0
  53. package/dist/utils/validationUtils.js +172 -0
  54. package/dist/utils/validationUtils.js.map +1 -0
  55. package/package.json +23 -0
  56. package/playwright.config.ts +79 -0
  57. package/src/api/base.api.ts +39 -0
  58. package/src/api/headers.ts +17 -0
  59. package/src/index.ts +12 -0
  60. package/src/pages/basepage.ts +11 -0
  61. package/src/testData/api.data.json +6 -0
  62. package/src/types/pdf-parse.d.ts +6 -0
  63. package/src/utils/apiUtils.ts +307 -0
  64. package/src/utils/assertionUtils.ts +455 -0
  65. package/src/utils/commonUtils.ts +1544 -0
  66. package/src/utils/fakerStaticData.ts +91 -0
  67. package/src/utils/fileCommonUtils.ts +239 -0
  68. package/src/utils/generationUtils.ts +929 -0
  69. package/src/utils/pageUtils.ts +224 -0
  70. package/src/utils/tableUtils.ts +715 -0
  71. package/src/utils/validationUtils.ts +179 -0
  72. 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
+ }