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 +21 -0
- package/README.md +3 -0
- package/docs/images/cypress-logo.png +0 -0
- package/package.json +10 -3
- package/src/agGrid/agGridInteractions.js +26 -200
- package/.circleci/config.yml +0 -14
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
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cypress-ag-grid",
|
|
3
|
-
"version": "3.
|
|
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": "
|
|
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": "
|
|
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 {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
55
|
-
|
|
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
|
-
|
|
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
|
-
|
|
106
|
-
|
|
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
|
package/.circleci/config.yml
DELETED
|
@@ -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
|