cypress-ag-grid 3.3.1 → 3.3.4

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.1",
3
+ "version": "3.3.4",
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
  }
@@ -22,8 +22,15 @@ export const agGridWaitForAnimation = async (agGridElement) => {
22
22
 
23
23
  const animations = agGridElement.get()[0].getAnimations({ subtree: true });
24
24
 
25
+ // Filter out infinite animations (e.g. loading spinners) whose .finished
26
+ // promise never resolves per the Web Animations API spec.
27
+ const finiteAnimations = animations.filter((animation) => {
28
+ const iterations = animation.effect?.getTiming?.()?.iterations;
29
+ return iterations !== Infinity;
30
+ });
31
+
25
32
  await Promise.all(
26
- animations.map(async (animation) => {
33
+ finiteAnimations.map(async (animation) => {
27
34
  try {
28
35
  await animation.finished;
29
36
  } catch (error) {
@@ -244,16 +251,22 @@ function getMenuTabElement(agGridElement, tab) {
244
251
  * @param tab
245
252
  */
246
253
  function selectMenuTab(agGridElement, tab) {
247
- getMenuTabElement(agGridElement, tab).then(($ele) => {
248
- cy.wrap($ele)
249
- .parent("span")
250
- .invoke("attr", "class")
251
- .then(($attr) => {
252
- if (!$attr.includes("selected")) {
253
- cy.wrap($ele).click();
254
- }
254
+ cy.get(agGridElement).then((agGr) => {
255
+ if (agGr.find('.ag-menu-list').length > 0) {
256
+ cy.log('Menu uses a list, not tabs');
257
+ } else {
258
+ getMenuTabElement(agGridElement, tab).then(($ele) => {
259
+ cy.wrap($ele)
260
+ .parent("span")
261
+ .invoke("attr", "class")
262
+ .then(($attr) => {
263
+ if (!$attr.includes("selected")) {
264
+ cy.wrap($ele).click();
265
+ }
266
+ });
255
267
  });
256
- });
268
+ }
269
+ })
257
270
  }
258
271
 
259
272
  /**
@@ -265,28 +278,54 @@ function getFilterColumnButtonElement(
265
278
  columnName,
266
279
  isFloatingFilter = false
267
280
  ) {
268
- let columnIndex;
269
- if (isFloatingFilter)
281
+ if (isFloatingFilter) {
270
282
  return getColumnHeaderElement(agGridElement, columnName)
271
283
  .parents(".ag-header-cell")
272
- .then(($ele) => {
273
- cy.wrap($ele)
274
- .invoke("attr", "aria-colindex")
275
- .then((colIndex) => {
276
- columnIndex = colIndex;
277
- })
278
- .then(() => {
279
- cy.wrap($ele)
280
- .parents(".ag-header-row-column")
281
- .siblings(".ag-header-row-column-filter")
282
- .find(`.ag-header-cell[aria-colindex=${columnIndex}]`)
283
- .find(".ag-floating-filter-button");
284
- });
284
+ .then(($headerCell) => {
285
+ const columnIndex = $headerCell.attr("aria-colindex");
286
+ const visibleHeaderCells = $headerCell
287
+ .closest(".ag-header")
288
+ .find(".ag-header-row-column .ag-header-cell:visible");
289
+ const headerPosition = visibleHeaderCells.index($headerCell);
290
+
291
+ return cy.get(agGridElement).then(($gridElement) => {
292
+ const usesV35FloatingFilterRow =
293
+ $gridElement.find(".ag-header-row-filter").length > 0;
294
+
295
+ let floatingFilterButton;
296
+
297
+ if (usesV35FloatingFilterRow) {
298
+ floatingFilterButton = $gridElement.find(
299
+ `.ag-header-row-filter .ag-header-cell[aria-colindex="${columnIndex}"] .ag-floating-filter-button:visible`
300
+ );
301
+
302
+ if (!floatingFilterButton.length && headerPosition > -1) {
303
+ floatingFilterButton = $gridElement
304
+ .find(".ag-header-row-filter .ag-floating-filter-button:visible")
305
+ .eq(headerPosition);
306
+ }
307
+ } else {
308
+ floatingFilterButton = $gridElement.find(
309
+ `.ag-header-row-column-filter .ag-header-cell[aria-colindex="${columnIndex}"] .ag-floating-filter-button-button:visible`
310
+ );
311
+
312
+ if (!floatingFilterButton.length && headerPosition > -1) {
313
+ floatingFilterButton = $gridElement
314
+ .find(
315
+ ".ag-header-row-column-filter .ag-floating-filter-button-button:visible"
316
+ )
317
+ .eq(headerPosition);
318
+ }
319
+ }
320
+
321
+ return cy.wrap(floatingFilterButton.first());
322
+ });
285
323
  });
286
- else
324
+ } else {
287
325
  return getColumnHeaderElement(agGridElement, columnName)
288
326
  .parent()
289
- .siblings(".ag-header-cell-menu-button");
327
+ .siblings(".ag-header-cell-filter-button");
328
+ }
290
329
  }
291
330
 
292
331
  /**
@@ -299,13 +338,16 @@ function filterBySearchTerm(agGridElement, options) {
299
338
  const filterValue = options.searchCriteria.filterValue;
300
339
  const operator = options.searchCriteria.operator;
301
340
  const searchInputIndex = options.searchCriteria.searchInputIndex || 0;
341
+ const operatorIndex =
342
+ options.searchCriteria.operatorIndex ??
343
+ (operator === filterOperator.inRange ? 0 : searchInputIndex);
302
344
  const isMultiFilter = options.searchCriteria.isMultiFilter;
303
345
  const noMenuTabs = options.noMenuTabs;
304
346
 
305
347
  // Navigate to the filter tab
306
- if (!noMenuTabs) {
307
- selectMenuTab(agGridElement, filterTab.filter);
308
- }
348
+ // if (!noMenuTabs) {
349
+ // selectMenuTab(agGridElement, filterTab.filter);
350
+ // }
309
351
 
310
352
  if (operator) {
311
353
  const elem = cy
@@ -313,7 +355,7 @@ function filterBySearchTerm(agGridElement, options) {
313
355
  .find(".ag-filter")
314
356
  .find(".ag-picker-field-wrapper")
315
357
  .filter(":visible")
316
- .eq(searchInputIndex);
358
+ .eq(operatorIndex);
317
359
  cy.get(agGridElement).agGridWaitForAnimation();
318
360
  elem.click();
319
361
  cy.get(agGridElement)
@@ -323,15 +365,20 @@ function filterBySearchTerm(agGridElement, options) {
323
365
  .click();
324
366
  }
325
367
  // Input filter term and allow grid a moment to render the results
326
- cy.get(agGridElement)
327
- .find(".ag-popup-child")
328
- .find("input")
329
- .filter(":visible")
330
- .as("filterInput");
368
+ if (
369
+ operator !== filterOperator.blank &&
370
+ operator !== filterOperator.notBlank
371
+ ) {
372
+ cy.get(agGridElement)
373
+ .find(".ag-popup-child")
374
+ .find("input")
375
+ .filter(":visible")
376
+ .as("filterInput");
377
+ }
331
378
 
332
379
  // If it's a multi filter, de-select the 'select-all' checkbox
333
380
  if (isMultiFilter) {
334
- const selectAllText = options.selectAllLocaleText || "Select All";
381
+ const selectAllText = options.selectAllLocaleText || "(Select All)";
335
382
  toggleColumnCheckboxFilter(agGridElement, selectAllText, false, true);
336
383
  }
337
384
 
@@ -341,7 +388,7 @@ function filterBySearchTerm(agGridElement, options) {
341
388
  operator !== filterOperator.notBlank
342
389
  ) {
343
390
  cy.get("@filterInput").then(($ele) => {
344
- cy.wrap($ele).eq(searchInputIndex).clear().type(filterValue);
391
+ cy.wrap($ele).eq(searchInputIndex).clear().type(filterValue + '{enter}');
345
392
  });
346
393
  }
347
394
 
@@ -359,7 +406,14 @@ function applyColumnFilter(agGridElement, hasApplyButton, noMenuTabs) {
359
406
  .click();
360
407
  }
361
408
  if (!noMenuTabs) {
362
- getMenuTabElement(agGridElement, filterTab.filter).click();
409
+ cy.get(agGridElement).then((agGr) => {
410
+ if (agGr.find('.ag-tab').length === 0) {
411
+ cy.log('Menu uses a list, not tabs');
412
+ cy.get(agGridElement).agGridWaitForAnimation();
413
+ } else {
414
+ getMenuTabElement(agGridElement, filterTab.filter).click();
415
+ }
416
+ })
363
417
  }
364
418
  }
365
419
 
@@ -375,9 +429,9 @@ function toggleColumnCheckboxFilter(
375
429
  doSelect,
376
430
  noMenuTabs = false
377
431
  ) {
378
- if (!noMenuTabs) {
379
- selectMenuTab(agGridElement, filterTab.filter);
380
- }
432
+ // if (!noMenuTabs) {
433
+ // selectMenuTab(agGridElement, filterTab.filter);
434
+ // }
381
435
  cy.get(agGridElement)
382
436
  .find(".ag-input-field-label")
383
437
  .contains(filterValue)
@@ -393,7 +447,7 @@ function populateSearchCriteria(
393
447
  searchCriteria,
394
448
  hasApplyButton = false,
395
449
  noMenuTabs = false,
396
- selectAllLocaleText = "Select All"
450
+ selectAllLocaleText = "(Select All)"
397
451
  ) {
398
452
  const options = {};
399
453
  options.searchCriteria = { ...searchCriteria };
@@ -487,24 +541,78 @@ function _filterBySearchTextColumnMenu(agGridElement, options) {
487
541
  * @param options.searchCriteria.operator [Optional] Use if using a search operator (i.e. Less Than, Equals, etc...use filterOperator.enum values).
488
542
  * @param options.hasApplyButton [Optional] True if "Apply" button is used, false if filters by text input automatically.
489
543
  * @param options.noMenuTabs [Optional] True if you use, for example, the community edition of ag-grid, which has no menu tabs
490
- * @param options.selectAllLocaleText [Optional] Pass in the locale text value of "Select All" for when you are filtering by checkbox - this wil first deselect the "Select All" option before selecting your filter value
544
+ * @param options.selectAllLocaleText [Optional] Pass in the locale text value of "(Select All)" for when you are filtering by checkbox - this wil first deselect the "(Select All)" option before selecting your filter value
491
545
  */
492
546
  export function filterBySearchTextColumnFloatingFilter(agGridElement, options) {
493
547
  // Check if there are multiple search criteria provided by attempting to access the columnName
494
548
  if (!options.searchCriteria.columnName) {
495
- options.searchCriteria.forEach((_searchCriteria) => {
496
- const _options = populateSearchCriteria(
497
- _searchCriteria,
498
- options.hasApplyButton,
499
- options.noMenuTabs
549
+ groupFloatingFilterSearchCriteria(
550
+ normalizeFloatingFilterSearchCriteria(options.searchCriteria)
551
+ ).forEach((searchCriteriaGroup) => {
552
+ const criteriaOptions = searchCriteriaGroup.map((_searchCriteria) =>
553
+ populateSearchCriteria(
554
+ _searchCriteria,
555
+ options.hasApplyButton,
556
+ options.noMenuTabs
557
+ )
500
558
  );
501
- _filterBySearchTextColumnFloatingFilter(agGridElement, _options);
559
+
560
+ if (criteriaOptions.length === 1) {
561
+ _filterBySearchTextColumnFloatingFilter(agGridElement, criteriaOptions[0]);
562
+ return;
563
+ }
564
+
565
+ _filterBySearchTextColumnFloatingFilterGroup(agGridElement, criteriaOptions);
502
566
  });
503
567
  } else {
504
568
  _filterBySearchTextColumnFloatingFilter(agGridElement, options);
505
569
  }
506
570
  }
507
571
 
572
+ function normalizeFloatingFilterSearchCriteria(searchCriteria) {
573
+ const betweenInputIndexes = new Map();
574
+
575
+ return searchCriteria.map((criteria) => {
576
+ if (
577
+ criteria.operator !== filterOperator.inRange ||
578
+ criteria.searchInputIndex !== undefined
579
+ ) {
580
+ return criteria;
581
+ }
582
+
583
+ const criteriaKey = `${criteria.columnName}::${criteria.operator}`;
584
+ const nextInputIndex = betweenInputIndexes.get(criteriaKey) || 0;
585
+ betweenInputIndexes.set(criteriaKey, nextInputIndex + 1);
586
+
587
+ return {
588
+ ...criteria,
589
+ searchInputIndex: nextInputIndex,
590
+ };
591
+ });
592
+ }
593
+
594
+ function groupFloatingFilterSearchCriteria(searchCriteria) {
595
+ const groupedCriteria = [];
596
+
597
+ searchCriteria.forEach((criteria) => {
598
+ const lastGroup = groupedCriteria[groupedCriteria.length - 1];
599
+
600
+ if (
601
+ criteria.operator === filterOperator.inRange &&
602
+ lastGroup &&
603
+ lastGroup[0].columnName === criteria.columnName &&
604
+ lastGroup[0].operator === criteria.operator
605
+ ) {
606
+ lastGroup.push(criteria);
607
+ return;
608
+ }
609
+
610
+ groupedCriteria.push([criteria]);
611
+ });
612
+
613
+ return groupedCriteria;
614
+ }
615
+
508
616
  function _filterBySearchTextColumnFloatingFilter(agGridElement, options) {
509
617
  cy.get(agGridElement).then((agGridElement) => {
510
618
  getFilterColumnButtonElement(
@@ -521,6 +629,37 @@ function _filterBySearchTextColumnFloatingFilter(agGridElement, options) {
521
629
  });
522
630
  }
523
631
 
632
+ function _filterBySearchTextColumnFloatingFilterGroup(
633
+ agGridElement,
634
+ criteriaOptions
635
+ ) {
636
+ cy.get(agGridElement).then((agGridElement) => {
637
+ getFilterColumnButtonElement(
638
+ agGridElement,
639
+ criteriaOptions[0].searchCriteria.columnName,
640
+ true
641
+ ).click();
642
+
643
+ criteriaOptions.forEach((criteriaOption, index) => {
644
+ const searchCriteria =
645
+ index === 0
646
+ ? criteriaOption.searchCriteria
647
+ : { ...criteriaOption.searchCriteria, operator: undefined };
648
+
649
+ filterBySearchTerm(agGridElement, {
650
+ ...criteriaOption,
651
+ searchCriteria,
652
+ });
653
+ });
654
+
655
+ applyColumnFilter(
656
+ agGridElement,
657
+ criteriaOptions[0].hasApplyButton,
658
+ criteriaOptions[0].noMenuTabs
659
+ );
660
+ });
661
+ }
662
+
524
663
  /**
525
664
  * * Performs a filter operation on the specified column and selects only the provided filterValue
526
665
  * @param agGridElement The get() selector for which ag grid table you wish to retrieve.
@@ -554,7 +693,7 @@ function _filterByCheckboxColumnMenu(agGridElement, options) {
554
693
  agGridElement,
555
694
  options.searchCriteria.columnName
556
695
  ).click();
557
- const selectAllText = options.selectAllLocaleText || "Select All";
696
+ const selectAllText = options.selectAllLocaleText || "(Select All)";
558
697
  toggleColumnCheckboxFilter(
559
698
  agGridElement,
560
699
  selectAllText,
@@ -11,5 +11,5 @@ export const filterOperator = {
11
11
  greaterThanOrEquals: "Greater than or equal to",
12
12
  inRange: "Between",
13
13
  blank: "Blank",
14
- notBlank: "Not Blank"
14
+ notBlank: "Not blank"
15
15
  }