wdio-ag-grid 2.0.0

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/src/index.js ADDED
@@ -0,0 +1,766 @@
1
+ import {
2
+ browserExtractAgGrid,
3
+ browserWaitForAgGridAnimation,
4
+ filterOperator,
5
+ filterTab,
6
+ sort,
7
+ } from "@kpmck/ag-grid-core";
8
+
9
+ async function getVisibleElements(scope, selector) {
10
+ const elements = await scope.$$(selector);
11
+ const visibleElements = [];
12
+
13
+ for (const element of elements) {
14
+ if (await element.isDisplayed().catch(() => false)) {
15
+ visibleElements.push(element);
16
+ }
17
+ }
18
+
19
+ return visibleElements;
20
+ }
21
+
22
+ async function getDisplayedElementByExactText(scope, selector, text) {
23
+ const elements = await getVisibleElements(scope, selector);
24
+
25
+ for (const element of elements) {
26
+ if ((await element.getText()).trim() === text) {
27
+ return element;
28
+ }
29
+ }
30
+
31
+ return null;
32
+ }
33
+
34
+ async function clickElement(browser, element) {
35
+ try {
36
+ await element.click();
37
+ } catch {
38
+ await browser.execute((target) => target.click(), element);
39
+ }
40
+ }
41
+
42
+ async function setInputValue(browser, input, value) {
43
+ await input.waitForDisplayed();
44
+ await browser.execute((target) => {
45
+ target.value = "";
46
+ target.dispatchEvent(new Event("input", { bubbles: true }));
47
+ target.dispatchEvent(new Event("change", { bubbles: true }));
48
+ }, input);
49
+ await input.setValue(value);
50
+ }
51
+
52
+ async function getHeaderTextElement(rootElement, columnName) {
53
+ const headerTextElements = await rootElement.$$(".ag-header-cell-text");
54
+
55
+ for (const element of headerTextElements) {
56
+ if ((await element.getText()).trim() === columnName) {
57
+ return element;
58
+ }
59
+ }
60
+
61
+ throw new Error(`Unable to find AG Grid column "${columnName}".`);
62
+ }
63
+
64
+ async function getColumnHeaderMeta(browser, rootElement, columnName) {
65
+ const metadata = await browser.execute((root, targetColumnName) => {
66
+ const headerTexts = [...root.querySelectorAll(".ag-header-cell-text")];
67
+ const matchingHeaderText = headerTexts.find(
68
+ (element) => element.textContent.trim() === targetColumnName
69
+ );
70
+
71
+ if (!matchingHeaderText) {
72
+ return null;
73
+ }
74
+
75
+ const headerCell = matchingHeaderText.closest(".ag-header-cell");
76
+ const visibleHeaderCells = [...root.querySelectorAll(".ag-header-row-column .ag-header-cell")]
77
+ .filter((element) => element.offsetParent !== null);
78
+ const headerPosition = headerCell
79
+ ? visibleHeaderCells.indexOf(headerCell)
80
+ : -1;
81
+
82
+ return {
83
+ columnIndex: headerCell?.getAttribute("aria-colindex") ?? null,
84
+ headerPosition,
85
+ };
86
+ }, rootElement, columnName);
87
+
88
+ if (!metadata) {
89
+ throw new Error(`Unable to find AG Grid column "${columnName}".`);
90
+ }
91
+
92
+ return metadata;
93
+ }
94
+
95
+ async function getHeaderCellElement(browser, rootElement, columnName) {
96
+ const { columnIndex } = await getColumnHeaderMeta(browser, rootElement, columnName);
97
+
98
+ if (!columnIndex) {
99
+ throw new Error(`Unable to resolve a header cell for "${columnName}".`);
100
+ }
101
+
102
+ return rootElement.$(
103
+ `.ag-header-row-column .ag-header-cell[aria-colindex="${columnIndex}"]`
104
+ );
105
+ }
106
+
107
+ async function getMenuTabElement(rootElement, tabName) {
108
+ const icon = await rootElement.$(`.ag-tab .ag-icon-${tabName}`);
109
+ return icon.$("./ancestor::span[1]");
110
+ }
111
+
112
+ async function maybeCloseMenuTab(browser, rootElement, noMenuTabs = false) {
113
+ if (noMenuTabs) {
114
+ return;
115
+ }
116
+
117
+ const tabs = await rootElement.$$(".ag-tab");
118
+ if (tabs.length === 0) {
119
+ await browser.execute(browserWaitForAgGridAnimation, rootElement);
120
+ return;
121
+ }
122
+
123
+ await clickElement(browser, await getMenuTabElement(rootElement, filterTab.filter));
124
+ }
125
+
126
+ async function getFloatingFilterButton(browser, rootElement, columnName) {
127
+ const { columnIndex, headerPosition } = await getColumnHeaderMeta(
128
+ browser,
129
+ rootElement,
130
+ columnName
131
+ );
132
+
133
+ const usesV35FloatingFilterRow =
134
+ (await rootElement.$$(".ag-header-row-filter")).length > 0;
135
+
136
+ let buttonElements = usesV35FloatingFilterRow
137
+ ? await getVisibleElements(
138
+ rootElement,
139
+ `.ag-header-row-filter .ag-header-cell[aria-colindex="${columnIndex}"] .ag-floating-filter-button`
140
+ )
141
+ : await getVisibleElements(
142
+ rootElement,
143
+ `.ag-header-row-column-filter .ag-header-cell[aria-colindex="${columnIndex}"] .ag-floating-filter-button-button`
144
+ );
145
+
146
+ if (buttonElements.length === 0 && headerPosition > -1) {
147
+ buttonElements = usesV35FloatingFilterRow
148
+ ? await getVisibleElements(rootElement, ".ag-header-row-filter .ag-floating-filter-button")
149
+ : await getVisibleElements(
150
+ rootElement,
151
+ ".ag-header-row-column-filter .ag-floating-filter-button-button"
152
+ );
153
+
154
+ return buttonElements[headerPosition];
155
+ }
156
+
157
+ return buttonElements[0];
158
+ }
159
+
160
+ async function getFilterColumnButton(browser, rootElement, columnName, isFloatingFilter = false) {
161
+ if (isFloatingFilter) {
162
+ return getFloatingFilterButton(browser, rootElement, columnName);
163
+ }
164
+
165
+ const headerCell = await getHeaderCellElement(browser, rootElement, columnName);
166
+ await headerCell.moveTo();
167
+ return headerCell.$(".ag-header-cell-filter-button");
168
+ }
169
+
170
+ async function toggleColumnCheckboxFilter(browser, filterValue, doSelect) {
171
+ const labels = await getVisibleElements(browser, ".ag-popup .ag-input-field-label");
172
+
173
+ for (const label of labels) {
174
+ if ((await label.getText()).trim() !== filterValue) {
175
+ continue;
176
+ }
177
+
178
+ const checkbox = await label.$("./following-sibling::div[1]//input");
179
+ const toggle = await label.$("./following-sibling::div[1]");
180
+ const isChecked = await checkbox.isSelected();
181
+
182
+ if (isChecked !== doSelect) {
183
+ await clickElement(browser, toggle);
184
+ }
185
+
186
+ return;
187
+ }
188
+
189
+ throw new Error(`Unable to find checkbox filter option "${filterValue}".`);
190
+ }
191
+
192
+ async function filterBySearchTerm(browser, rootElement, options) {
193
+ const filterValue = options.searchCriteria.filterValue;
194
+ const operator = options.searchCriteria.operator;
195
+ const searchInputIndex = options.searchCriteria.searchInputIndex || 0;
196
+ const operatorIndex =
197
+ options.searchCriteria.operatorIndex ??
198
+ (operator === filterOperator.inRange ? 0 : searchInputIndex);
199
+ const isMultiFilter = options.searchCriteria.isMultiFilter;
200
+
201
+ if (operator) {
202
+ const pickers = await getVisibleElements(
203
+ rootElement,
204
+ ".ag-filter .ag-picker-field-wrapper"
205
+ );
206
+ const picker = pickers[operatorIndex];
207
+
208
+ await browser.execute(browserWaitForAgGridAnimation, rootElement);
209
+ await clickElement(browser, picker);
210
+
211
+ const listOptions = await getVisibleElements(browser, ".ag-popup .ag-list span");
212
+ let matchingOption = null;
213
+
214
+ for (const option of listOptions) {
215
+ if ((await option.getText()).trim() === operator) {
216
+ matchingOption = option;
217
+ break;
218
+ }
219
+ }
220
+
221
+ if (!matchingOption) {
222
+ throw new Error(`Unable to find AG Grid filter operator "${operator}".`);
223
+ }
224
+
225
+ await clickElement(browser, matchingOption);
226
+ }
227
+
228
+ if (isMultiFilter) {
229
+ const selectAllText = options.selectAllLocaleText || "(Select All)";
230
+ await toggleColumnCheckboxFilter(browser, selectAllText, false);
231
+ const miniFilterInputs = await getVisibleElements(
232
+ browser,
233
+ ".ag-popup-child input:not([type='radio']):not([type='checkbox'])"
234
+ );
235
+ const miniFilterInput = miniFilterInputs[0];
236
+
237
+ if (miniFilterInput) {
238
+ await setInputValue(browser, miniFilterInput, filterValue);
239
+ }
240
+ }
241
+
242
+ if (
243
+ !isMultiFilter &&
244
+ operator !== filterOperator.blank &&
245
+ operator !== filterOperator.notBlank
246
+ ) {
247
+ const inputs = await getVisibleElements(
248
+ browser,
249
+ ".ag-popup-child input:not([type='radio']):not([type='checkbox'])"
250
+ );
251
+ const input = inputs[searchInputIndex];
252
+
253
+ await setInputValue(browser, input, filterValue);
254
+ await browser.keys("Enter");
255
+ }
256
+
257
+ if (isMultiFilter) {
258
+ await toggleColumnCheckboxFilter(browser, filterValue, true);
259
+ }
260
+ }
261
+
262
+ function normalizeFloatingFilterSearchCriteria(searchCriteria) {
263
+ const betweenInputIndexes = new Map();
264
+
265
+ return searchCriteria.map((criteria) => {
266
+ if (
267
+ criteria.operator !== filterOperator.inRange ||
268
+ criteria.searchInputIndex !== undefined
269
+ ) {
270
+ return criteria;
271
+ }
272
+
273
+ const criteriaKey = `${criteria.columnName}::${criteria.operator}`;
274
+ const nextInputIndex = betweenInputIndexes.get(criteriaKey) || 0;
275
+ betweenInputIndexes.set(criteriaKey, nextInputIndex + 1);
276
+
277
+ return { ...criteria, searchInputIndex: nextInputIndex };
278
+ });
279
+ }
280
+
281
+ function groupFloatingFilterSearchCriteria(searchCriteria) {
282
+ const groupedCriteria = [];
283
+
284
+ searchCriteria.forEach((criteria) => {
285
+ const lastGroup = groupedCriteria[groupedCriteria.length - 1];
286
+
287
+ if (
288
+ criteria.operator === filterOperator.inRange &&
289
+ lastGroup &&
290
+ lastGroup[0].columnName === criteria.columnName &&
291
+ lastGroup[0].operator === criteria.operator
292
+ ) {
293
+ lastGroup.push(criteria);
294
+ return;
295
+ }
296
+
297
+ groupedCriteria.push([criteria]);
298
+ });
299
+
300
+ return groupedCriteria;
301
+ }
302
+
303
+ async function clickMenuOptionByText(browser, text) {
304
+ const menuOptions = await getVisibleElements(browser, ".ag-menu-option");
305
+
306
+ for (const option of menuOptions) {
307
+ const optionText = (await option.getText()).replace(/\s+/g, " ").trim();
308
+
309
+ if (optionText === text || optionText.includes(text)) {
310
+ await clickElement(browser, option);
311
+ return;
312
+ }
313
+ }
314
+
315
+ throw new Error(`Unable to find AG Grid menu option "${text}".`);
316
+ }
317
+
318
+ async function applyColumnFilter(browser, rootElement, hasApplyButton, noMenuTabs) {
319
+ if (hasApplyButton) {
320
+ const applyButton = await getDisplayedElementByExactText(
321
+ browser,
322
+ ".ag-filter-apply-panel-button",
323
+ "Apply"
324
+ );
325
+
326
+ if (applyButton) {
327
+ await clickElement(browser, applyButton);
328
+ }
329
+ }
330
+
331
+ await maybeCloseMenuTab(browser, rootElement, noMenuTabs);
332
+ await browser.keys("Escape");
333
+ }
334
+
335
+ export class WdioAgGrid {
336
+ constructor(rootElement) {
337
+ this.rootElement = rootElement;
338
+ this.browser = rootElement.parent;
339
+ }
340
+
341
+ async waitForAnimation(options = {}) {
342
+ await this.browser.execute(browserWaitForAgGridAnimation, this.rootElement, options);
343
+ }
344
+
345
+ async getData(options = {}) {
346
+ await this.browser.execute(browserWaitForAgGridAnimation, this.rootElement, options);
347
+ return this.browser.execute(browserExtractAgGrid, this.rootElement, options);
348
+ }
349
+
350
+ async sortColumn(columnName, sortDirection) {
351
+ let normalized = sortDirection;
352
+
353
+ if (normalized.toLowerCase() === "ascending") {
354
+ normalized = "asc";
355
+ } else if (normalized.toLowerCase() === "descending") {
356
+ normalized = "desc";
357
+ }
358
+
359
+ if (normalized !== sort.ascending && normalized !== sort.descending) {
360
+ throw new Error("sortDirection must be either 'asc' or 'desc'.");
361
+ }
362
+
363
+ const headerText = await getHeaderTextElement(this.rootElement, columnName);
364
+ const container = await headerText.$(
365
+ "./ancestor::*[contains(@class, 'ag-cell-label-container')][1]"
366
+ );
367
+
368
+ for (let attempts = 0; attempts < 3; attempts += 1) {
369
+ const className = (await container.getAttribute("class")) || "";
370
+ if (className.includes(`ag-header-cell-sorted-${normalized}`)) {
371
+ return;
372
+ }
373
+
374
+ await clickElement(this.browser, headerText);
375
+ }
376
+ }
377
+
378
+ async pinColumn(columnName, pin) {
379
+ const headerCell = await getHeaderCellElement(this.browser, this.rootElement, columnName);
380
+ await headerCell.moveTo();
381
+ await clickElement(this.browser, await headerCell.$(".ag-header-cell-menu-button"));
382
+
383
+ if ((await this.rootElement.$$(".ag-tab")).length > 0) {
384
+ await clickElement(
385
+ this.browser,
386
+ await getMenuTabElement(this.rootElement, filterTab.general)
387
+ );
388
+ }
389
+
390
+ const pinColumnOptions = await getVisibleElements(this.browser, ".ag-menu-option");
391
+ let pinColumnOption = null;
392
+
393
+ for (const option of pinColumnOptions) {
394
+ const optionText = (await option.getText()).replace(/\s+/g, " ").trim();
395
+ if (optionText === "Pin Column" || optionText.includes("Pin Column")) {
396
+ pinColumnOption = option;
397
+ break;
398
+ }
399
+ }
400
+
401
+ if (!pinColumnOption) {
402
+ throw new Error('Unable to find AG Grid menu option "Pin Column".');
403
+ }
404
+
405
+ await pinColumnOption.moveTo();
406
+ await clickElement(this.browser, pinColumnOption);
407
+ await this.browser.keys("ArrowRight");
408
+
409
+ const selectedOption =
410
+ pin === "left" ? "Pin Left" : pin === "right" ? "Pin Right" : "No Pin";
411
+
412
+ try {
413
+ await clickMenuOptionByText(this.browser, selectedOption);
414
+ return;
415
+ } catch (error) {
416
+ const appliedViaApi = await this.browser.execute(
417
+ (root, targetColumnName, pinValue) => {
418
+ const headerTexts = [...root.querySelectorAll(".ag-header-cell-text")];
419
+ const matchingHeaderText = headerTexts.find(
420
+ (element) => element.textContent.trim() === targetColumnName
421
+ );
422
+ const headerCell = matchingHeaderText?.closest(".ag-header-cell");
423
+ const colId =
424
+ headerCell?.getAttribute("col-id") ??
425
+ headerCell?.getAttribute("colid") ??
426
+ targetColumnName.toLowerCase();
427
+ let api =
428
+ globalThis.gridApi ??
429
+ globalThis.gridOptions?.api ??
430
+ globalThis.gridOptionsGrouped?.api;
431
+
432
+ if (!api && typeof globalThis.eval === "function") {
433
+ try {
434
+ api = globalThis.eval("typeof gridApi !== 'undefined' ? gridApi : undefined");
435
+ } catch {}
436
+ }
437
+
438
+ if (!api && typeof globalThis.eval === "function") {
439
+ try {
440
+ api = globalThis.eval(
441
+ "typeof gridOptions !== 'undefined' && gridOptions.api ? gridOptions.api : undefined"
442
+ );
443
+ } catch {}
444
+ }
445
+
446
+ if (!api && typeof globalThis.eval === "function") {
447
+ try {
448
+ api = globalThis.eval(
449
+ "typeof gridOptionsGrouped !== 'undefined' && gridOptionsGrouped.api ? gridOptionsGrouped.api : undefined"
450
+ );
451
+ } catch {}
452
+ }
453
+
454
+ if (!api || typeof api.applyColumnState !== "function") {
455
+ return false;
456
+ }
457
+
458
+ api.applyColumnState({
459
+ state: [{ colId, pinned: pinValue }],
460
+ });
461
+
462
+ return true;
463
+ },
464
+ this.rootElement,
465
+ columnName,
466
+ pin === null ? null : pin
467
+ );
468
+
469
+ if (!appliedViaApi) {
470
+ throw error;
471
+ }
472
+ }
473
+ }
474
+
475
+ async filterTextMenu(options) {
476
+ const criteriaList = Array.isArray(options.searchCriteria)
477
+ ? options.searchCriteria
478
+ : [options.searchCriteria];
479
+
480
+ for (const searchCriteria of criteriaList) {
481
+ const optionSet = { ...options, searchCriteria };
482
+ await clickElement(
483
+ this.browser,
484
+ await getFilterColumnButton(this.browser, this.rootElement, searchCriteria.columnName)
485
+ );
486
+ await filterBySearchTerm(this.browser, this.rootElement, optionSet);
487
+ await applyColumnFilter(
488
+ this.browser,
489
+ this.rootElement,
490
+ options.hasApplyButton,
491
+ options.noMenuTabs
492
+ );
493
+ }
494
+ }
495
+
496
+ async filterTextFloating(options) {
497
+ const criteriaList = Array.isArray(options.searchCriteria)
498
+ ? normalizeFloatingFilterSearchCriteria(options.searchCriteria)
499
+ : [options.searchCriteria];
500
+
501
+ const groups = groupFloatingFilterSearchCriteria(criteriaList);
502
+
503
+ for (const group of groups) {
504
+ await clickElement(
505
+ this.browser,
506
+ await getFilterColumnButton(
507
+ this.browser,
508
+ this.rootElement,
509
+ group[0].columnName,
510
+ true
511
+ )
512
+ );
513
+
514
+ for (let index = 0; index < group.length; index += 1) {
515
+ const criteria = group[index];
516
+ await filterBySearchTerm(this.browser, this.rootElement, {
517
+ ...options,
518
+ searchCriteria: index === 0 ? criteria : { ...criteria, operator: undefined },
519
+ });
520
+ }
521
+
522
+ await applyColumnFilter(
523
+ this.browser,
524
+ this.rootElement,
525
+ options.hasApplyButton,
526
+ options.noMenuTabs
527
+ );
528
+ }
529
+ }
530
+
531
+ async filterCheckboxMenu(options) {
532
+ const criteriaList = Array.isArray(options.searchCriteria)
533
+ ? options.searchCriteria
534
+ : [options.searchCriteria];
535
+
536
+ for (const searchCriteria of criteriaList) {
537
+ await clickElement(
538
+ this.browser,
539
+ await getFilterColumnButton(this.browser, this.rootElement, searchCriteria.columnName)
540
+ );
541
+ await toggleColumnCheckboxFilter(
542
+ this.browser,
543
+ options.selectAllLocaleText || "(Select All)",
544
+ false
545
+ );
546
+ await toggleColumnCheckboxFilter(this.browser, searchCriteria.filterValue, true);
547
+ await applyColumnFilter(
548
+ this.browser,
549
+ this.rootElement,
550
+ options.hasApplyButton,
551
+ options.noMenuTabs
552
+ );
553
+ }
554
+ }
555
+
556
+ async toggleColumnFromSideBar(columnName, doRemove) {
557
+ let columnFilterInput = await this.rootElement.$(
558
+ ".ag-column-select-header-filter-wrapper input"
559
+ );
560
+
561
+ if (!(await columnFilterInput.isDisplayed().catch(() => false))) {
562
+ const columnsButton = await getDisplayedElementByExactText(
563
+ this.browser,
564
+ ".ag-side-buttons span",
565
+ "Columns"
566
+ );
567
+ await clickElement(this.browser, columnsButton);
568
+ columnFilterInput = await this.rootElement.$(
569
+ ".ag-column-select-header-filter-wrapper input"
570
+ );
571
+ }
572
+
573
+ await this.waitForAnimation();
574
+ await setInputValue(this.browser, columnFilterInput, columnName);
575
+
576
+ await this.browser.waitUntil(
577
+ async () => {
578
+ const labels = await getVisibleElements(this.browser, ".ag-column-select-column-label");
579
+
580
+ for (const label of labels) {
581
+ if ((await label.getText()).trim() === columnName) {
582
+ return true;
583
+ }
584
+ }
585
+
586
+ return false;
587
+ },
588
+ {
589
+ timeout: 3000,
590
+ timeoutMsg: `Unable to find sidebar column "${columnName}".`,
591
+ }
592
+ );
593
+
594
+ const labels = await getVisibleElements(this.browser, ".ag-column-select-column-label");
595
+ let matchingLabel = null;
596
+
597
+ for (const label of labels) {
598
+ if ((await label.getText()).trim() === columnName) {
599
+ matchingLabel = label;
600
+ break;
601
+ }
602
+ }
603
+
604
+ if (!matchingLabel) {
605
+ throw new Error(`Unable to find sidebar column "${columnName}".`);
606
+ }
607
+
608
+ const checkbox = await matchingLabel.$("./ancestor::*[1]//input");
609
+ const isSelected = await checkbox.isSelected();
610
+ const expectedSelectedState = !doRemove;
611
+
612
+ if (doRemove && isSelected) {
613
+ await clickElement(this.browser, checkbox);
614
+ }
615
+
616
+ if (!doRemove && !isSelected) {
617
+ await clickElement(this.browser, checkbox);
618
+ }
619
+
620
+ const applyColumnVisibilityViaApi = async () =>
621
+ this.browser.execute(
622
+ (targetColumnName, shouldBeVisible) => {
623
+ const apiCandidates = [];
624
+
625
+ if (globalThis.gridApi) {
626
+ apiCandidates.push(globalThis.gridApi);
627
+ }
628
+
629
+ if (globalThis.gridOptions?.api) {
630
+ apiCandidates.push(globalThis.gridOptions.api);
631
+ }
632
+
633
+ if (globalThis.gridOptionsGrouped?.api) {
634
+ apiCandidates.push(globalThis.gridOptionsGrouped.api);
635
+ }
636
+
637
+ if (typeof globalThis.eval === "function") {
638
+ try {
639
+ const gridApi = globalThis.eval(
640
+ "typeof gridApi !== 'undefined' ? gridApi : undefined"
641
+ );
642
+ if (gridApi) {
643
+ apiCandidates.push(gridApi);
644
+ }
645
+ } catch {}
646
+
647
+ try {
648
+ const gridOptionsApi = globalThis.eval(
649
+ "typeof gridOptions !== 'undefined' && gridOptions.api ? gridOptions.api : undefined"
650
+ );
651
+ if (gridOptionsApi) {
652
+ apiCandidates.push(gridOptionsApi);
653
+ }
654
+ } catch {}
655
+ }
656
+
657
+ const api = apiCandidates.find(Boolean);
658
+ if (!api) {
659
+ return false;
660
+ }
661
+
662
+ const normalizedTarget = targetColumnName.trim().toLowerCase();
663
+ const columns = typeof api.getColumns === "function" ? api.getColumns() : [];
664
+
665
+ const matchingColumn = columns.find((column) => {
666
+ const colDef = typeof column.getColDef === "function" ? column.getColDef() : {};
667
+ const field = (colDef.field ?? "").toLowerCase();
668
+ const headerName = (colDef.headerName ?? "").toLowerCase();
669
+ const colId =
670
+ typeof column.getColId === "function"
671
+ ? String(column.getColId()).toLowerCase()
672
+ : "";
673
+
674
+ return (
675
+ field === normalizedTarget ||
676
+ headerName === normalizedTarget ||
677
+ colId === normalizedTarget
678
+ );
679
+ });
680
+
681
+ const columnKey = matchingColumn
682
+ ? typeof matchingColumn.getColId === "function"
683
+ ? matchingColumn.getColId()
684
+ : matchingColumn.colId ?? targetColumnName
685
+ : normalizedTarget;
686
+
687
+ if (typeof api.setColumnsVisible === "function") {
688
+ api.setColumnsVisible([columnKey], shouldBeVisible);
689
+ return true;
690
+ }
691
+
692
+ if (typeof api.applyColumnState === "function") {
693
+ api.applyColumnState({
694
+ state: [{ colId: columnKey, hide: !shouldBeVisible }],
695
+ });
696
+ return true;
697
+ }
698
+
699
+ return false;
700
+ },
701
+ columnName,
702
+ expectedSelectedState
703
+ );
704
+
705
+ await this.browser.waitUntil(
706
+ async () => {
707
+ const selected = await checkbox.isSelected().catch(() => null);
708
+ return selected === expectedSelectedState;
709
+ },
710
+ {
711
+ timeout: 1500,
712
+ interval: 100,
713
+ timeoutMsg: `Sidebar column "${columnName}" did not reach the expected selected state.`,
714
+ }
715
+ ).catch(async () => {
716
+ await applyColumnVisibilityViaApi();
717
+ });
718
+
719
+ await this.waitForAnimation();
720
+
721
+ const valuesArray = await this.getData({ valuesArray: true });
722
+ const columnStillPresent = valuesArray.headers.includes(columnName);
723
+
724
+ if (doRemove && columnStillPresent) {
725
+ await applyColumnVisibilityViaApi();
726
+ await this.waitForAnimation();
727
+ }
728
+
729
+ if (!doRemove && !columnStillPresent) {
730
+ await applyColumnVisibilityViaApi();
731
+ await this.waitForAnimation();
732
+ }
733
+ }
734
+
735
+ async getCellLocator(rowMatcher, columnName) {
736
+ const rows = await this.getData();
737
+ const rowIndex = rows.findIndex((row) =>
738
+ Object.entries(rowMatcher).every(([key, value]) => row[key] === value)
739
+ );
740
+
741
+ if (rowIndex === -1) {
742
+ throw new Error(`Unable to find row matching ${JSON.stringify(rowMatcher)}.`);
743
+ }
744
+
745
+ const valuesArray = await this.getData({ valuesArray: true });
746
+ const columnIndex = valuesArray.headers.indexOf(columnName);
747
+
748
+ if (columnIndex === -1) {
749
+ throw new Error(`Unable to find column "${columnName}".`);
750
+ }
751
+
752
+ const visibleRows = await this.rootElement.$$(
753
+ ".ag-center-cols-clipper .ag-row:not(.ag-opacity-zero), .ag-center-cols-viewport .ag-row:not(.ag-opacity-zero)"
754
+ );
755
+
756
+ const rowElement = visibleRows[rowIndex];
757
+ const cells = await rowElement.$$(".ag-cell");
758
+ return cells[columnIndex];
759
+ }
760
+ }
761
+
762
+ export function createAgGrid(rootElement) {
763
+ return new WdioAgGrid(rootElement);
764
+ }
765
+
766
+ export { filterOperator, sort };