testaro 64.9.0 → 64.9.2
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/package.json +1 -1
- package/procs/getLocatorData.js +74 -0
- package/procs/nu.js +3 -1
- package/procs/standardize.js +2 -2
- package/procs/testaro.js +4 -45
- package/run.js +25 -12
- package/tests/htmlcs.js +4 -1
- package/tests/nuVnu.js +5 -5
- package/tests/wax.js +3 -1
package/package.json
CHANGED
package/procs/getLocatorData.js
CHANGED
|
@@ -101,3 +101,77 @@ exports.getLocatorData = async loc => {
|
|
|
101
101
|
return null;
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
|
+
// Returns location data from the extract of a standard instance.
|
|
105
|
+
exports.getLocationData = async (page, excerpt) => {
|
|
106
|
+
const testaroIDArray = excerpt.match(/data-testaro-id="(\d+)#([^"]*)"/);
|
|
107
|
+
// If the extract contains a Testaro identifier:
|
|
108
|
+
if (testaroIDArray) {
|
|
109
|
+
const testaroID = `${testaroIDArray[1]}#${testaroIDArray[2]}`;
|
|
110
|
+
// Return location data for the element.
|
|
111
|
+
return await page.evaluate(testaroID => {
|
|
112
|
+
const element = document.querySelector(`[data-testaro-id="${testaroID}"]`);
|
|
113
|
+
// If any element has that identifier:
|
|
114
|
+
if (element) {
|
|
115
|
+
// Get a box ID for the element.
|
|
116
|
+
const box = {};
|
|
117
|
+
let boxID = '';
|
|
118
|
+
const boundingBox = element.getBoundingClientRect() || {};
|
|
119
|
+
if (boundingBox.x) {
|
|
120
|
+
['x', 'y', 'width', 'height'].forEach(coordinate => {
|
|
121
|
+
box[coordinate] = Math.round(boundingBox[coordinate]);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (typeof box.x === 'number') {
|
|
125
|
+
boxID = Object.values(box).join(':');
|
|
126
|
+
}
|
|
127
|
+
const oldPathID = testaroID.replace(/^.*?#/, '');
|
|
128
|
+
const newPathID = window.getXPath(element);
|
|
129
|
+
let pathID = '';
|
|
130
|
+
// If the XPath of the element is the same as that in the identifier:
|
|
131
|
+
if (newPathID === oldPathID) {
|
|
132
|
+
// Use it as the path ID.
|
|
133
|
+
pathID = oldPathID;
|
|
134
|
+
}
|
|
135
|
+
// Otherwise, if both paths exist but differ:
|
|
136
|
+
else if (oldPathID && newPathID) {
|
|
137
|
+
// Use both as a path ID.
|
|
138
|
+
pathID = `${newPathID} (originally: ${oldPathID})`;
|
|
139
|
+
}
|
|
140
|
+
// Otherwise, i.e. if only one of them exists:
|
|
141
|
+
else {
|
|
142
|
+
// Use the existing one as the path ID.
|
|
143
|
+
pathID = newPathID || oldPathID;
|
|
144
|
+
}
|
|
145
|
+
// Return the box and path IDs.
|
|
146
|
+
return {
|
|
147
|
+
boxID,
|
|
148
|
+
pathID
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// Otherwise, if no element has it but the identifier includes an XPath:
|
|
152
|
+
else if (testaroIDArray[2]) {
|
|
153
|
+
// Return an empty box ID and that XPath as a path ID.
|
|
154
|
+
return {
|
|
155
|
+
notInDOM: true,
|
|
156
|
+
boxID: '',
|
|
157
|
+
pathID: testaroIDArray[2]
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Otherwise, return empty location properties.
|
|
161
|
+
return {
|
|
162
|
+
notInDOM: true,
|
|
163
|
+
boxID: '',
|
|
164
|
+
pathID: ''
|
|
165
|
+
};
|
|
166
|
+
}, testaroID);
|
|
167
|
+
}
|
|
168
|
+
// Otherwise, i.e. if the extract contains no Testaro identifier:
|
|
169
|
+
else {
|
|
170
|
+
// Return a non-DOM location.
|
|
171
|
+
return {
|
|
172
|
+
notInDOM: true,
|
|
173
|
+
boxID: '',
|
|
174
|
+
pathID: ''
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
};
|
package/procs/nu.js
CHANGED
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
// ########## IMPORTS
|
|
16
16
|
|
|
17
17
|
// Module to add Testaro IDs to elements.
|
|
18
|
-
const {addTestaroIDs
|
|
18
|
+
const {addTestaroIDs} = require('./testaro');
|
|
19
|
+
// Module to get location data from an element.
|
|
20
|
+
const {getLocationData} = require('./getLocatorData');
|
|
19
21
|
// Module to get the document source.
|
|
20
22
|
const {getSource} = require('./getSource');
|
|
21
23
|
|
package/procs/standardize.js
CHANGED
|
@@ -42,8 +42,8 @@ const getIdentifiers = code => {
|
|
|
42
42
|
const tagNameArray = startTagData[1].match(/^[A-Za-z0-9]+/);
|
|
43
43
|
const tagName = tagNameArray ? tagNameArray[0].toUpperCase() : '';
|
|
44
44
|
// Get the value of the id attribute, if any.
|
|
45
|
-
const
|
|
46
|
-
const id =
|
|
45
|
+
const identifierData = startTagData[1].match(/ id="([^"]+)"/);
|
|
46
|
+
const id = identifierData ? identifierData[1] : '';
|
|
47
47
|
// Return the tag name and the value of the id attribute, if any.
|
|
48
48
|
return [tagName, id];
|
|
49
49
|
}
|
package/procs/testaro.js
CHANGED
|
@@ -227,54 +227,13 @@ exports.getVisibleCountChange = async (
|
|
|
227
227
|
};
|
|
228
228
|
// Annotates every element on a page with a unique identifier.
|
|
229
229
|
exports.addTestaroIDs = async page => {
|
|
230
|
+
// Wait for the page to be fully loaded.
|
|
231
|
+
await page.waitForLoadState('networkidle');
|
|
230
232
|
await page.evaluate(() => {
|
|
231
233
|
let serialID = 0;
|
|
232
234
|
for (const element of Array.from(document.querySelectorAll('*'))) {
|
|
233
|
-
|
|
235
|
+
const xPath = window.getXPath(element);
|
|
236
|
+
element.setAttribute('data-testaro-id', `${serialID++}#${xPath}`);
|
|
234
237
|
}
|
|
235
238
|
});
|
|
236
239
|
};
|
|
237
|
-
// Returns location data from the extract of a standard instance.
|
|
238
|
-
exports.getLocationData = async (page, excerpt) => {
|
|
239
|
-
const testaroIDArray = excerpt.match(/data-testaro-id="(\d+)#"/);
|
|
240
|
-
// If the excerpt contains a Testaro identifier:
|
|
241
|
-
if (testaroIDArray) {
|
|
242
|
-
const testaroID = testaroIDArray[1];
|
|
243
|
-
// Return location data for the element.
|
|
244
|
-
return await page.evaluate(testaroID => {
|
|
245
|
-
const element = document.querySelector(`[data-testaro-id="${testaroID}#"]`);
|
|
246
|
-
// If any element has that identifier:
|
|
247
|
-
if (element) {
|
|
248
|
-
// Get box and path IDs for the element.
|
|
249
|
-
const box = {};
|
|
250
|
-
let boxID = '';
|
|
251
|
-
const boundingBox = element.getBoundingClientRect() || {};
|
|
252
|
-
if (boundingBox.x) {
|
|
253
|
-
['x', 'y', 'width', 'height'].forEach(coordinate => {
|
|
254
|
-
box[coordinate] = Math.round(boundingBox[coordinate]);
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
if (typeof box.x === 'number') {
|
|
258
|
-
boxID = Object.values(box).join(':');
|
|
259
|
-
}
|
|
260
|
-
const pathID = window.getXPath(element) || '';
|
|
261
|
-
// Return them.
|
|
262
|
-
return {
|
|
263
|
-
boxID,
|
|
264
|
-
pathID
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
// Otherwise, i.e. if no element has it, return empty location data.
|
|
268
|
-
return {};
|
|
269
|
-
}, testaroID);
|
|
270
|
-
}
|
|
271
|
-
// Otherwise, i.e. if the extract contains no Testaro identifier:
|
|
272
|
-
else {
|
|
273
|
-
// Return a non-DOM location.
|
|
274
|
-
return {
|
|
275
|
-
notInDOM: true,
|
|
276
|
-
boxID: '',
|
|
277
|
-
pathID: ''
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
};
|
package/run.js
CHANGED
|
@@ -374,7 +374,6 @@ const launch = exports.launch = async (
|
|
|
374
374
|
// If the page emits a message:
|
|
375
375
|
page.on('console', msg => {
|
|
376
376
|
const msgText = msg.text();
|
|
377
|
-
let indentedMsg = '';
|
|
378
377
|
// If debugging is on:
|
|
379
378
|
if (debug) {
|
|
380
379
|
// Log the start of the message on the console.
|
|
@@ -917,7 +916,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
917
916
|
child.on('close', code => {
|
|
918
917
|
if (! closed) {
|
|
919
918
|
closed = true;
|
|
920
|
-
resolve(code);
|
|
919
|
+
resolve(`Page closed with code ${code}`);
|
|
921
920
|
}
|
|
922
921
|
});
|
|
923
922
|
});
|
|
@@ -1648,16 +1647,19 @@ const doActs = async (report, opts = {}) => {
|
|
|
1648
1647
|
standardize(act);
|
|
1649
1648
|
// For each of its standard instances:
|
|
1650
1649
|
for (const instance of act.standardResult.instances) {
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
//
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
//
|
|
1660
|
-
|
|
1650
|
+
// If the instance does not have both a box ID and a path ID:
|
|
1651
|
+
if (! (instance.boxID && instance.pathID)) {
|
|
1652
|
+
const elementID = await identify(instance, page);
|
|
1653
|
+
// If it has no box ID but the element has a bounding box:
|
|
1654
|
+
if (elementID.boxID && ! instance.boxID) {
|
|
1655
|
+
// Add a box ID.
|
|
1656
|
+
instance.boxID = elementID.boxID;
|
|
1657
|
+
}
|
|
1658
|
+
// If it has no path ID but the element has one:
|
|
1659
|
+
if (elementID.pathID && ! instance.pathID) {
|
|
1660
|
+
// Add a path ID.
|
|
1661
|
+
instance.pathID = elementID.pathID;
|
|
1662
|
+
}
|
|
1661
1663
|
}
|
|
1662
1664
|
};
|
|
1663
1665
|
// If the original-format result is not to be included in the report:
|
|
@@ -1677,9 +1679,12 @@ const doActs = async (report, opts = {}) => {
|
|
|
1677
1679
|
console.log('Standardization completed');
|
|
1678
1680
|
const {acts} = report;
|
|
1679
1681
|
const idData = {};
|
|
1682
|
+
// For each act:
|
|
1680
1683
|
for (const act of acts) {
|
|
1684
|
+
// If it is a test act:
|
|
1681
1685
|
if (act.type === 'test') {
|
|
1682
1686
|
const {which} = act;
|
|
1687
|
+
// Initialize an idData property for the tool if necessary.
|
|
1683
1688
|
idData[which] ??= {
|
|
1684
1689
|
instanceCount: 0,
|
|
1685
1690
|
boxIDCount: 0,
|
|
@@ -1690,18 +1695,26 @@ const doActs = async (report, opts = {}) => {
|
|
|
1690
1695
|
const actIDData = idData[which];
|
|
1691
1696
|
const {standardResult} = act;
|
|
1692
1697
|
const {instances} = standardResult;
|
|
1698
|
+
// For each standard instance in the act:
|
|
1693
1699
|
for (const instance of instances) {
|
|
1694
1700
|
const {boxID, pathID} = instance;
|
|
1701
|
+
// Increment the instance count.
|
|
1695
1702
|
actIDData.instanceCount++;
|
|
1703
|
+
// If the instance has a box ID:
|
|
1696
1704
|
if (boxID) {
|
|
1705
|
+
// Increment the box ID count.
|
|
1697
1706
|
actIDData.boxIDCount++;
|
|
1698
1707
|
}
|
|
1708
|
+
// If the instance has a path ID:
|
|
1699
1709
|
if (pathID) {
|
|
1710
|
+
// Increment the path ID count.
|
|
1700
1711
|
actIDData.pathIDCount++;
|
|
1701
1712
|
}
|
|
1702
1713
|
}
|
|
1703
1714
|
const {instanceCount, boxIDCount, pathIDCount} = actIDData;
|
|
1715
|
+
// If there are any instances:
|
|
1704
1716
|
if (instanceCount) {
|
|
1717
|
+
// Add the box ID and path ID percentages to the iData property.
|
|
1705
1718
|
actIDData.boxIDPercent = Math.round(100 * boxIDCount / instanceCount);
|
|
1706
1719
|
actIDData.pathIDPercent = Math.round(100 * pathIDCount / instanceCount);
|
|
1707
1720
|
}
|
package/tests/htmlcs.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2022–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Jonathan Robert Pool.
|
|
3
4
|
|
|
4
5
|
Licensed under the MIT License. See LICENSE file at the project root or
|
|
5
6
|
https://opensource.org/license/mit/ for details.
|
|
@@ -15,7 +16,9 @@
|
|
|
15
16
|
// IMPORTS
|
|
16
17
|
|
|
17
18
|
// Module to add and use unique element IDs.
|
|
18
|
-
const {addTestaroIDs
|
|
19
|
+
const {addTestaroIDs} = require('../procs/testaro');
|
|
20
|
+
// Module to get location data from an element.
|
|
21
|
+
const {getLocationData} = require('../procs/getLocatorData');
|
|
19
22
|
// Module to handle files.
|
|
20
23
|
const fs = require('fs/promises');
|
|
21
24
|
|
package/tests/nuVnu.js
CHANGED
|
@@ -33,7 +33,7 @@ const tmpDir = os.tmpdir();
|
|
|
33
33
|
|
|
34
34
|
// Conducts and reports the Nu Html Checker tests.
|
|
35
35
|
exports.reporter = async (page, report, actIndex) => {
|
|
36
|
-
// Get the
|
|
36
|
+
// Get the nuVal act, if it exists.
|
|
37
37
|
const nuValAct = report.acts.find(act => act.type === 'test' && act.which === 'nuVal');
|
|
38
38
|
// If it does not exist or it exists but was prevented:
|
|
39
39
|
if (! nuValAct || nuValAct.data?.prevented) {
|
|
@@ -70,6 +70,10 @@ exports.reporter = async (page, report, actIndex) => {
|
|
|
70
70
|
await fs.unlink(pagePath);
|
|
71
71
|
// Postprocess the result.
|
|
72
72
|
result = await curate(page, data, nuData, rules);
|
|
73
|
+
return {
|
|
74
|
+
data,
|
|
75
|
+
result
|
|
76
|
+
};
|
|
73
77
|
}
|
|
74
78
|
// Otherwise, i.e. if the content was not obtained:
|
|
75
79
|
else {
|
|
@@ -77,10 +81,6 @@ exports.reporter = async (page, report, actIndex) => {
|
|
|
77
81
|
data.prevented = true;
|
|
78
82
|
data.error = 'Content not obtained';
|
|
79
83
|
}
|
|
80
|
-
return {
|
|
81
|
-
data,
|
|
82
|
-
result
|
|
83
|
-
};
|
|
84
84
|
}
|
|
85
85
|
// Otherwise, i.e. if the nuVal act exists and succeeded:
|
|
86
86
|
else {
|
package/tests/wax.js
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
// IMPORTS
|
|
17
17
|
|
|
18
18
|
// Module to add and use unique element IDs.
|
|
19
|
-
const {addTestaroIDs
|
|
19
|
+
const {addTestaroIDs} = require('../procs/testaro');
|
|
20
|
+
// Module to get location data from an element.
|
|
21
|
+
const {getLocationData} = require('../procs/getLocatorData');
|
|
20
22
|
// Modules to run WAX.
|
|
21
23
|
const runWax = require('@wally-ax/wax-dev');
|
|
22
24
|
const waxDev = {runWax};
|