testaro 64.11.0 → 65.0.0
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/README.md +10 -6
- package/package.json +1 -1
- package/procs/doTestAct.js +51 -8
- package/run.js +187 -74
package/README.md
CHANGED
|
@@ -725,9 +725,10 @@ Here is an example of an instance in a standard result:
|
|
|
725
725
|
type: 'xpath',
|
|
726
726
|
spec: '/html[1]/body[1]/section[3]/div[2]/div[1]/ul[1]/li[1]/button[1]'
|
|
727
727
|
},
|
|
728
|
-
excerpt: '<button type="link"
|
|
728
|
+
excerpt: '<button type="link">Create an account</button>',
|
|
729
729
|
boxID: '12:340:46:50',
|
|
730
|
-
pathID: '/html/body/section[3]/div[2]/div/ul/li[1]/button[1]'
|
|
730
|
+
pathID: '/html/body/section[3]/div[2]/div/ul/li[1]/button[1]',
|
|
731
|
+
text: 'Create an account'
|
|
731
732
|
}
|
|
732
733
|
```
|
|
733
734
|
|
|
@@ -741,14 +742,15 @@ The element has no `id` attribute to distinguish it from other `button` elements
|
|
|
741
742
|
- `box` (coordinates, width, and height of the element box): Editoria11y, Testaro
|
|
742
743
|
- none: HTML CodeSniffer
|
|
743
744
|
|
|
744
|
-
The tool also reproduces an excerpt of the element code.
|
|
745
|
+
The tool or Testaro also reproduces an excerpt of the element code.
|
|
745
746
|
|
|
746
747
|
##### Element identification
|
|
747
748
|
|
|
748
|
-
While the above properties can help you find the offending element, Testaro makes this easier by adding, where practical,
|
|
749
|
+
While the above properties can help you find the offending element, Testaro makes this easier by adding, where practical, three standard element identifiers to each standard instance:
|
|
749
750
|
|
|
750
751
|
- `boxID`: a compact representation of the x, y, width, and height of the element bounding box, if the element can be identified and is visible.
|
|
751
752
|
- `pathID`: the XPath of the element, if the element can be identified.
|
|
753
|
+
- `text`: the text content of the element, if the element can be identified.
|
|
752
754
|
|
|
753
755
|
These standard identifiers can help you determine whether violations reported by different tools belong to the same element or different elements. The `boxID` property can also support the making of images of the violating elements.
|
|
754
756
|
|
|
@@ -757,7 +759,7 @@ Some tools limit the efficacy of the current algorithm for standard identifiers:
|
|
|
757
759
|
- HTML CodeSniffer does not report element locations, and the reported code excerpts exclude all text content.
|
|
758
760
|
- Nu Html Checker reports line and column boundaries of element start tags and truncates element text content in reported code excerpts.
|
|
759
761
|
|
|
760
|
-
Testaro aims to overcome these limitations by inserting uniquely identifying attributes into all elements of the pages being tested by these tools. Those attribute values
|
|
762
|
+
Testaro aims to overcome these limitations by inserting uniquely identifying attributes into all elements of the pages being tested by these tools. Those attribute values permit Testaro to identify the elements in the tested page. Except for elements excluded from the DOM, such as descendants of `noscript` elements, this mechanism allows Testaro to provide a `pathID` property in almost all standard instances. The `boxID` property is less universal, since some elements, such as `script` elements and hidden elements, have no bounding boxes.
|
|
761
763
|
|
|
762
764
|
Testing can change the pages being tested, and such changes can cause a particular element to change its physical or logical location. In such cases, an element may appear multiple times in a tool report with different `boxID` or `pathID` values, even though it is, for practical purposes, the same element.
|
|
763
765
|
|
|
@@ -966,7 +968,9 @@ The rationales motivating the Testaro-defined tests can be found in comments wit
|
|
|
966
968
|
|
|
967
969
|
On some occasions a test throws an error that cannot be handled with a `try`-`catch` structure. It has been observed, for example, that the `ibm` test does this when the page content, rather than the page URL, is given to `getCompliance()` and the target is `https://globalsolutions.org`, `https://monsido.com`, or `https://www.ambetterhealth.com/`.
|
|
968
970
|
|
|
969
|
-
Some tools take apparently infinite time to perform their tests on some pages.
|
|
971
|
+
Some tools take apparently infinite time to perform their tests on some pages. One website whose pages prevent 5 of the tools from ever completing their tests is the site of BrowserStack.
|
|
972
|
+
|
|
973
|
+
To handle such fatal errors andstalling, Testaro runs the tests of each tool in a separate forked child process that executes the `doTestAct.js` module. The parent process subjects each tool to a time limit and kills the child if the time limit expires.
|
|
970
974
|
|
|
971
975
|
### Activation
|
|
972
976
|
|
package/package.json
CHANGED
package/procs/doTestAct.js
CHANGED
|
@@ -22,12 +22,21 @@ const {browserClose, launch} = require(`${__dirname}/../run`);
|
|
|
22
22
|
// Module to set operating-system constants.
|
|
23
23
|
const os = require('os');
|
|
24
24
|
|
|
25
|
-
// CONSTANTS
|
|
26
|
-
|
|
27
|
-
const tmpDir = os.tmpdir();
|
|
28
|
-
|
|
29
25
|
// FUNCTIONS
|
|
30
26
|
|
|
27
|
+
// Sends a message to the parent process.
|
|
28
|
+
const sendMessage = message => {
|
|
29
|
+
try {
|
|
30
|
+
if (typeof process.send === 'function') {
|
|
31
|
+
process.send(message);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch(error) {
|
|
35
|
+
console.log(
|
|
36
|
+
`ERROR: process.send threw ${error.message} trying to send message ${message} to parent`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
31
40
|
// Performs the tests of an act.
|
|
32
41
|
const doTestAct = async (reportPath, actIndex) => {
|
|
33
42
|
// Get the report from the temporary directory.
|
|
@@ -58,7 +67,11 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
58
67
|
const reportJSON = JSON.stringify(report);
|
|
59
68
|
await fs.writeFile(reportPath, reportJSON);
|
|
60
69
|
// Report this.
|
|
61
|
-
|
|
70
|
+
sendMessage({
|
|
71
|
+
status: 'error',
|
|
72
|
+
error: 'Page launch aborted'
|
|
73
|
+
});
|
|
74
|
+
process.exit(1);
|
|
62
75
|
}
|
|
63
76
|
// Otherwise, i.e. if the launch did not abort the job:
|
|
64
77
|
else {
|
|
@@ -85,7 +98,10 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
85
98
|
// Save the revised report.
|
|
86
99
|
await fs.writeFile(reportPath, reportJSON);
|
|
87
100
|
// Send a completion message.
|
|
88
|
-
|
|
101
|
+
sendMessage({
|
|
102
|
+
status: 'ok',
|
|
103
|
+
});
|
|
104
|
+
process.exit(0);
|
|
89
105
|
}
|
|
90
106
|
// If the tool invocation failed:
|
|
91
107
|
catch(error) {
|
|
@@ -97,7 +113,11 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
97
113
|
// Report the failure.
|
|
98
114
|
const message = error.message.slice(0, 400);
|
|
99
115
|
console.log(`ERROR: Test act ${act.which} failed (${message})`);
|
|
100
|
-
|
|
116
|
+
sendMessage({
|
|
117
|
+
status: 'error',
|
|
118
|
+
error: 'ERROR performing the act'
|
|
119
|
+
});
|
|
120
|
+
process.exit(1);
|
|
101
121
|
};
|
|
102
122
|
}
|
|
103
123
|
// Otherwise, i.e. if the page does not exist:
|
|
@@ -116,9 +136,32 @@ const doTestAct = async (reportPath, actIndex) => {
|
|
|
116
136
|
// Report this.
|
|
117
137
|
const message = 'ERROR: No page';
|
|
118
138
|
console.log(message);
|
|
119
|
-
|
|
139
|
+
sendMessage({
|
|
140
|
+
status: 'error',
|
|
141
|
+
error: message
|
|
142
|
+
});
|
|
143
|
+
process.exit(1);
|
|
120
144
|
}
|
|
121
145
|
};
|
|
122
146
|
|
|
147
|
+
process.on('uncaughtException', error => {
|
|
148
|
+
console.log(`ERROR: uncaughtException (${error.message})`);
|
|
149
|
+
sendMessage({
|
|
150
|
+
status: 'error',
|
|
151
|
+
error: 'uncaughtException'
|
|
152
|
+
});
|
|
153
|
+
process.exit(1);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
process.on('unhandledRejection', error => {
|
|
157
|
+
const message = error && error.message ? error.message : String(error);
|
|
158
|
+
console.log(`ERROR: unhandledRejection (${message})`);
|
|
159
|
+
sendMessage({
|
|
160
|
+
status: 'error',
|
|
161
|
+
error: 'unhandledRejection'
|
|
162
|
+
});
|
|
163
|
+
process.exit(1);
|
|
164
|
+
});
|
|
165
|
+
|
|
123
166
|
const args = process.argv;
|
|
124
167
|
doTestAct(args[2], Number.parseInt(args[3]));
|
package/run.js
CHANGED
|
@@ -791,7 +791,7 @@ const launchSpecs = (act, report) => [
|
|
|
791
791
|
];
|
|
792
792
|
// Performs the acts in a report and adds the results to the report.
|
|
793
793
|
const doActs = async (report, opts = {}) => {
|
|
794
|
-
|
|
794
|
+
let {acts} = report;
|
|
795
795
|
// Get the granular observation options, if any.
|
|
796
796
|
const {onProgress = null, signal = null} = opts;
|
|
797
797
|
// Get the standardization specification.
|
|
@@ -885,9 +885,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
885
885
|
// If this failed:
|
|
886
886
|
if (! page) {
|
|
887
887
|
// Add this to the act.
|
|
888
|
-
|
|
889
|
-
act.data.prevented = true;
|
|
890
|
-
act.data.error = page.error || '';
|
|
888
|
+
addError(false, false, report, actIndex, page.error || '');
|
|
891
889
|
}
|
|
892
890
|
}
|
|
893
891
|
// Otherwise, if the act is a test act:
|
|
@@ -898,72 +896,154 @@ const doActs = async (report, opts = {}) => {
|
|
|
898
896
|
const startTime = Date.now();
|
|
899
897
|
// Add it to the act.
|
|
900
898
|
act.startTime = startTime;
|
|
901
|
-
// Save the report.
|
|
902
899
|
let reportJSON = JSON.stringify(report);
|
|
900
|
+
// Save a copy of the report.
|
|
903
901
|
await fs.writeFile(reportPath, reportJSON);
|
|
904
|
-
|
|
902
|
+
let timedOut = false;
|
|
903
|
+
const limitMs = timeoutMultiplier * 1000 * (timeLimits[act.which] || 15);
|
|
904
|
+
// Create a child process to perform the act and add the result to the saved report.
|
|
905
905
|
const actResult = await new Promise(resolve => {
|
|
906
906
|
let closed = false;
|
|
907
|
-
const child = fork(
|
|
908
|
-
|
|
909
|
-
|
|
907
|
+
const child = fork(`${__dirname}/procs/doTestAct`, [reportPath, actIndex]);
|
|
908
|
+
let killTimer = null;
|
|
909
|
+
// Start a timeout timer for the child process.
|
|
910
|
+
const timeoutTimer = setTimeout(() => {
|
|
911
|
+
if (! timedOut) {
|
|
912
|
+
timedOut = true;
|
|
913
|
+
console.log(`ERROR: Timed out at ${Math.round(limitMs / 1000)} seconds`);
|
|
914
|
+
child.kill('SIGTERM');
|
|
915
|
+
killTimer = setTimeout(() => {
|
|
916
|
+
if (! closed) {
|
|
917
|
+
console.log('ERROR: Failed to exit on SIGTERM from parent')
|
|
918
|
+
}
|
|
919
|
+
child.kill('SIGKILL');
|
|
920
|
+
}, 2000);
|
|
921
|
+
}
|
|
922
|
+
}, limitMs);
|
|
923
|
+
// Clears any current timers.
|
|
924
|
+
const clearTimers = () => {
|
|
925
|
+
[timeoutTimer, killTimer].forEach(timer => {
|
|
926
|
+
if (timer) {
|
|
927
|
+
clearTimeout(timer);
|
|
928
|
+
}
|
|
929
|
+
});
|
|
930
|
+
};
|
|
931
|
+
// If the child process sends a message (normally Act completed):
|
|
910
932
|
child.on('message', message => {
|
|
911
933
|
if (! closed) {
|
|
912
934
|
closed = true;
|
|
913
|
-
|
|
935
|
+
clearTimers();
|
|
936
|
+
// Return the message.
|
|
937
|
+
resolve({
|
|
938
|
+
kind: 'message',
|
|
939
|
+
message
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
// If the child process sends an error:
|
|
944
|
+
child.on('error', error => {
|
|
945
|
+
if (! closed) {
|
|
946
|
+
closed = true;
|
|
947
|
+
clearTimers();
|
|
948
|
+
// Return the error message.
|
|
949
|
+
resolve({
|
|
950
|
+
kind: 'error',
|
|
951
|
+
error: error.message
|
|
952
|
+
});
|
|
914
953
|
}
|
|
915
954
|
});
|
|
916
|
-
child
|
|
955
|
+
// If the child process closes:
|
|
956
|
+
child.on('close', (code, signal) => {
|
|
917
957
|
if (! closed) {
|
|
918
958
|
closed = true;
|
|
919
|
-
|
|
959
|
+
clearTimers();
|
|
960
|
+
// Return the exit code, signal, and timeout status.
|
|
961
|
+
resolve({
|
|
962
|
+
kind: 'close',
|
|
963
|
+
code,
|
|
964
|
+
signal,
|
|
965
|
+
timedOut
|
|
966
|
+
});
|
|
920
967
|
}
|
|
921
968
|
});
|
|
922
969
|
});
|
|
923
|
-
//
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
970
|
+
// If the child process sent a message:
|
|
971
|
+
if (actResult.kind === 'message') {
|
|
972
|
+
// Get the revised report file.
|
|
973
|
+
reportJSON = await fs.readFile(reportPath, 'utf8');
|
|
974
|
+
try {
|
|
975
|
+
// Convert it from JSON to an object and replace the report with the object.
|
|
976
|
+
report = JSON.parse(reportJSON);
|
|
977
|
+
// Redefine the acts as those in the revised report.
|
|
978
|
+
acts = report.acts;
|
|
979
|
+
}
|
|
980
|
+
// If the conversion fails, leaving the report and its acts unchanged:
|
|
981
|
+
catch (error) {
|
|
982
|
+
// Report this.
|
|
983
|
+
console.log(
|
|
984
|
+
`ERROR: Tool sent message ${actResult.message}. Report is no longer JSON (${error.message}) but is instead a(n) ${typeof reportJSON} of length ${reportJSON.length}:\n${reportJSON}`
|
|
985
|
+
);
|
|
986
|
+
// Add the error data to the act.
|
|
987
|
+
addError(
|
|
988
|
+
false,
|
|
989
|
+
false,
|
|
990
|
+
report,
|
|
991
|
+
actIndex,
|
|
992
|
+
`Non-JSON report file after message ${actResult.message}`
|
|
993
|
+
);
|
|
994
|
+
}
|
|
934
995
|
}
|
|
935
|
-
// Otherwise, i.e. if
|
|
996
|
+
// Otherwise, i.e. if the child process closed abnormally:
|
|
936
997
|
else {
|
|
937
|
-
// Add the
|
|
938
|
-
const
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
998
|
+
// Add the error data to the act.
|
|
999
|
+
const {code, error, kind, signal} = actResult;
|
|
1000
|
+
if (kind === 'close' && timedOut) {
|
|
1001
|
+
addError(
|
|
1002
|
+
false, false, report, actIndex, `Timed out at ${Math.round(limitMs / 1000)} seconds`
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
else if (kind === 'close') {
|
|
1006
|
+
addError(
|
|
1007
|
+
true, false, report, actIndex, `Closed with code ${code} and signal ${signal})`
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
addError(
|
|
1012
|
+
true, false, report, actIndex, `Terminated with error ${error}`
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
// Get the (usually revised) act.
|
|
1017
|
+
act = acts[actIndex];
|
|
1018
|
+
// Add the elapsed time of the tool to the report.
|
|
1019
|
+
const time = Math.round((Date.now() - startTime) / 1000);
|
|
1020
|
+
const {toolTimes} = report.jobData;
|
|
1021
|
+
toolTimes[act.which] ??= 0;
|
|
1022
|
+
toolTimes[act.which] += time;
|
|
1023
|
+
// If the act was not prevented:
|
|
1024
|
+
if (act.data && ! act.data.prevented) {
|
|
1025
|
+
const expectations = act.expect;
|
|
1026
|
+
// If the act has expectations:
|
|
1027
|
+
if (expectations) {
|
|
1028
|
+
// Initialize whether they were fulfilled.
|
|
1029
|
+
act.expectations = [];
|
|
1030
|
+
let failureCount = 0;
|
|
1031
|
+
// For each expectation:
|
|
1032
|
+
expectations.forEach(spec => {
|
|
1033
|
+
// Add its result to the act.
|
|
1034
|
+
const truth = isTrue(act, spec);
|
|
1035
|
+
act.expectations.push({
|
|
1036
|
+
property: spec[0],
|
|
1037
|
+
relation: spec[1],
|
|
1038
|
+
criterion: spec[2],
|
|
1039
|
+
actual: truth[0],
|
|
1040
|
+
passed: truth[1]
|
|
964
1041
|
});
|
|
965
|
-
|
|
966
|
-
|
|
1042
|
+
if (! truth[1]) {
|
|
1043
|
+
failureCount++;
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
act.expectationFailures = failureCount;
|
|
967
1047
|
}
|
|
968
1048
|
}
|
|
969
1049
|
}
|
|
@@ -1602,10 +1682,9 @@ const doActs = async (report, opts = {}) => {
|
|
|
1602
1682
|
// Notify the observer of the act and log it.
|
|
1603
1683
|
tellServer(report, messageParams, message);
|
|
1604
1684
|
}
|
|
1605
|
-
|
|
1685
|
+
}
|
|
1606
1686
|
// Notify the observer and log the start of standardization.
|
|
1607
1687
|
tellServer(report, '', 'Starting result standardization');
|
|
1608
|
-
}
|
|
1609
1688
|
const launchSpecActs = {};
|
|
1610
1689
|
// For each act:
|
|
1611
1690
|
report.acts.forEach((act, index) => {
|
|
@@ -1645,20 +1724,36 @@ const doActs = async (report, opts = {}) => {
|
|
|
1645
1724
|
};
|
|
1646
1725
|
// Populate it.
|
|
1647
1726
|
standardize(act);
|
|
1727
|
+
// If the original-format result is not to be included in the report:
|
|
1728
|
+
if (standard === 'only') {
|
|
1729
|
+
// Remove it.
|
|
1730
|
+
delete act.result;
|
|
1731
|
+
}
|
|
1732
|
+
// Notify the observer and log the start of identification.
|
|
1733
|
+
tellServer(report, '', 'Starting element identification');
|
|
1648
1734
|
// For each of its standard instances:
|
|
1649
1735
|
for (const instance of act.standardResult.instances) {
|
|
1650
|
-
|
|
1651
|
-
|
|
1736
|
+
let {boxID, pathID} = instance;
|
|
1737
|
+
// If the instance does not have both a box ID and a valid path ID:
|
|
1738
|
+
if (! boxID && (! pathID || pathID.includes(' '))) {
|
|
1652
1739
|
const elementID = await identify(instance, page);
|
|
1653
1740
|
// If it has no box ID but the element has a bounding box:
|
|
1654
|
-
if (elementID.boxID && !
|
|
1655
|
-
// Add a box ID.
|
|
1741
|
+
if (elementID.boxID && ! boxID) {
|
|
1742
|
+
// Add a box ID to the instance.
|
|
1656
1743
|
instance.boxID = elementID.boxID;
|
|
1657
1744
|
}
|
|
1658
|
-
// If it has no path ID
|
|
1659
|
-
if (
|
|
1660
|
-
//
|
|
1661
|
-
|
|
1745
|
+
// If it has no valid path ID:
|
|
1746
|
+
if (! pathID || pathID.includes(' ')) {
|
|
1747
|
+
// If the element has a valid path ID:
|
|
1748
|
+
if (elementID.pathID && ! elementID.pathID.includes(' ')) {
|
|
1749
|
+
// Add or replace the path ID of the instance.
|
|
1750
|
+
instance.pathID = elementID.pathID;
|
|
1751
|
+
}
|
|
1752
|
+
// Otherwise, if the instance has an invalid but uncorrectable path ID:
|
|
1753
|
+
else if (pathID) {
|
|
1754
|
+
// Delete it.
|
|
1755
|
+
delete instance.pathID;
|
|
1756
|
+
}
|
|
1662
1757
|
}
|
|
1663
1758
|
}
|
|
1664
1759
|
// If the instance excerpt contains a unique Testaro identifier attribute:
|
|
@@ -1669,12 +1764,22 @@ const doActs = async (report, opts = {}) => {
|
|
|
1669
1764
|
.replace(/ data-testaro-id="[^" ]*("|$)/g, '')
|
|
1670
1765
|
.replace(/ data-testaro-id="[^" ]* /g, ' ');
|
|
1671
1766
|
}
|
|
1767
|
+
pathID = instance.pathID;
|
|
1768
|
+
// If the instance has a pathID and no text property:
|
|
1769
|
+
if (pathID && ! instance.text) {
|
|
1770
|
+
// Get the element.
|
|
1771
|
+
const elementLoc = page.locator(`xpath=${pathID}`, {hasText: /.+/});
|
|
1772
|
+
// If it exists and is unique:
|
|
1773
|
+
if (await elementLoc.count() === 1) {
|
|
1774
|
+
let text = await elementLoc.textContent();
|
|
1775
|
+
if (text.length > 200) {
|
|
1776
|
+
text = `${text.slice(0, 150)} … ${text.slice(-50)}`;
|
|
1777
|
+
}
|
|
1778
|
+
// Add the text content or its ends to the instance.
|
|
1779
|
+
instance.text = text.trim();
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1672
1782
|
};
|
|
1673
|
-
// If the original-format result is not to be included in the report:
|
|
1674
|
-
if (standard === 'only') {
|
|
1675
|
-
// Remove it.
|
|
1676
|
-
delete act.result;
|
|
1677
|
-
}
|
|
1678
1783
|
};
|
|
1679
1784
|
}
|
|
1680
1785
|
// Otherwise, i.e. if the launch or navigation failed:
|
|
@@ -1682,9 +1787,9 @@ const doActs = async (report, opts = {}) => {
|
|
|
1682
1787
|
console.log(`ERROR: Launch or navigation to standardize ${specString} acts failed`);
|
|
1683
1788
|
}
|
|
1684
1789
|
};
|
|
1685
|
-
// Close the last browser launched for standardization.
|
|
1790
|
+
// Close the last browser launched for standardization and element identification.
|
|
1686
1791
|
await browserClose();
|
|
1687
|
-
console.log('Standardization completed');
|
|
1792
|
+
console.log('Standardization and element identification completed');
|
|
1688
1793
|
const {acts} = report;
|
|
1689
1794
|
const idData = {};
|
|
1690
1795
|
// For each act:
|
|
@@ -1697,15 +1802,17 @@ const doActs = async (report, opts = {}) => {
|
|
|
1697
1802
|
instanceCount: 0,
|
|
1698
1803
|
boxIDCount: 0,
|
|
1699
1804
|
pathIDCount: 0,
|
|
1805
|
+
textCount: 0,
|
|
1700
1806
|
boxIDPercent: null,
|
|
1701
|
-
pathIDPercent: null
|
|
1807
|
+
pathIDPercent: null,
|
|
1808
|
+
textPercent: null
|
|
1702
1809
|
};
|
|
1703
1810
|
const actIDData = idData[which];
|
|
1704
1811
|
const {standardResult} = act;
|
|
1705
1812
|
const {instances} = standardResult;
|
|
1706
1813
|
// For each standard instance in the act:
|
|
1707
1814
|
for (const instance of instances) {
|
|
1708
|
-
const {boxID, pathID} = instance;
|
|
1815
|
+
const {boxID, pathID, text} = instance;
|
|
1709
1816
|
// Increment the instance count.
|
|
1710
1817
|
actIDData.instanceCount++;
|
|
1711
1818
|
// If the instance has a box ID:
|
|
@@ -1718,13 +1825,19 @@ const doActs = async (report, opts = {}) => {
|
|
|
1718
1825
|
// Increment the path ID count.
|
|
1719
1826
|
actIDData.pathIDCount++;
|
|
1720
1827
|
}
|
|
1828
|
+
// If the instance has a text:
|
|
1829
|
+
if (text) {
|
|
1830
|
+
// Increment the text count.
|
|
1831
|
+
actIDData.textCount++;
|
|
1832
|
+
}
|
|
1721
1833
|
}
|
|
1722
|
-
const {instanceCount, boxIDCount, pathIDCount} = actIDData;
|
|
1834
|
+
const {instanceCount, boxIDCount, pathIDCount, textCount} = actIDData;
|
|
1723
1835
|
// If there are any instances:
|
|
1724
1836
|
if (instanceCount) {
|
|
1725
|
-
// Add the box ID
|
|
1837
|
+
// Add the box ID path ID, and text percentages to the iData property.
|
|
1726
1838
|
actIDData.boxIDPercent = Math.round(100 * boxIDCount / instanceCount);
|
|
1727
1839
|
actIDData.pathIDPercent = Math.round(100 * pathIDCount / instanceCount);
|
|
1840
|
+
actIDData.textPercent = Math.round(100 * textCount / instanceCount);
|
|
1728
1841
|
}
|
|
1729
1842
|
}
|
|
1730
1843
|
}
|