cypress-ag-grid 3.3.2 → 3.3.5

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.
@@ -0,0 +1,56 @@
1
+ import { filterOperator } from "../../../src/agGrid/filterOperator.enum";
2
+
3
+ const agGridSelector = "#myGrid2";
4
+
5
+ export function runAgGridElementsSuite({ pagePath, versionLabel }) {
6
+ describe(`ag-grid get elements scenario (${versionLabel})`, () => {
7
+ beforeEach(() => {
8
+ cy.visit(pagePath);
9
+ cy.contains(".example-version", `AG Grid ${versionLabel}`).should("be.visible");
10
+ cy.get(".ag-cell", { timeout: 10000 }).should("be.visible");
11
+ });
12
+
13
+ it("able to update grid cell value", () => {
14
+ cy.get(agGridSelector).agGridColumnFilterTextFloating({
15
+ searchCriteria: {
16
+ columnName: "Make",
17
+ filterValue: "Porsche",
18
+ operator: filterOperator.equals,
19
+ },
20
+ hasApplyButton: true,
21
+ });
22
+
23
+ const expectedTableBeforeEditing = [
24
+ { Year: "2020", Make: "Porsche", Model: "Boxter", Price: "72000" },
25
+ { Year: "2020", Make: "Porsche", Model: "Boxter", Price: "99000" },
26
+ ];
27
+
28
+ cy.get(agGridSelector)
29
+ .getAgGridData()
30
+ .then((tableData) => {
31
+ cy.agGridValidateRowsSubset(tableData, expectedTableBeforeEditing);
32
+ });
33
+
34
+ cy.get(agGridSelector)
35
+ .getAgGridElements()
36
+ .then((tableElements) => {
37
+ const porscheRow = tableElements.find(
38
+ (row) => row.Price.innerText === "72000"
39
+ );
40
+ const priceCell = porscheRow.Price;
41
+ cy.wrap(priceCell).dblclick().type("66000{enter}");
42
+ });
43
+
44
+ const expectedTableAfterEditing = [
45
+ { Year: "2020", Make: "Porsche", Model: "Boxter", Price: "66000" },
46
+ { Year: "2020", Make: "Porsche", Model: "Boxter", Price: "99000" },
47
+ ];
48
+
49
+ cy.get(agGridSelector)
50
+ .getAgGridData()
51
+ .then((tableData) => {
52
+ cy.agGridValidateRowsSubset(tableData, expectedTableAfterEditing);
53
+ });
54
+ });
55
+ });
56
+ }
@@ -1,21 +1,21 @@
1
1
  [
2
- { "Year": "2020", "Make": "Toyota", "Model": "Celica", "Condition": "fair", "Price": "35000" },
3
- { "Year": "2020", "Make": "Ford", "Model": "Mondeo", "Condition": "excellent", "Price": "32000" },
4
- { "Year": "2020", "Make": "Porsche", "Model": "Boxter", "Condition": "good", "Price": "72000" },
5
- { "Year": "2020", "Make": "BMW", "Model": "3-series", "Condition": "fair", "Price": "45000" },
6
- { "Year": "2020", "Make": "Mercedes", "Model": "GLC300", "Condition": "good", "Price": "53000" },
7
- { "Year": "2020", "Make": "Honda", "Model": "Civic", "Condition": "poor", "Price": "22000" },
8
- { "Year": "2020", "Make": "Honda", "Model": "Accord", "Condition": "poor", "Price": "32000" },
9
- { "Year": "2020", "Make": "Ford", "Model": "Taurus", "Condition": "excellent", "Price": "19000" },
10
- { "Year": "2020", "Make": "Hyundai", "Model": "Elantra", "Condition": "good", "Price": "22000" },
11
- { "Year": "2020", "Make": "Toyota", "Model": "Celica", "Condition": "poor", "Price": "5000" },
12
- { "Year": "2020", "Make": "Ford", "Model": "Mondeo", "Condition": "good", "Price": "25000" },
13
- { "Year": "2020", "Make": "Porsche", "Model": "Boxter", "Condition": "good", "Price": "99000" },
14
- { "Year": "2020", "Make": "BMW", "Model": "3-series", "Condition": "poor", "Price": "32000" },
15
- { "Year": "2020", "Make": "Mercedes", "Model": "GLC300", "Condition": "excellent", "Price": "35000" },
16
- { "Year": "2011", "Make": "Honda", "Model": "Civic", "Condition": "good", "Price": "9000" },
17
- { "Year": "2020", "Make": "Honda", "Model": "Accord", "Condition": "good", "Price": "34000" },
18
- { "Year": "1990", "Make": "Ford", "Model": "Taurus", "Condition": "excellent", "Price": "900" },
19
- { "Year": "2020", "Make": "Hyundai", "Model": "Elantra", "Condition": "fair", "Price": "3000" },
20
- { "Year": "2020", "Make": "BMW", "Model": "2002", "Condition": "excellent", "Price": "88001" }
21
- ]
2
+ { "Year": "2020", "Make": "Toyota", "Model": "Celica", "Condition": "fair", "Mileage": "12000", "Price": "35000" },
3
+ { "Year": "2020", "Make": "Ford", "Model": "Mondeo", "Condition": "excellent", "Mileage": "8000", "Price": "32000" },
4
+ { "Year": "2020", "Make": "Porsche", "Model": "Boxter", "Condition": "good", "Mileage": "30000", "Price": "72000" },
5
+ { "Year": "2020", "Make": "BMW", "Model": "3-series", "Condition": "fair", "Mileage": "18000", "Price": "45000" },
6
+ { "Year": "2020", "Make": "Mercedes", "Model": "GLC300", "Condition": "good", "Mileage": "24000", "Price": "53000" },
7
+ { "Year": "2020", "Make": "Honda", "Model": "Civic", "Condition": "poor", "Mileage": "40000", "Price": "22000" },
8
+ { "Year": "2020", "Make": "Honda", "Model": "Accord", "Condition": "poor", "Mileage": "42000", "Price": "32000" },
9
+ { "Year": "2020", "Make": "Ford", "Model": "Taurus", "Condition": "excellent", "Mileage": "5000", "Price": "19000" },
10
+ { "Year": "2020", "Make": "Hyundai", "Model": "Elantra", "Condition": "good", "Mileage": "28000", "Price": "22000" },
11
+ { "Year": "2020", "Make": "Toyota", "Model": "Celica", "Condition": "poor", "Mileage": "60000", "Price": "5000" },
12
+ { "Year": "2020", "Make": "Ford", "Model": "Mondeo", "Condition": "good", "Mileage": "15000", "Price": "25000" },
13
+ { "Year": "2020", "Make": "Porsche", "Model": "Boxter", "Condition": "good", "Mileage": "1000", "Price": "99000" },
14
+ { "Year": "2020", "Make": "BMW", "Model": "3-series", "Condition": "poor", "Mileage": "52000", "Price": "32000" },
15
+ { "Year": "2020", "Make": "Mercedes", "Model": "GLC300", "Condition": "excellent", "Mileage": "9000", "Price": "35000" },
16
+ { "Year": "2011", "Make": "Honda", "Model": "Civic", "Condition": "good", "Mileage": "70000", "Price": "9000" },
17
+ { "Year": "2020", "Make": "Honda", "Model": "Accord", "Condition": "good", "Mileage": "22000", "Price": "34000" },
18
+ { "Year": "1990", "Make": "Ford", "Model": "Taurus", "Condition": "excellent", "Mileage": "90000", "Price": "900" },
19
+ { "Year": "2020", "Make": "Hyundai", "Model": "Elantra", "Condition": "fair", "Mileage": "3500", "Price": "3000" },
20
+ { "Year": "2020", "Make": "BMW", "Model": "2002", "Condition": "excellent", "Mileage": "4500", "Price": "88001" }
21
+ ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress-ag-grid",
3
- "version": "3.3.2",
3
+ "version": "3.3.5",
4
4
  "description": "Cypress plugin to interact with ag grid",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -18,12 +18,15 @@
18
18
  "cypress aggrid"
19
19
  ],
20
20
  "scripts": {
21
- "test": "npx cypress run --headless --spec cypress/e2e/*.cy.js",
21
+ "test": "npx cypress run --headless --spec \"cypress/e2e/*.cy.js\"",
22
+ "test:v33": "npx cypress run --headless --spec \"cypress/e2e/*.v33.cy.js\"",
23
+ "test:v34": "npx cypress run --headless --spec \"cypress/e2e/*.v34.cy.js\"",
24
+ "test:v35": "npx cypress run --headless --spec \"cypress/e2e/*.v35.cy.js\"",
22
25
  "test:watch": "npx cypress open"
23
26
  },
24
27
  "author": "Kerry McKeever <kerry@kerrymckeever.com>",
25
28
  "license": "MIT",
26
29
  "devDependencies": {
27
- "cypress": "^13.3.0"
30
+ "cypress": "^15.12.0"
28
31
  }
29
32
  }
@@ -20,19 +20,53 @@ export const agGridWaitForAnimation = async (agGridElement) => {
20
20
  throw new Error(`Couldn't find the element ${agGridElement}`);
21
21
  }
22
22
 
23
- const animations = agGridElement.get()[0].getAnimations({ subtree: true });
24
-
25
- await Promise.all(
26
- animations.map(async (animation) => {
27
- try {
28
- await animation.finished;
29
- } catch (error) {
30
- if (error.name === "AbortError") return;
31
- console.error("error", error, error.name);
32
- throw error;
33
- }
34
- })
35
- );
23
+ const AG_GRID_ANIMATION_TIMEOUT_MS = 5000;
24
+ const agGridRootElement = agGridElement.get()[0];
25
+ const animations = agGridRootElement.getAnimations({ subtree: true });
26
+
27
+ const agGridAnimations = animations.filter((animation) => {
28
+ const animationTarget = animation.effect?.target;
29
+ if (
30
+ !animationTarget ||
31
+ animationTarget.nodeType !== 1 ||
32
+ !animationTarget.classList
33
+ ) {
34
+ return false;
35
+ }
36
+
37
+ const hasAgGridClass = [...animationTarget.classList].some((className) =>
38
+ className.startsWith("ag-")
39
+ );
40
+
41
+ return (
42
+ animationTarget === agGridRootElement ||
43
+ hasAgGridClass
44
+ );
45
+ });
46
+
47
+ // Filter out infinite animations (e.g. loading spinners) whose .finished
48
+ // promise never resolves per the Web Animations API spec.
49
+ const finiteAnimations = agGridAnimations.filter((animation) => {
50
+ const iterations = animation.effect?.getTiming?.()?.iterations;
51
+ return iterations !== Infinity;
52
+ });
53
+
54
+ await Promise.race([
55
+ Promise.all(
56
+ finiteAnimations.map(async (animation) => {
57
+ try {
58
+ await animation.finished;
59
+ } catch (error) {
60
+ if (error.name === "AbortError") return;
61
+ console.error("error", error, error.name);
62
+ throw error;
63
+ }
64
+ })
65
+ ),
66
+ new Promise((resolve) => {
67
+ setTimeout(resolve, AG_GRID_ANIMATION_TIMEOUT_MS);
68
+ }),
69
+ ]);
36
70
 
37
71
  return agGridElement;
38
72
  };
@@ -271,28 +305,54 @@ function getFilterColumnButtonElement(
271
305
  columnName,
272
306
  isFloatingFilter = false
273
307
  ) {
274
- let columnIndex;
275
- if (isFloatingFilter)
308
+ if (isFloatingFilter) {
276
309
  return getColumnHeaderElement(agGridElement, columnName)
277
310
  .parents(".ag-header-cell")
278
- .then(($ele) => {
279
- cy.wrap($ele)
280
- .invoke("attr", "aria-colindex")
281
- .then((colIndex) => {
282
- columnIndex = colIndex;
283
- })
284
- .then(() => {
285
- cy.wrap($ele)
286
- .parents(".ag-header-row-column")
287
- .siblings(".ag-header-row-column-filter")
288
- .find(`.ag-header-cell[aria-colindex=${columnIndex}]`)
289
- .find(".ag-floating-filter-button");
290
- });
311
+ .then(($headerCell) => {
312
+ const columnIndex = $headerCell.attr("aria-colindex");
313
+ const visibleHeaderCells = $headerCell
314
+ .closest(".ag-header")
315
+ .find(".ag-header-row-column .ag-header-cell:visible");
316
+ const headerPosition = visibleHeaderCells.index($headerCell);
317
+
318
+ return cy.get(agGridElement).then(($gridElement) => {
319
+ const usesV35FloatingFilterRow =
320
+ $gridElement.find(".ag-header-row-filter").length > 0;
321
+
322
+ let floatingFilterButton;
323
+
324
+ if (usesV35FloatingFilterRow) {
325
+ floatingFilterButton = $gridElement.find(
326
+ `.ag-header-row-filter .ag-header-cell[aria-colindex="${columnIndex}"] .ag-floating-filter-button:visible`
327
+ );
328
+
329
+ if (!floatingFilterButton.length && headerPosition > -1) {
330
+ floatingFilterButton = $gridElement
331
+ .find(".ag-header-row-filter .ag-floating-filter-button:visible")
332
+ .eq(headerPosition);
333
+ }
334
+ } else {
335
+ floatingFilterButton = $gridElement.find(
336
+ `.ag-header-row-column-filter .ag-header-cell[aria-colindex="${columnIndex}"] .ag-floating-filter-button-button:visible`
337
+ );
338
+
339
+ if (!floatingFilterButton.length && headerPosition > -1) {
340
+ floatingFilterButton = $gridElement
341
+ .find(
342
+ ".ag-header-row-column-filter .ag-floating-filter-button-button:visible"
343
+ )
344
+ .eq(headerPosition);
345
+ }
346
+ }
347
+
348
+ return cy.wrap(floatingFilterButton.first());
349
+ });
291
350
  });
292
- else
351
+ } else {
293
352
  return getColumnHeaderElement(agGridElement, columnName)
294
353
  .parent()
295
354
  .siblings(".ag-header-cell-filter-button");
355
+ }
296
356
  }
297
357
 
298
358
  /**
@@ -305,6 +365,9 @@ function filterBySearchTerm(agGridElement, options) {
305
365
  const filterValue = options.searchCriteria.filterValue;
306
366
  const operator = options.searchCriteria.operator;
307
367
  const searchInputIndex = options.searchCriteria.searchInputIndex || 0;
368
+ const operatorIndex =
369
+ options.searchCriteria.operatorIndex ??
370
+ (operator === filterOperator.inRange ? 0 : searchInputIndex);
308
371
  const isMultiFilter = options.searchCriteria.isMultiFilter;
309
372
  const noMenuTabs = options.noMenuTabs;
310
373
 
@@ -319,7 +382,7 @@ function filterBySearchTerm(agGridElement, options) {
319
382
  .find(".ag-filter")
320
383
  .find(".ag-picker-field-wrapper")
321
384
  .filter(":visible")
322
- .eq(searchInputIndex);
385
+ .eq(operatorIndex);
323
386
  cy.get(agGridElement).agGridWaitForAnimation();
324
387
  elem.click();
325
388
  cy.get(agGridElement)
@@ -510,19 +573,73 @@ function _filterBySearchTextColumnMenu(agGridElement, options) {
510
573
  export function filterBySearchTextColumnFloatingFilter(agGridElement, options) {
511
574
  // Check if there are multiple search criteria provided by attempting to access the columnName
512
575
  if (!options.searchCriteria.columnName) {
513
- options.searchCriteria.forEach((_searchCriteria) => {
514
- const _options = populateSearchCriteria(
515
- _searchCriteria,
516
- options.hasApplyButton,
517
- options.noMenuTabs
576
+ groupFloatingFilterSearchCriteria(
577
+ normalizeFloatingFilterSearchCriteria(options.searchCriteria)
578
+ ).forEach((searchCriteriaGroup) => {
579
+ const criteriaOptions = searchCriteriaGroup.map((_searchCriteria) =>
580
+ populateSearchCriteria(
581
+ _searchCriteria,
582
+ options.hasApplyButton,
583
+ options.noMenuTabs
584
+ )
518
585
  );
519
- _filterBySearchTextColumnFloatingFilter(agGridElement, _options);
586
+
587
+ if (criteriaOptions.length === 1) {
588
+ _filterBySearchTextColumnFloatingFilter(agGridElement, criteriaOptions[0]);
589
+ return;
590
+ }
591
+
592
+ _filterBySearchTextColumnFloatingFilterGroup(agGridElement, criteriaOptions);
520
593
  });
521
594
  } else {
522
595
  _filterBySearchTextColumnFloatingFilter(agGridElement, options);
523
596
  }
524
597
  }
525
598
 
599
+ function normalizeFloatingFilterSearchCriteria(searchCriteria) {
600
+ const betweenInputIndexes = new Map();
601
+
602
+ return searchCriteria.map((criteria) => {
603
+ if (
604
+ criteria.operator !== filterOperator.inRange ||
605
+ criteria.searchInputIndex !== undefined
606
+ ) {
607
+ return criteria;
608
+ }
609
+
610
+ const criteriaKey = `${criteria.columnName}::${criteria.operator}`;
611
+ const nextInputIndex = betweenInputIndexes.get(criteriaKey) || 0;
612
+ betweenInputIndexes.set(criteriaKey, nextInputIndex + 1);
613
+
614
+ return {
615
+ ...criteria,
616
+ searchInputIndex: nextInputIndex,
617
+ };
618
+ });
619
+ }
620
+
621
+ function groupFloatingFilterSearchCriteria(searchCriteria) {
622
+ const groupedCriteria = [];
623
+
624
+ searchCriteria.forEach((criteria) => {
625
+ const lastGroup = groupedCriteria[groupedCriteria.length - 1];
626
+
627
+ if (
628
+ criteria.operator === filterOperator.inRange &&
629
+ lastGroup &&
630
+ lastGroup[0].columnName === criteria.columnName &&
631
+ lastGroup[0].operator === criteria.operator
632
+ ) {
633
+ lastGroup.push(criteria);
634
+ return;
635
+ }
636
+
637
+ groupedCriteria.push([criteria]);
638
+ });
639
+
640
+ return groupedCriteria;
641
+ }
642
+
526
643
  function _filterBySearchTextColumnFloatingFilter(agGridElement, options) {
527
644
  cy.get(agGridElement).then((agGridElement) => {
528
645
  getFilterColumnButtonElement(
@@ -539,6 +656,37 @@ function _filterBySearchTextColumnFloatingFilter(agGridElement, options) {
539
656
  });
540
657
  }
541
658
 
659
+ function _filterBySearchTextColumnFloatingFilterGroup(
660
+ agGridElement,
661
+ criteriaOptions
662
+ ) {
663
+ cy.get(agGridElement).then((agGridElement) => {
664
+ getFilterColumnButtonElement(
665
+ agGridElement,
666
+ criteriaOptions[0].searchCriteria.columnName,
667
+ true
668
+ ).click();
669
+
670
+ criteriaOptions.forEach((criteriaOption, index) => {
671
+ const searchCriteria =
672
+ index === 0
673
+ ? criteriaOption.searchCriteria
674
+ : { ...criteriaOption.searchCriteria, operator: undefined };
675
+
676
+ filterBySearchTerm(agGridElement, {
677
+ ...criteriaOption,
678
+ searchCriteria,
679
+ });
680
+ });
681
+
682
+ applyColumnFilter(
683
+ agGridElement,
684
+ criteriaOptions[0].hasApplyButton,
685
+ criteriaOptions[0].noMenuTabs
686
+ );
687
+ });
688
+ }
689
+
542
690
  /**
543
691
  * * Performs a filter operation on the specified column and selects only the provided filterValue
544
692
  * @param agGridElement The get() selector for which ag grid table you wish to retrieve.
package/src/index.d.ts CHANGED
@@ -119,7 +119,11 @@ interface agGridColumnFilterSearchCriteriaOptionsWithOperator extends agGridColu
119
119
  operator?: string
120
120
  }
121
121
 
122
- interface agGridColumnFilterSearchCriteriaOptionsWithMultiFilter extends agGridColumnFilterSearchCriteriaOptionsWithOperator {
123
- /** Use if floating filter is multiselect checkboxes vs free form input */
124
- isMultiFilter?: boolean
125
- }
122
+ interface agGridColumnFilterSearchCriteriaOptionsWithMultiFilter extends agGridColumnFilterSearchCriteriaOptionsWithOperator {
123
+ /** Index of which visible filter input to use when the floating filter renders multiple inputs */
124
+ searchInputIndex?: number
125
+ /** Index of which visible operator dropdown to use when the floating filter renders multiple conditions */
126
+ operatorIndex?: number
127
+ /** Use if floating filter is multiselect checkboxes vs free form input */
128
+ isMultiFilter?: boolean
129
+ }