cypress-ag-grid 3.3.5 → 3.4.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/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # cypress-ag-grid
2
+
3
+ ## 3.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Update all published packages to declare the Apache-2.0 license and include the
8
+ repository license file for downstream consumers.
9
+ - Updated dependencies
10
+ - @kpmck/ag-grid-core@1.0.1
11
+
12
+ ## 3.4.0
13
+
14
+ ### Minor Changes
15
+
16
+ - 2a7e5d7: Move to monorepo structure to support more node-based testing tools for ag grid interactions and validations
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [2a7e5d7]
21
+ - @kpmck/ag-grid-core@1.0.0
package/README.md CHANGED
@@ -1,4 +1,7 @@
1
1
  # cypress-ag-grid
2
+
3
+ ![Cypress](./docs/images/cypress-logo.png)
4
+
2
5
  Cypress plugin for interacting with and validating against ag grid.
3
6
 
4
7
  ## Table of Contents
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress-ag-grid",
3
- "version": "3.3.5",
3
+ "version": "3.4.1",
4
4
  "description": "Cypress plugin to interact with ag grid",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -18,14 +18,21 @@
18
18
  "cypress aggrid"
19
19
  ],
20
20
  "scripts": {
21
- "test": "npx cypress run --headless --spec \"cypress/e2e/*.cy.js\"",
21
+ "test": "npm run test:all",
22
+ "test:all": "npx cypress run --headless --spec \"cypress/e2e/*.cy.js\"",
22
23
  "test:v33": "npx cypress run --headless --spec \"cypress/e2e/*.v33.cy.js\"",
23
24
  "test:v34": "npx cypress run --headless --spec \"cypress/e2e/*.v34.cy.js\"",
24
25
  "test:v35": "npx cypress run --headless --spec \"cypress/e2e/*.v35.cy.js\"",
25
26
  "test:watch": "npx cypress open"
26
27
  },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
27
31
  "author": "Kerry McKeever <kerry@kerrymckeever.com>",
28
- "license": "MIT",
32
+ "license": "Apache-2.0",
33
+ "dependencies": {
34
+ "@kpmck/ag-grid-core": "1.0.1"
35
+ },
29
36
  "devDependencies": {
30
37
  "cypress": "^15.12.0"
31
38
  }
@@ -1,99 +1,41 @@
1
1
  /// <reference types="cypress" />
2
- import { filterOperator } from "./filterOperator.enum";
3
- import { filterTab } from "./menuTab.enum";
4
- import { sort } from "./sort.enum";
5
-
6
- function isRowNotDestroyed(rowElement) {
7
- const rect = rowElement.getBoundingClientRect();
8
- const viewPortRect = rowElement.parentElement.getBoundingClientRect();
9
-
10
- return (
11
- rect.top >= viewPortRect.top &&
12
- rect.left >= viewPortRect.left &&
13
- rect.bottom <= viewPortRect.bottom &&
14
- rect.right <= viewPortRect.right
15
- );
16
- }
17
-
18
- export const agGridWaitForAnimation = async (agGridElement) => {
19
- if (agGridElement.get().length < 1) {
2
+ import {
3
+ extractAgGridData,
4
+ extractAgGridElements,
5
+ filterOperator,
6
+ filterTab,
7
+ sort,
8
+ waitForAgGridAnimation,
9
+ } from "@kpmck/ag-grid-core";
10
+
11
+ function getSingleAgGridRootElement(agGridElement) {
12
+ const rootElements = agGridElement.get();
13
+
14
+ if (rootElements.length < 1) {
20
15
  throw new Error(`Couldn't find the element ${agGridElement}`);
21
16
  }
22
17
 
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
18
+ if (rootElements.length > 1) {
19
+ throw new Error(
20
+ `Selector "${agGridElement.selector}" returned more than 1 element.`
44
21
  );
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
- });
22
+ }
53
23
 
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
- ]);
24
+ return rootElements[0];
25
+ }
70
26
 
27
+ export const agGridWaitForAnimation = async (agGridElement) => {
28
+ await waitForAgGridAnimation(getSingleAgGridRootElement(agGridElement));
71
29
  return agGridElement;
72
30
  };
73
31
 
74
- /**
75
- * Uses the attribute value's index and sorts the data accordingly.
76
- * For our purposes, we are getting the attribute with the items' indices and sorting accordingly.
77
- *
78
- * @param {*} index
79
- * @returns
80
- */
81
- function sortElementsByAttributeValue(attribute) {
82
- return (a, b) => {
83
- const contentA = parseInt(a.attributes[attribute].nodeValue, 10).valueOf();
84
- const contentB = parseInt(b.attributes[attribute].nodeValue, 10).valueOf();
85
- return contentA < contentB ? -1 : contentA > contentB ? 1 : 0;
86
- };
87
- }
88
-
89
32
  /**
90
33
  * Retrieves the values from the *displayed* page in ag grid and assigns each value to its respective column name.
91
34
  * @param agGridElement The get() selector for which ag grid table you wish to retrieve.
92
35
  * @param options Provide an array of columns you wish to exclude from the table retrieval.
93
36
  */
94
37
  export const getAgGridData = async (agGridElement, options = {}) => {
95
- await agGridWaitForAnimation(agGridElement);
96
- return _getAgGrid(agGridElement, options, false);
38
+ return extractAgGridData(getSingleAgGridRootElement(agGridElement), options);
97
39
  };
98
40
 
99
41
  /**
@@ -102,127 +44,11 @@ export const getAgGridData = async (agGridElement, options = {}) => {
102
44
  * @param options Provide an array of columns you wish to exclude from the table retrieval.
103
45
  */
104
46
  export const getAgGridElements = async (agGridElement, options = {}) => {
105
- await agGridWaitForAnimation(agGridElement);
106
- return _getAgGrid(agGridElement, options, true);
107
- };
108
-
109
- function _getAgGrid(agGridElement, options = {}, returnElements) {
110
- const agGridColumnSelectors =
111
- ".ag-pinned-left-cols-container^.ag-center-cols-clipper^.ag-center-cols-viewport^.ag-pinned-right-cols-container";
112
- if (agGridElement.get().length > 1)
113
- throw new Error(
114
- `Selector "${agGridElement.selector}" returned more than 1 element.`
115
- );
116
-
117
- const tableElement = agGridElement.get()[0].querySelectorAll(".ag-root")[0];
118
- const agGridSelectors = agGridColumnSelectors.split("^");
119
- const headers = [
120
- ...tableElement.querySelectorAll(".ag-header-row-column [aria-colindex]"),
121
- ]
122
- .sort(sortElementsByAttributeValue("aria-colindex"))
123
- .map((headerElement) => {
124
- // Check if the elements returned are already .ag-header-cell-text elements
125
- // If not, query for that element and return the text content
126
- let headerCells = [
127
- ...headerElement.querySelectorAll(".ag-header-cell-text"),
128
- ];
129
- if (headerCells.length === 0) {
130
- return [headerElement].map((e) => e.textContent.trim());
131
- } else {
132
- return [...headerElement.querySelectorAll(".ag-header-cell-text")].map(
133
- (e) => e.textContent.trim()
134
- );
135
- }
136
- })
137
- .flat();
138
-
139
- let allRows = [];
140
- let rows = [];
141
-
142
- agGridSelectors.forEach((selector) => {
143
- const _rows = [
144
- ...tableElement.querySelectorAll(
145
- `${selector}:not(.ag-hidden) .ag-row:not(.ag-opacity-zero)`
146
- ),
147
- ]
148
- // When animation is enabled, ag-grid destroys rows in 2 phases,
149
- // first it runs an animation to place rows to be destroyed just outside
150
- // the viewport.
151
- // In the second phase those rows are removed from the DOM.
152
- // Because we get here AFTER all animations are finished, it is possible,
153
- // those rows are still in the DOM, but are not visible.
154
- // therefore those rows should be filtered out.
155
- .filter(isRowNotDestroyed)
156
- // Sort rows by their row-index attribute value
157
- .sort(sortElementsByAttributeValue("row-index"))
158
- .map((row) => {
159
- // Sort row cells by their aria-colindex attribute value
160
- // First check if elements returned already contain the aria-colindex
161
- // If not, just query for the .ag-cell
162
- let rowCells = [...row.querySelectorAll(".ag-cell[aria-colindex]")];
163
- if (rowCells.length === 0) {
164
- rowCells = [...row.querySelectorAll(".ag-cell")];
165
- }
166
- const rowIndex = parseInt(
167
- row.attributes["row-index"].nodeValue,
168
- 10
169
- ).valueOf();
170
-
171
- if (allRows[rowIndex]) {
172
- allRows[rowIndex] = [...allRows[rowIndex], ...rowCells];
173
- } else {
174
- allRows[rowIndex] = rowCells;
175
- }
176
- });
177
- });
178
- // Remove any empty arrays before merging
179
- allRows = allRows.filter(function (ele) {
180
- return ele.length;
181
- });
182
-
183
- // Remove duplicate entries from allRows
184
- // In some instances we see cell duplication for non-unique rows
185
- allRows = allRows.map((row) => {
186
- return row.filter((cell, index) => {
187
- return row.indexOf(cell) === index;
188
- });
189
- });
190
-
191
- if (!allRows.length) rows = [];
192
- else {
193
- rows = allRows
194
- .filter((rowCells) => rowCells.length)
195
- .map((rowCells) =>
196
- rowCells
197
- .sort(sortElementsByAttributeValue("aria-colindex"))
198
- .map((e) => {
199
- if (returnElements) {
200
- return e;
201
- } else {
202
- return e.textContent.trim();
203
- }
204
- })
205
- );
206
- }
207
- // if options.rawValues = true, return headers & rows values as arrays instead of mapping as objects
208
- if (options.valuesArray) {
209
- return { headers, rows };
210
- }
211
- // return structured object from headers and rows variables
212
- return rows.map((row) =>
213
- row.reduce((acc, curr, idx) => {
214
- if (
215
- //@ts-ignore
216
- (options.onlyColumns && !options.onlyColumns.includes(headers[idx])) ||
217
- headers[idx] === undefined
218
- ) {
219
- // dont include columns that are not present in onlyColumns, or if the header is undefined
220
- return { ...acc };
221
- }
222
- return { ...acc, [headers[idx]]: curr };
223
- }, {})
47
+ return extractAgGridElements(
48
+ getSingleAgGridRootElement(agGridElement),
49
+ options
224
50
  );
225
- }
51
+ };
226
52
 
227
53
  /**
228
54
  * Retrieve the ag grid column header element based on its column name value
@@ -1,14 +0,0 @@
1
- # Use the latest 2.1 version of CircleCI pipeline process engine.
2
- # See: https://circleci.com/docs/2.0/configuration-reference
3
- version: 2.1
4
-
5
- orbs:
6
- # "cypress-io/cypress@1" installs the latest published
7
- # version "1.x.y" of the orb. We recommend you then use
8
- # the strict explicit version "cypress-io/cypress@1.x.y"
9
- # to lock the version and prevent unexpected CI changes
10
- cypress: cypress-io/cypress@3
11
- workflows:
12
- run_cypress_tests:
13
- jobs:
14
- - cypress/run # "run" job comes from "cypress" orb