testaro 2.3.11 → 3.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 +45 -56
- package/index.js +34 -117
- package/package.json +1 -1
- package/samples/scripts/simple.json +21 -0
- package/validation/executors/{appNoBatch.js → app.js} +15 -17
- package/validation/executors/test.js +18 -0
- package/validation/executors/tests.js +12 -14
- package/validation/executors/appBatch.js +0 -87
package/README.md
CHANGED
|
@@ -10,14 +10,20 @@ The purpose of Testaro is to provide programmatic access to over 600 accessibili
|
|
|
10
10
|
|
|
11
11
|
Running Testaro requires telling it which operations (including tests) to perform and which URLs to perform them on, and giving Testaro an object to put its output into.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Origin
|
|
14
|
+
|
|
15
|
+
Work on the custom tests in this package began in 2017, and work on the multi-package federation that Testaro implements began in early 2018. These two aspects were combined into the [Autotest](https://github.com/jrpool/autotest) package in early 2021 and into this more limited-purpose package, Testaro, in January 2022.
|
|
16
|
+
|
|
17
|
+
Testaro omits some functionalities of Autotest, such as:
|
|
18
|
+
- tests producing results intended to be human-inspected
|
|
19
|
+
- previous versions of scoring algorithms
|
|
20
|
+
- file operations for score aggregation, report revision, and HTML reports
|
|
21
|
+
- a web user interface
|
|
14
22
|
|
|
15
23
|
## System requirements
|
|
16
24
|
|
|
17
25
|
Version 14 or later of [Node.js](https://nodejs.org/en/).
|
|
18
26
|
|
|
19
|
-
A file system with a directory that the Testaro user has permission to read and write in.
|
|
20
|
-
|
|
21
27
|
## Dependencies
|
|
22
28
|
|
|
23
29
|
Testaro uses:
|
|
@@ -41,6 +47,10 @@ As of this version, the counts of tests in the packages referenced above were:
|
|
|
41
47
|
- Testaro tests: 16
|
|
42
48
|
- grand total: 628
|
|
43
49
|
|
|
50
|
+
## Related packages
|
|
51
|
+
|
|
52
|
+
[Testilo](https://github.com/jrpool/testilo) is an application that facilitates the use of Testaro.
|
|
53
|
+
|
|
44
54
|
## Code organization
|
|
45
55
|
|
|
46
56
|
The main directories containing code files are:
|
|
@@ -100,25 +110,25 @@ A script is a JSON file with the properties:
|
|
|
100
110
|
|
|
101
111
|
Here is an example of a script:
|
|
102
112
|
|
|
103
|
-
```
|
|
113
|
+
```javascript
|
|
104
114
|
{
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
115
|
+
what: 'Test example.com with alfa',
|
|
116
|
+
strict: true,
|
|
117
|
+
commands: [
|
|
108
118
|
{
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
119
|
+
type: 'launch',
|
|
120
|
+
which: 'chromium',
|
|
121
|
+
what: 'Chromium browser'
|
|
112
122
|
},
|
|
113
123
|
{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
type: 'url',
|
|
125
|
+
which: 'https://example.com/',
|
|
126
|
+
what: 'page with a few accessibility defects'
|
|
117
127
|
},
|
|
118
128
|
{
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
type: 'test',
|
|
130
|
+
which: 'alfa',
|
|
131
|
+
what: 'Siteimprove alfa package'
|
|
122
132
|
}
|
|
123
133
|
]
|
|
124
134
|
}
|
|
@@ -383,56 +393,32 @@ A typical use for an `expect` property is checking the correctness of a Testaro
|
|
|
383
393
|
|
|
384
394
|
## Batches
|
|
385
395
|
|
|
386
|
-
|
|
387
|
-
- The script can be the complete specification of the operations to perform and the URLs to perform them on.
|
|
388
|
-
- The script can specify the operations to perform, and a _batch_ can specify which URLs to perform them on.
|
|
389
|
-
|
|
390
|
-
A batch is a JSON file with this format:
|
|
391
|
-
|
|
392
|
-
```json
|
|
393
|
-
{
|
|
394
|
-
"what": "Accessibility standards",
|
|
395
|
-
"hosts": [
|
|
396
|
-
{
|
|
397
|
-
"which": "https://www.w3.org/TR/WCAG21/",
|
|
398
|
-
"what": "WCAG 2.1"
|
|
399
|
-
},
|
|
400
|
-
{
|
|
401
|
-
"which": "https://www.w3.org/WAI/standards-guidelines/aria/",
|
|
402
|
-
"what": "W3C WAI-ARIA"
|
|
403
|
-
}
|
|
404
|
-
]
|
|
405
|
-
}
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
When you combine a script with a batch, Testaro performs the script, replacing the `which` and `what` properties of all `url` commands with the values in the first object in the `hosts` array of the batch, then again with the values in the second `host` object, and so on. Those replacements also occur in the inserted extra `url` commands mentioned above.
|
|
396
|
+
In some cases you may wish to repeatedly run Testaro with the same script, changing only its `url` commands. The purpose would be to perform the same set of tests on multiple web pages. Such a use would apply only to scripts whose `url` commands are all identical, not to a script that moves from one host to another.
|
|
409
397
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
A no-batch script offers a way to carry out a complex operation, which can include navigating from one host to another, which is not possible with a batch. Any `url` commands are performed as-is, without changes to their URLs.
|
|
398
|
+
Testaro does not support such batch processing, but Testilo does. See its `README.md` file for instructions.
|
|
413
399
|
|
|
414
400
|
## Execution
|
|
415
401
|
|
|
416
402
|
### Invocation
|
|
417
403
|
|
|
418
|
-
To run Testaro, create
|
|
404
|
+
To run Testaro, create a report object like this:
|
|
419
405
|
|
|
420
406
|
```javascript
|
|
421
|
-
{
|
|
407
|
+
const report = {
|
|
408
|
+
id: '',
|
|
409
|
+
script: {…},
|
|
422
410
|
log: [],
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
batch: {def}
|
|
426
|
-
}
|
|
411
|
+
acts: []
|
|
412
|
+
};
|
|
427
413
|
```
|
|
428
414
|
|
|
429
|
-
Replace `{
|
|
415
|
+
Replace `{…}` with a script object, like the example script shown above.
|
|
430
416
|
|
|
431
|
-
|
|
417
|
+
Then execute the statement `require('testaro').handleRequest(report)`. That statement will run Testaro.
|
|
432
418
|
|
|
433
|
-
|
|
419
|
+
While it runs, Testaro will populate the `log` and `acts` arrays of the report object. When Testaro finishes, the `log` and `acts` properties will contain its results.
|
|
434
420
|
|
|
435
|
-
|
|
421
|
+
Another way to run Testaro is to use Testilo, which can handle batches and saves results to files. Testilo prepopulates the report object with an `id` property consisting of a timestamp and, if a batch is used, the host ID. If Testaro finds a non-empty `id` property in the `report` object, Testaro leaves it unchanged; if not, Testaro creates an `id` property with a timestamp value.
|
|
436
422
|
|
|
437
423
|
### Environment variables
|
|
438
424
|
|
|
@@ -442,11 +428,14 @@ Before executing a Testaro script, you can optionally also set the environment v
|
|
|
442
428
|
|
|
443
429
|
## Validation
|
|
444
430
|
|
|
445
|
-
|
|
431
|
+
_Executors_ for Testaro validation are located in the `validation` directory.
|
|
432
|
+
|
|
433
|
+
A basic executor is the `test.js` file. It runs Testaro with a simple sample script and outputs the log and the acts.
|
|
434
|
+
|
|
435
|
+
The other executors are commonJS JavaScript modules that run Testaro and report whether the results are correct.
|
|
446
436
|
|
|
447
|
-
The executors are:
|
|
448
|
-
- `
|
|
449
|
-
- `appBatch.js`: Reports whether Testaro runs correctly with a script and a batch.
|
|
437
|
+
The other executors are:
|
|
438
|
+
- `app.js`: Reports whether Testaro runs correctly with a script.
|
|
450
439
|
- `tests.js`: Runs Testaro with each custom test and reports whether the results are correct.
|
|
451
440
|
|
|
452
441
|
To execute any executor `xyz.js`, call it with the statement `node validation/executors/xyz`. The results will appear in the standard output.
|
package/index.js
CHANGED
|
@@ -194,38 +194,18 @@ const isValidScript = script => {
|
|
|
194
194
|
&& isURL(commands[1].which)
|
|
195
195
|
&& commands.every(command => isValidCommand(command));
|
|
196
196
|
};
|
|
197
|
-
// Validates a batch.
|
|
198
|
-
const isValidBatch = batch => {
|
|
199
|
-
// If the batch exists:
|
|
200
|
-
if (batch) {
|
|
201
|
-
// Get its data.
|
|
202
|
-
const {what, hosts} = batch;
|
|
203
|
-
// Return whether the batch is valid:
|
|
204
|
-
return what
|
|
205
|
-
&& hosts
|
|
206
|
-
&& typeof what === 'string'
|
|
207
|
-
&& Array.isArray(hosts)
|
|
208
|
-
&& hosts.every(host => host.which && host.what && isURL(host.which));
|
|
209
|
-
}
|
|
210
|
-
// Otherwise, i.e. if the batch does not exist:
|
|
211
|
-
else {
|
|
212
|
-
// Return that it is valid, because it is optional.
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
197
|
// Validates an initialized reports array.
|
|
217
|
-
const
|
|
198
|
+
const isValidActs = acts => Array.isArray(acts) && ! acts.length;
|
|
218
199
|
// Validates an initialized log array.
|
|
219
200
|
const isValidLog = log => Array.isArray(log) && ! log.length;
|
|
220
|
-
// Validates
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
223
|
-
const {id, script,
|
|
201
|
+
// Validates a report object.
|
|
202
|
+
const isValidReport = async report => {
|
|
203
|
+
if (report) {
|
|
204
|
+
const {id, script, log, acts} = report;
|
|
224
205
|
return id
|
|
225
206
|
&& isValidScript(script)
|
|
226
|
-
&& isValidBatch(batch)
|
|
227
207
|
&& isValidLog(log)
|
|
228
|
-
&&
|
|
208
|
+
&& isValidActs(acts);
|
|
229
209
|
}
|
|
230
210
|
else {
|
|
231
211
|
return false;
|
|
@@ -569,7 +549,7 @@ const waitError = (page, act, error, what) => {
|
|
|
569
549
|
act.result.error = `ERROR waiting for ${what}`;
|
|
570
550
|
return false;
|
|
571
551
|
};
|
|
572
|
-
// Recursively performs the
|
|
552
|
+
// Recursively performs the acts in a report.
|
|
573
553
|
const doActs = async (report, actIndex, page) => {
|
|
574
554
|
const {acts} = report;
|
|
575
555
|
// If any more commands are to be performed:
|
|
@@ -1009,7 +989,7 @@ const doActs = async (report, actIndex, page) => {
|
|
|
1009
989
|
// Otherwise, if it is entering text on the element:
|
|
1010
990
|
else if (act.type === 'text') {
|
|
1011
991
|
// If the text contains a placeholder for an environment variable:
|
|
1012
|
-
let {what} = act;
|
|
992
|
+
let {what} = act;
|
|
1013
993
|
if (/__[A-Z]+__/.test(what)) {
|
|
1014
994
|
// Replace it.
|
|
1015
995
|
const envKey = /__([A-Z]+)__/.exec(what)[1];
|
|
@@ -1079,7 +1059,7 @@ const doActs = async (report, actIndex, page) => {
|
|
|
1079
1059
|
}
|
|
1080
1060
|
};
|
|
1081
1061
|
// Performs the commands in a script.
|
|
1082
|
-
const doScript = async (
|
|
1062
|
+
const doScript = async (report) => {
|
|
1083
1063
|
// Reinitialize the log statistics.
|
|
1084
1064
|
logCount = logSize = prohibitedCount = visitTimeoutCount = visitRejectionCount= 0;
|
|
1085
1065
|
// Add the start time to the report.
|
|
@@ -1122,88 +1102,35 @@ const doScript = async (options, report) => {
|
|
|
1122
1102
|
const endTime = new Date();
|
|
1123
1103
|
report.endTime = endTime.toISOString().slice(0, 19);
|
|
1124
1104
|
report.elapsedSeconds = Math.floor((endTime - startTime) / 1000);
|
|
1125
|
-
// Add the report to the reports array.
|
|
1126
|
-
options.reports.push(report);
|
|
1127
|
-
};
|
|
1128
|
-
// Recursively performs commands on the hosts of a batch.
|
|
1129
|
-
const doBatch = async (options, reportTemplate, hostIndex = 0) => {
|
|
1130
|
-
const {hosts} = options.batch;
|
|
1131
|
-
const host = hosts[hostIndex];
|
|
1132
|
-
// If the specified host exists:
|
|
1133
|
-
if (host) {
|
|
1134
|
-
// Create a report for it.
|
|
1135
|
-
const hostReport = JSON.parse(JSON.stringify(reportTemplate));
|
|
1136
|
-
// Copy the properties of the specified host to all url acts.
|
|
1137
|
-
hostReport.acts.forEach(act => {
|
|
1138
|
-
if (act.type === 'url') {
|
|
1139
|
-
act.which = host.which;
|
|
1140
|
-
act.what = host.what;
|
|
1141
|
-
}
|
|
1142
|
-
});
|
|
1143
|
-
// Add the host’s ID to the host report.
|
|
1144
|
-
hostReport.hostName = host.id;
|
|
1145
|
-
// Add data from the template to the host report.
|
|
1146
|
-
hostReport.orderName = options.id;
|
|
1147
|
-
hostReport.id = `${options.id}-${host.id}`;
|
|
1148
|
-
hostReport.orderUserName = options.userName;
|
|
1149
|
-
hostReport.orderTime = options.orderTime;
|
|
1150
|
-
hostReport.assignedBy = options.assignedBy;
|
|
1151
|
-
hostReport.assignedTime = options.assignedTime;
|
|
1152
|
-
hostReport.tester = options.tester;
|
|
1153
|
-
hostReport.scriptName = options.scriptName;
|
|
1154
|
-
hostReport.batchName = options.batchName;
|
|
1155
|
-
hostReport.scriptIsValid = options.scriptIsValid;
|
|
1156
|
-
hostReport.batchIsValid = options.batchIsValid;
|
|
1157
|
-
hostReport.host = host;
|
|
1158
|
-
// Perform the commands on the host and add a report to the options object.
|
|
1159
|
-
await doScript(options, hostReport);
|
|
1160
|
-
// Process the remaining hosts.
|
|
1161
|
-
await doBatch(options, reportTemplate, hostIndex + 1);
|
|
1162
|
-
}
|
|
1163
|
-
};
|
|
1164
|
-
// Performs a script, with or without a batch.
|
|
1165
|
-
const doScriptOrBatch = async (options, reportTemplate) => {
|
|
1166
|
-
// If there is a batch:
|
|
1167
|
-
if (options.batch) {
|
|
1168
|
-
// Perform the script on all the hosts in the batch.
|
|
1169
|
-
console.log('Starting batch');
|
|
1170
|
-
await doBatch(options, reportTemplate);
|
|
1171
|
-
}
|
|
1172
|
-
// Otherwise, i.e. if there is no batch:
|
|
1173
|
-
else {
|
|
1174
|
-
// Perform the script.
|
|
1175
|
-
console.log('Starting no-batch script');
|
|
1176
|
-
await doScript(options, reportTemplate);
|
|
1177
|
-
}
|
|
1178
1105
|
// Add an end time to the log.
|
|
1179
|
-
|
|
1106
|
+
report.log.push({
|
|
1180
1107
|
event: 'endTime',
|
|
1181
1108
|
value: ((new Date()).toISOString().slice(0, 19))
|
|
1182
1109
|
});
|
|
1183
1110
|
};
|
|
1184
|
-
// Injects url
|
|
1185
|
-
const
|
|
1111
|
+
// Injects url acts into a report where necessary to undo DOM changes.
|
|
1112
|
+
const injectURLActs = acts => {
|
|
1186
1113
|
let injectMore = true;
|
|
1187
1114
|
while (injectMore) {
|
|
1188
|
-
const injectIndex =
|
|
1189
|
-
index <
|
|
1190
|
-
&&
|
|
1191
|
-
&&
|
|
1192
|
-
&& domChangers.has(
|
|
1115
|
+
const injectIndex = acts.findIndex((act, index) =>
|
|
1116
|
+
index < acts.length - 1
|
|
1117
|
+
&& act.type === 'test'
|
|
1118
|
+
&& acts[index + 1].type === 'test'
|
|
1119
|
+
&& domChangers.has(act.which)
|
|
1193
1120
|
);
|
|
1194
1121
|
if (injectIndex === -1) {
|
|
1195
1122
|
injectMore = false;
|
|
1196
1123
|
}
|
|
1197
1124
|
else {
|
|
1198
|
-
const lastURL =
|
|
1199
|
-
if (
|
|
1200
|
-
return
|
|
1125
|
+
const lastURL = acts.reduce((url, act, index) => {
|
|
1126
|
+
if (act.type === 'url' && index < injectIndex) {
|
|
1127
|
+
return act.which;
|
|
1201
1128
|
}
|
|
1202
1129
|
else {
|
|
1203
1130
|
return url;
|
|
1204
1131
|
}
|
|
1205
1132
|
}, '');
|
|
1206
|
-
|
|
1133
|
+
acts.splice(injectIndex + 1, 0, {
|
|
1207
1134
|
type: 'url',
|
|
1208
1135
|
which: lastURL,
|
|
1209
1136
|
what: 'URL'
|
|
@@ -1212,36 +1139,26 @@ const injectURLCommands = commands => {
|
|
|
1212
1139
|
}
|
|
1213
1140
|
};
|
|
1214
1141
|
// Handles a request.
|
|
1215
|
-
exports.handleRequest = async
|
|
1216
|
-
// If the
|
|
1217
|
-
if(
|
|
1218
|
-
// Add a start time
|
|
1219
|
-
|
|
1142
|
+
exports.handleRequest = async report => {
|
|
1143
|
+
// If the report object is valid:
|
|
1144
|
+
if(isValidReport(report)) {
|
|
1145
|
+
// Add a start time to the log.
|
|
1146
|
+
report.log.push(
|
|
1220
1147
|
{
|
|
1221
1148
|
event: 'startTime',
|
|
1222
1149
|
value: ((new Date()).toISOString().slice(0, 19))
|
|
1223
|
-
},
|
|
1224
|
-
{
|
|
1225
|
-
event: 'timeStamp',
|
|
1226
|
-
value: Math.floor((Date.now() - Date.UTC(2022, 1)) / 500).toString(36)
|
|
1227
1150
|
}
|
|
1228
1151
|
);
|
|
1229
|
-
// Add
|
|
1230
|
-
if (
|
|
1231
|
-
|
|
1232
|
-
event: 'batchSize',
|
|
1233
|
-
value: options.batch.hosts.length
|
|
1234
|
-
});
|
|
1152
|
+
// Add an ID to the report if none exists yet.
|
|
1153
|
+
if (! report.id) {
|
|
1154
|
+
report.id = Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
|
|
1235
1155
|
}
|
|
1236
|
-
//
|
|
1237
|
-
|
|
1238
|
-
host: '',
|
|
1239
|
-
acts: JSON.parse(JSON.stringify(options.script.commands))
|
|
1240
|
-
};
|
|
1156
|
+
// Add the script commands to the report as its initial acts.
|
|
1157
|
+
report.acts = JSON.parse(JSON.stringify(report.script.commands));
|
|
1241
1158
|
// Inject url acts where necessary to undo DOM changes.
|
|
1242
|
-
|
|
1243
|
-
// Perform the script,
|
|
1244
|
-
await
|
|
1159
|
+
injectURLActs(report.acts);
|
|
1160
|
+
// Perform the script, asynchronously adding to the log and report.
|
|
1161
|
+
await doScript(report);
|
|
1245
1162
|
}
|
|
1246
1163
|
else {
|
|
1247
1164
|
console.log('ERROR: options missing or invalid');
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"what": "Test example.com with alfa",
|
|
3
|
+
"strict": true,
|
|
4
|
+
"commands": [
|
|
5
|
+
{
|
|
6
|
+
"type": "launch",
|
|
7
|
+
"which": "chromium",
|
|
8
|
+
"what": "Chromium browser"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"type": "url",
|
|
12
|
+
"which": "https://example.com/",
|
|
13
|
+
"what": "page with a few accessibility defects"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "test",
|
|
17
|
+
"which": "alfa",
|
|
18
|
+
"what": "Siteimprove alfa package"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// app.js
|
|
2
2
|
// Validator for Testaro application with a no-batch script.
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const report = {
|
|
5
5
|
script: {
|
|
6
6
|
what: 'Sample Testaro executor with 1 test',
|
|
7
7
|
strict: true,
|
|
@@ -29,14 +29,14 @@ const options = {
|
|
|
29
29
|
]
|
|
30
30
|
},
|
|
31
31
|
log: [],
|
|
32
|
-
|
|
32
|
+
acts: []
|
|
33
33
|
};
|
|
34
34
|
const {handleRequest} = require(`${__dirname}/../../index`);
|
|
35
|
-
handleRequest(
|
|
35
|
+
handleRequest(report)
|
|
36
36
|
.then(
|
|
37
37
|
() => {
|
|
38
|
-
const {log,
|
|
39
|
-
if (log.length ===
|
|
38
|
+
const {log, acts} = report;
|
|
39
|
+
if (log.length === 2 && log[1].event === 'endTime' && /^\d{4}-.+$/.test(log[1].value)) {
|
|
40
40
|
console.log('Success: Log has been correctly populated');
|
|
41
41
|
}
|
|
42
42
|
else {
|
|
@@ -44,21 +44,19 @@ handleRequest(options)
|
|
|
44
44
|
console.log(JSON.stringify(log, null, 2));
|
|
45
45
|
}
|
|
46
46
|
if (
|
|
47
|
-
|
|
48
|
-
&&
|
|
49
|
-
&&
|
|
50
|
-
&&
|
|
51
|
-
&&
|
|
52
|
-
&& typeof
|
|
53
|
-
&&
|
|
54
|
-
&& typeof reports[0].acts[3].result === 'string'
|
|
55
|
-
&& reports[0].acts[3].result.startsWith('ERROR')
|
|
47
|
+
acts.length === 4
|
|
48
|
+
&& acts[2].result
|
|
49
|
+
&& acts[2].result.visibleElements
|
|
50
|
+
&& typeof acts[2].result.visibleElements === 'number'
|
|
51
|
+
&& acts[3].result
|
|
52
|
+
&& typeof acts[3].result === 'string'
|
|
53
|
+
&& acts[3].result.startsWith('ERROR')
|
|
56
54
|
) {
|
|
57
|
-
console.log('Success:
|
|
55
|
+
console.log('Success: Acts have been correctly populated');
|
|
58
56
|
}
|
|
59
57
|
else {
|
|
60
|
-
console.log('Failure:
|
|
61
|
-
console.log(JSON.stringify(
|
|
58
|
+
console.log('Failure: Acts empty or invalid');
|
|
59
|
+
console.log(JSON.stringify(acts, null, 2));
|
|
62
60
|
}
|
|
63
61
|
},
|
|
64
62
|
rejection => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// test.js
|
|
2
|
+
// Test executor.
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const {handleRequest} = require('../../index');
|
|
6
|
+
const scriptJSON = fs.readFileSync('samples/scripts/simple.json', 'utf8');
|
|
7
|
+
const script = JSON.parse(scriptJSON);
|
|
8
|
+
const report = {
|
|
9
|
+
id: '',
|
|
10
|
+
script,
|
|
11
|
+
log: [],
|
|
12
|
+
acts: []
|
|
13
|
+
};
|
|
14
|
+
(async () => {
|
|
15
|
+
await handleRequest(report);
|
|
16
|
+
console.log(`Report log:\n${JSON.stringify(report.log, null, 2)}\n`);
|
|
17
|
+
console.log(`Report acts:\n${JSON.stringify(report.acts, null, 2)}`);
|
|
18
|
+
})();
|
|
@@ -15,12 +15,12 @@ const validateTests = async () => {
|
|
|
15
15
|
const scriptJSON = rawScriptJSON
|
|
16
16
|
.replace(/__targets__/g, `file://${__dirname}/../tests/targets`);
|
|
17
17
|
const script = JSON.parse(scriptJSON);
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
await handleRequest(
|
|
22
|
-
const {log,
|
|
23
|
-
if (log.length ===
|
|
18
|
+
const report = {script};
|
|
19
|
+
report.log = [];
|
|
20
|
+
report.acts = [];
|
|
21
|
+
await handleRequest(report);
|
|
22
|
+
const {log, acts} = report;
|
|
23
|
+
if (log.length === 2 && log[1].event === 'endTime' && /^\d{4}-.+$/.test(log[1].value)) {
|
|
24
24
|
console.log('Success: Log has been correctly populated');
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
@@ -28,19 +28,17 @@ const validateTests = async () => {
|
|
|
28
28
|
console.log(JSON.stringify(log, null, 2));
|
|
29
29
|
}
|
|
30
30
|
if (
|
|
31
|
-
|
|
32
|
-
&&
|
|
33
|
-
&& reports[0].acts.length === script.commands.length
|
|
34
|
-
&& reports[0].acts.every(
|
|
31
|
+
acts.length === script.commands.length
|
|
32
|
+
&& acts.every(
|
|
35
33
|
act => act.type && act.type === 'test'
|
|
36
|
-
? act.result && act.result.failureCount !== undefined
|
|
34
|
+
? act.result && act.result.failureCount !== undefined
|
|
37
35
|
: true
|
|
38
36
|
)
|
|
39
37
|
) {
|
|
40
38
|
totals.attempts++;
|
|
41
39
|
totals.successes++;
|
|
42
40
|
console.log('Success: Reports have been correctly populated');
|
|
43
|
-
if (
|
|
41
|
+
if (acts.every(
|
|
44
42
|
act => act.type === 'test' ? act.result.failureCount === 0 : true
|
|
45
43
|
)) {
|
|
46
44
|
totals.attempts++;
|
|
@@ -50,13 +48,13 @@ const validateTests = async () => {
|
|
|
50
48
|
else {
|
|
51
49
|
totals.attempts++;
|
|
52
50
|
console.log('Failure: At least one test has at least one failure');
|
|
53
|
-
console.log(JSON.stringify(
|
|
51
|
+
console.log(JSON.stringify(acts, null, 2));
|
|
54
52
|
}
|
|
55
53
|
}
|
|
56
54
|
else {
|
|
57
55
|
totals.attempts++;
|
|
58
56
|
console.log('Failure: Reports empty or invalid');
|
|
59
|
-
console.log(JSON.stringify(
|
|
57
|
+
console.log(JSON.stringify(acts, null, 2));
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
console.log(`Grand totals: attempts ${totals.attempts}, successes ${totals.successes}`);
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// app.js
|
|
2
|
-
// Validator for Testaro application with a script and a batch.
|
|
3
|
-
|
|
4
|
-
const options = {
|
|
5
|
-
script: {
|
|
6
|
-
what: 'Sample Testaro executor with 1 test',
|
|
7
|
-
strict: true,
|
|
8
|
-
commands: [
|
|
9
|
-
{
|
|
10
|
-
type: 'launch',
|
|
11
|
-
which: 'chromium',
|
|
12
|
-
what: 'Chromium browser'
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
type: 'url',
|
|
16
|
-
which: 'https://*',
|
|
17
|
-
what: 'URL to be replaced with URLs in the batch'
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
type: 'test',
|
|
21
|
-
which: 'bulk',
|
|
22
|
-
what: 'bulk'
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
type: 'test',
|
|
26
|
-
which: 'noSuchTest',
|
|
27
|
-
what: 'test that does not exist'
|
|
28
|
-
}
|
|
29
|
-
]
|
|
30
|
-
},
|
|
31
|
-
batch: {
|
|
32
|
-
what: 'Two websites',
|
|
33
|
-
hosts: [
|
|
34
|
-
{
|
|
35
|
-
which: 'https://www.w3.org/',
|
|
36
|
-
what: 'W3C'
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
which: 'https://www.wikimedia.org/',
|
|
40
|
-
what: 'Wikimedia'
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
log: [],
|
|
45
|
-
reports: []
|
|
46
|
-
};
|
|
47
|
-
const {handleRequest} = require(`${__dirname}/../../index`);
|
|
48
|
-
const isValidReport = (reports, index) => {
|
|
49
|
-
const isValid = reports[index].acts
|
|
50
|
-
&& reports[index].acts.length === 4
|
|
51
|
-
&& reports[index].acts[2].result
|
|
52
|
-
&& reports[index].acts[2].result.visibleElements
|
|
53
|
-
&& typeof reports[index].acts[2].result.visibleElements === 'number'
|
|
54
|
-
&& reports[index].acts[3].result
|
|
55
|
-
&& typeof reports[index].acts[3].result === 'string'
|
|
56
|
-
&& reports[index].acts[3].result.startsWith('ERROR');
|
|
57
|
-
return isValid;
|
|
58
|
-
};
|
|
59
|
-
handleRequest(options)
|
|
60
|
-
.then(
|
|
61
|
-
() => {
|
|
62
|
-
const {log, reports} = options;
|
|
63
|
-
if (
|
|
64
|
-
log.length === 4
|
|
65
|
-
&& log[1].event === 'timeStamp'
|
|
66
|
-
&& /^[a-z0-9]+$/.test(log[1].value)
|
|
67
|
-
&& log[2].event === 'batchSize'
|
|
68
|
-
&& log[2].value === 2
|
|
69
|
-
) {
|
|
70
|
-
console.log('Success: Log has been correctly populated');
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
console.log('Failure: Log empty or invalid');
|
|
74
|
-
console.log(JSON.stringify(log, null, 2));
|
|
75
|
-
}
|
|
76
|
-
if (reports.length === 2 && isValidReport(reports, 0) && isValidReport(reports, 1)) {
|
|
77
|
-
console.log('Success: Reports have been correctly populated');
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
console.log('Failure: Reports empty or invalid');
|
|
81
|
-
console.log(JSON.stringify(reports, null, 2));
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
rejection => {
|
|
85
|
-
console.log(`Failure: ${rejection}`);
|
|
86
|
-
}
|
|
87
|
-
);
|