testaro 2.3.9 → 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 CHANGED
@@ -1,23 +1,29 @@
1
1
  # testaro
2
2
 
3
- Accessibility test automation
3
+ Federated accessibility test automation
4
4
 
5
5
  ## Summary
6
6
 
7
- Testaro is a collection of web accessibility tests.
7
+ Testaro is a collection of collections of web accessibility tests.
8
8
 
9
9
  The purpose of Testaro is to provide programmatic access to over 600 accessibility tests defined in several test packages and in Testaro itself.
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
- Testaro outputs progress messages to the standard output. It populates the object with log information and test reports.
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
- ```json
113
+ ```javascript
104
114
  {
105
- "what": "Test example.com with alfa",
106
- "strict": true,
107
- "commands": [
115
+ what: 'Test example.com with alfa',
116
+ strict: true,
117
+ commands: [
108
118
  {
109
- "type": "launch",
110
- "which": "chromium",
111
- "what": "Chromium browser"
119
+ type: 'launch',
120
+ which: 'chromium',
121
+ what: 'Chromium browser'
112
122
  },
113
123
  {
114
- "type": "url",
115
- "which": "https://example.com/",
116
- "what": "page with a few accessibility defects"
124
+ type: 'url',
125
+ which: 'https://example.com/',
126
+ what: 'page with a few accessibility defects'
117
127
  },
118
128
  {
119
- "type": "test",
120
- "which": "alfa",
121
- "what": "Siteimprove alfa package"
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
- There are two ways to use a script to give instructions to Testaro:
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.
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.
389
397
 
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.
409
-
410
- A batch offers an efficient way to perform a uniform set of operations on every host in a set of hosts. In this way you can run the same set of tests on multiple web pages.
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 an options object like this:
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
- reports: [],
424
- script: {abc},
425
- batch: {def}
426
- }
411
+ acts: []
412
+ };
427
413
  ```
428
414
 
429
- Replace `{abc}` with a script object, like the example script shown above.
415
+ Replace `{}` with a script object, like the example script shown above.
430
416
 
431
- Replace `{def}` with a batch object, like the example batch shown above, or omit the `batch` property if there is no batch.
417
+ Then execute the statement `require('testaro').handleRequest(report)`. That statement will run Testaro.
432
418
 
433
- Then execute the statement `require('testaro').handleRequest(ghi)`, where `ghi` is replaced with the name of the options object. That statement will run Testaro.
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
- While it runs, Testaro will populate the `log` and `reports` arrays of the options object. When Testaro finishes, the `log` and `reports` arrays will contain its results.
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
- Three _executors_ for Testaro validation are located in the `validation` directory. An executor is a commonJS JavaScript module that runs Testaro and reports whether the results are correct.
431
+ _Executors_ for Testaro validation are located in the `validation` directory.
446
432
 
447
- The executors are:
448
- - `appNoBatch.js`: Reports whether Testaro runs correctly with a no-batch script.
449
- - `appBatch.js`: Reports whether Testaro runs correctly with a script and a batch.
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.
436
+
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.
@@ -464,6 +453,7 @@ The rationales motivating the Testaro-defined tests and scoring procs can be fou
464
453
  ### Future work
465
454
 
466
455
  Further development is contemplated, is taking place, or is welcomed, on:
456
+ - addition of Tenon to the set of packages
467
457
  - links with href="#"
468
458
  - links and buttons styled non-distinguishably
469
459
  - first focused element not first focusable element in DOM
@@ -472,8 +462,6 @@ Further development is contemplated, is taking place, or is welcomed, on:
472
462
  - modal dialogs
473
463
  - autocomplete attributes
474
464
 
475
- Additional test packages may be integratable into Testaro. The [`bbc-a11y`](https://github.com/bbc/bbc-a11y) package has been considered, but it has not been updated since 2018 and has vulnerable dependencies.
476
-
477
465
  ## Testing challenges
478
466
 
479
467
  ### Activation
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 isValidReports = reports => Array.isArray(reports) && ! reports.length;
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 an options object.
221
- const isValidOptions = async options => {
222
- if (options) {
223
- const {id, script, batch, log, reports} = options;
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
- && isValidReports(reports);
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 commands in a report.
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 (options, report) => {
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
- options.log.push({
1106
+ report.log.push({
1180
1107
  event: 'endTime',
1181
1108
  value: ((new Date()).toISOString().slice(0, 19))
1182
1109
  });
1183
1110
  };
1184
- // Injects url commands into a report where necessary to undo DOM changes.
1185
- const injectURLCommands = commands => {
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 = commands.findIndex((command, index) =>
1189
- index < commands.length - 1
1190
- && command.type === 'test'
1191
- && commands[index + 1].type === 'test'
1192
- && domChangers.has(command.which)
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 = commands.reduce((url, command, index) => {
1199
- if (command.type === 'url' && index < injectIndex) {
1200
- return command.which;
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
- commands.splice(injectIndex + 1, 0, {
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 options => {
1216
- // If the options object is valid:
1217
- if(isValidOptions(options)) {
1218
- // Add a start time and a timeStamp to the log.
1219
- options.log.push(
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 the batch size to the log if there is a batch.
1230
- if (options.batch) {
1231
- options.log.push({
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
- // Create a report template, containing a copy of the commands as its acts.
1237
- const reportTemplate = {
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
- injectURLCommands(reportTemplate.acts);
1243
- // Perform the script, with or without a batch, asynchronously adding to the log and reports.
1244
- await doScriptOrBatch(options, reportTemplate);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "2.3.9",
3
+ "version": "3.0.0",
4
4
  "description": "Automation of accessibility testing",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -255,7 +255,7 @@ exports.scorer = acts => {
255
255
  facts = test.result;
256
256
  if (facts && facts.content && facts.url && (facts.content.totals || facts.url.totals)) {
257
257
  rules.ibm = 'multiply violations by 4*, recommendations by 2* (*discounted); sum';
258
- const scores = {
258
+ const ibmScores = {
259
259
  content: null,
260
260
  url: null
261
261
  };
@@ -263,7 +263,7 @@ exports.scorer = acts => {
263
263
  const totals = facts[type].totals;
264
264
  if (totals) {
265
265
  const items = facts[type].items || [];
266
- scores[type] = Math.round(items.reduce((total, item) => {
266
+ ibmScores[type] = Math.round(items.reduce((total, item) => {
267
267
  const {ruleId, level} = item;
268
268
  const rawScore = [4, 2][['violation', 'recommendation'].indexOf(level)] || 0;
269
269
  const divisor = duplications.ibm[`${level.slice(0, 1)}:${ruleId}`] + 1 || 1;
@@ -271,8 +271,8 @@ exports.scorer = acts => {
271
271
  }, 0));
272
272
  }
273
273
  });
274
- if (scores.content !== null || scores.url !== null) {
275
- scores.ibm = Math.max(scores.content || 0, scores.url || 0);
274
+ if (ibmScores.content !== null || ibmScores.url !== null) {
275
+ scores.ibm = Math.max(ibmScores.content || 0, ibmScores.url || 0);
276
276
  scores.total += scores.ibm;
277
277
  }
278
278
  }
@@ -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 options = {
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
- reports: []
32
+ acts: []
33
33
  };
34
34
  const {handleRequest} = require(`${__dirname}/../../index`);
35
- handleRequest(options)
35
+ handleRequest(report)
36
36
  .then(
37
37
  () => {
38
- const {log, reports} = options;
39
- if (log.length === 3 && log[1].event === 'timeStamp' && /^[a-z0-9]+$/.test(log[1].value)) {
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
- reports.length === 1
48
- && reports[0].acts
49
- && reports[0].acts.length === 4
50
- && reports[0].acts[2].result
51
- && reports[0].acts[2].result.visibleElements
52
- && typeof reports[0].acts[2].result.visibleElements === 'number'
53
- && reports[0].acts[3].result
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: Reports have been correctly populated');
55
+ console.log('Success: Acts have been correctly populated');
58
56
  }
59
57
  else {
60
- console.log('Failure: Reports empty or invalid');
61
- console.log(JSON.stringify(reports, null, 2));
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 options = {script};
19
- options.log = [];
20
- options.reports = [];
21
- await handleRequest(options);
22
- const {log, reports} = options;
23
- if (log.length === 3 && log[1].event === 'timeStamp' && /^[a-z0-9]+$/.test(log[1].value)) {
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
- reports.length === 1
32
- && reports[0].acts
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 (reports[0].acts.every(
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(reports, null, 2));
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(reports, null, 2));
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
- );