testaro 2.2.7 → 2.3.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
@@ -38,8 +38,8 @@ As of this version, the counts of tests in the packages referenced above were:
38
38
  - Equal Access: 163
39
39
  - WAVE: 110
40
40
  - subtotal: 612
41
- - Testaro tests: 15
42
- - grand total: 627
41
+ - Testaro tests: 16
42
+ - grand total: 628
43
43
 
44
44
  ## Code organization
45
45
 
@@ -279,6 +279,8 @@ The data for scores can include not only test results, but also log statistics.
279
279
  - `visitTimeoutCount`: how many times an attempt to visit a URL timed out
280
280
  - `visitRejectionCount`: how many times a URL visit got an HTTP status other than 200 or 304
281
281
 
282
+ Those log statistics can provide data for a log-based test defined in a score proc.
283
+
282
284
  A good score proc takes account of duplications between test packages: two or more packages that discover the same accessibility defects. Score procs can apply discounts to reflect duplications between test packages, so that, if two or more packages discover the same defect, the defect will not be overweighted.
283
285
 
284
286
  The procedures in the `scoring` directory have produced data there that score procs can use for the calibration of discounts.
package/commands.js CHANGED
@@ -119,11 +119,11 @@ exports.commands = {
119
119
  }
120
120
  ],
121
121
  text: [
122
- 'Enter text into a text input',
122
+ 'Enter text into a text input, optionally with 1 placeholder for an all-caps literal environment variable',
123
123
  {
124
124
  which: [true, 'string', 'hasLength', 'substring of input text'],
125
125
  index: [false, 'number', '', 'index among matches if not 0'],
126
- what: [true, 'string', 'hasLength', 'text to enter']
126
+ what: [true, 'string', 'hasLength', 'text to enter, with optional __PLACEHOLDER__']
127
127
  }
128
128
  ],
129
129
  url: [
package/index.js CHANGED
@@ -1006,8 +1006,17 @@ const doActs = async (report, actIndex, page) => {
1006
1006
  ? `“${optionText}}” selected`
1007
1007
  : 'ERROR: option not found';
1008
1008
  }
1009
- // Otherwise, if it is entering text on the element, perform it.
1009
+ // Otherwise, if it is entering text on the element:
1010
1010
  else if (act.type === 'text') {
1011
+ // If the text contains a placeholder for an environment variable:
1012
+ let {what} = act;
1013
+ if (/__[A-Z]+__/.test(what)) {
1014
+ // Replace it.
1015
+ const envKey = /__([A-Z]+)__/.exec(what)[1];
1016
+ const envValue = process.env[envKey];
1017
+ what = what.replace(/__[A-Z]+__/, envValue);
1018
+ }
1019
+ // Enter the text.
1011
1020
  await whichElement.type(act.what);
1012
1021
  report.presses += act.what.length;
1013
1022
  act.result = 'entered';
@@ -1138,6 +1147,9 @@ const doBatch = async (options, reportTemplate, hostIndex = 0) => {
1138
1147
  hostReport.id = `${options.id}-${host.id}`;
1139
1148
  hostReport.orderUserName = options.userName;
1140
1149
  hostReport.orderTime = options.orderTime;
1150
+ hostReport.assignedBy = options.assignedBy;
1151
+ hostReport.assignedTime = options.assignedTime;
1152
+ hostReport.tester = options.tester;
1141
1153
  hostReport.scriptName = options.scriptName;
1142
1154
  hostReport.batchName = options.batchName;
1143
1155
  hostReport.scriptIsValid = options.scriptIsValid;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "2.2.7",
3
+ "version": "2.3.0",
4
4
  "description": "Automation of accessibility testing",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -57,7 +57,7 @@ exports.scorer = acts => {
57
57
  ];
58
58
  // Initialize the score.
59
59
  const inferences = {};
60
- let deficit = {
60
+ let scores = {
61
61
  total: 0,
62
62
  aatt: null,
63
63
  alfa: null,
@@ -205,7 +205,7 @@ exports.scorer = acts => {
205
205
  // FUNCTIONS
206
206
  // Adds the actual or inferred score of a test to the total score.
207
207
  const increment = test => {
208
- deficit.total += typeof deficit[test] === 'number' ? deficit[test] : inferences[test];
208
+ scores.total += typeof scores[test] === 'number' ? scores[test] : inferences[test];
209
209
  };
210
210
  // OPERATION
211
211
  // For each test:
@@ -216,12 +216,12 @@ exports.scorer = acts => {
216
216
  facts = test.result;
217
217
  if (facts && Array.isArray(facts)) {
218
218
  rules.alfa = 'multiply cantTell by 2*, failed by 4* (*discounted); sum';
219
- deficit.alfa = Math.round(facts.reduce((total, issue) => {
219
+ scores.alfa = Math.round(facts.reduce((total, issue) => {
220
220
  const rawScore = [4, 2][['failed', 'cantTell'].indexOf(issue.verdict)] || 0;
221
221
  const divisor = duplications.alfa[issue.rule.ruleID] + 1 || 1;
222
222
  return total + rawScore / divisor;
223
223
  }, 0));
224
- deficit.total += deficit.alfa;
224
+ scores.total += scores.alfa;
225
225
  }
226
226
  }
227
227
  else if (which === 'aatt') {
@@ -229,26 +229,26 @@ exports.scorer = acts => {
229
229
  if (facts && Array.isArray(facts)) {
230
230
  rules.aatt = 'multiply warning by 2*, error by 4* (*discounted); sum';
231
231
  const issues = facts.filter(fact => fact.type);
232
- deficit.aatt = Math.round(issues.reduce((total, issue) => {
232
+ scores.aatt = Math.round(issues.reduce((total, issue) => {
233
233
  const rawScore = [4, 2][['error', 'warning'].indexOf(issue.type)] || 0;
234
234
  const divisor = duplications.aatt[`${issue.type.slice(0, 1)}:${issue.id}`] + 1 || 1;
235
235
  return total + rawScore / divisor;
236
236
  }, 0));
237
- deficit.total += deficit.aatt;
237
+ scores.total += scores.aatt;
238
238
  }
239
239
  }
240
240
  else if (which === 'axe') {
241
241
  facts = test.result && test.result.items;
242
242
  if (facts) {
243
243
  rules.axe = 'multiply minor by 2*, moderate by 3*, serious by 4*, critical by 5* (*discounted); sum';
244
- deficit.axe = Math.round(facts.reduce((total, item) => {
244
+ scores.axe = Math.round(facts.reduce((total, item) => {
245
245
  const rawScore = item.elements.length * (
246
246
  [5, 4, 3, 2][['critical', 'serious', 'moderate', 'minor'].indexOf(item.impact)] || 0
247
247
  );
248
248
  const divisor = duplications.axe[item.rule] + 1 || 1;
249
249
  return total + rawScore / divisor;
250
250
  }, 0));
251
- deficit.total += deficit.axe;
251
+ scores.total += scores.axe;
252
252
  }
253
253
  }
254
254
  else if (which === 'ibm') {
@@ -272,8 +272,8 @@ exports.scorer = acts => {
272
272
  }
273
273
  });
274
274
  if (scores.content !== null || scores.url !== null) {
275
- deficit.ibm = Math.max(scores.content || 0, scores.url || 0);
276
- deficit.total += deficit.ibm;
275
+ scores.ibm = Math.max(scores.content || 0, scores.url || 0);
276
+ scores.total += scores.ibm;
277
277
  }
278
278
  }
279
279
  }
@@ -300,8 +300,8 @@ exports.scorer = acts => {
300
300
  return total + rawScore / divisor;
301
301
  }, 0));
302
302
  });
303
- deficit.wave = scores.error + scores.contrast + scores.alert;
304
- deficit.total += deficit.wave;
303
+ scores.wave = scores.error + scores.contrast + scores.alert;
304
+ scores.total += scores.wave;
305
305
  }
306
306
  }
307
307
  else if (which === 'bulk') {
@@ -309,7 +309,7 @@ exports.scorer = acts => {
309
309
  if (typeof facts === 'number') {
310
310
  rules.bulk = 'subtract 250 from visible elements; make 0 if negative; raise to 0.9th power; multiply by 0.15';
311
311
  // Deficit: 15% of the excess, to the 0.9th power, of the element count over 250.
312
- deficit.bulk = Math.floor(0.15 * Math.pow(Math.max(0, facts - 250), 0.9));
312
+ scores.bulk = Math.floor(0.15 * Math.pow(Math.max(0, facts - 250), 0.9));
313
313
  }
314
314
  else {
315
315
  inferences.bulk = 100;
@@ -320,7 +320,7 @@ exports.scorer = acts => {
320
320
  facts = test.result && test.result.totals;
321
321
  if (facts) {
322
322
  rules.embAc = 'multiply link- or button-contained links, buttons, inputs, and selects by 3 (discounted)';
323
- deficit.embAc = 3 * (facts.links + facts.buttons + facts.inputs + facts.selects);
323
+ scores.embAc = 3 * (facts.links + facts.buttons + facts.inputs + facts.selects);
324
324
  }
325
325
  else {
326
326
  inferences.embAc = 150;
@@ -331,7 +331,7 @@ exports.scorer = acts => {
331
331
  facts = test.result;
332
332
  if (facts && typeof facts === 'object') {
333
333
  rules.focAll= 'multiply discrepancy between focusable and focused element counts by 3';
334
- deficit.focAll = 3 * Math.abs(facts.discrepancy);
334
+ scores.focAll = 3 * Math.abs(facts.discrepancy);
335
335
  }
336
336
  else {
337
337
  inferences.focAll = 150;
@@ -343,7 +343,7 @@ exports.scorer = acts => {
343
343
  facts = facts ? facts.types : null;
344
344
  if (facts) {
345
345
  rules.focInd = 'multiply indicatorless-when-focused elements by 5';
346
- deficit.focInd = 5 * facts.indicatorMissing.total + 3 * facts.nonOutlinePresent.total;
346
+ scores.focInd = 5 * facts.indicatorMissing.total + 3 * facts.nonOutlinePresent.total;
347
347
  }
348
348
  else {
349
349
  inferences.focInd = 150;
@@ -356,7 +356,7 @@ exports.scorer = acts => {
356
356
  facts = facts ? facts.outlineMissing : null;
357
357
  if (facts) {
358
358
  rules.focOl = 'multiply non-outline focus indicators by 3, missing focus indicators by 5; sum';
359
- deficit.focOl = 3 * facts.total;
359
+ scores.focOl = 3 * facts.total;
360
360
  }
361
361
  else {
362
362
  inferences.focOl = 100;
@@ -367,7 +367,7 @@ exports.scorer = acts => {
367
367
  facts = test.result && test.result.totals;
368
368
  if (facts) {
369
369
  rules.focOp = 'multiply nonfocusable operable elements by 4, nonoperable focusable by 1; sum';
370
- deficit.focOp
370
+ scores.focOp
371
371
  = 4 * facts.types.onlyOperable.total + 1 * facts.types.onlyFocusable.total;
372
372
  }
373
373
  else {
@@ -379,7 +379,7 @@ exports.scorer = acts => {
379
379
  facts = test.result && test.result.totals;
380
380
  if (facts) {
381
381
  rules.hover = 'multiply elements changing page on hover by 4, made visible by 2, with directly changed opacity by 0.1, with indirectly changed opacity by 0.2, unhoverable by 2; sum';
382
- deficit.hover
382
+ scores.hover
383
383
  = 4 * facts.triggers
384
384
  + 2 * facts.madeVisible
385
385
  + Math.floor(0.1 * facts.opacityChanged)
@@ -396,7 +396,7 @@ exports.scorer = acts => {
396
396
  if (facts) {
397
397
  rules.labClash = 'multiply conflictually labeled elements by 2, unlabeled elements by 2; sum';
398
398
  // Unlabeled elements discounted.
399
- deficit.labClash = 2 * facts.mislabeled + 2 * facts.unlabeled;
399
+ scores.labClash = 2 * facts.mislabeled + 2 * facts.unlabeled;
400
400
  }
401
401
  else {
402
402
  inferences.labClash = 100;
@@ -408,7 +408,7 @@ exports.scorer = acts => {
408
408
  facts = facts ? facts.inline : null;
409
409
  if (facts) {
410
410
  rules.linkUl = 'multiply nonunderlined inline links by 3';
411
- deficit.linkUl = 3 * (facts.total - facts.underlined);
411
+ scores.linkUl = 3 * (facts.total - facts.underlined);
412
412
  }
413
413
  else {
414
414
  inferences.linkUl = 150;
@@ -419,7 +419,7 @@ exports.scorer = acts => {
419
419
  facts = test.result && test.result.totals && test.result.totals.navigations;
420
420
  if (facts) {
421
421
  rules.menuNav = 'multiply Home and End errors by 1 and other key-navigation errors by 3; sum';
422
- deficit.menuNav
422
+ scores.menuNav
423
423
  = 3 * facts.all.incorrect
424
424
  - 2 * (facts.specific.home.incorrect + facts.specific.end.incorrect);
425
425
  }
@@ -432,7 +432,7 @@ exports.scorer = acts => {
432
432
  facts = test.result;
433
433
  if (facts && facts.bytes) {
434
434
  rules.motion = 'get PNG screenshot sizes (sss); get differing-pixel counts between adjacent PNG screenshots (pd); “sssd” = sss difference ÷ smaller sss - 1; multiply mean adjacent sssd by 5, maximum adjacent sssd by 2, maximum over-all ssd by 1; divide mean pd by 10,000, maximum pd by 25,000; multiply count of non-0 pd by 30; sum';
435
- deficit.motion = Math.floor(
435
+ scores.motion = Math.floor(
436
436
  5 * (facts.meanLocalRatio - 1)
437
437
  + 2 * (facts.maxLocalRatio - 1)
438
438
  + facts.globalRatio - 1
@@ -451,7 +451,7 @@ exports.scorer = acts => {
451
451
  if (facts) {
452
452
  rules.radioSet = 'multiply radio buttons not in fieldsets with legends and no other-name radio buttons by 2';
453
453
  // Defects discounted.
454
- deficit.radioSet = 2 * (facts.total - facts.inSet);
454
+ scores.radioSet = 2 * (facts.total - facts.inSet);
455
455
  }
456
456
  else {
457
457
  inferences.radioSet = 100;
@@ -463,7 +463,7 @@ exports.scorer = acts => {
463
463
  if (typeof facts === 'number') {
464
464
  rules.role = 'multiple role attributes with invalid or native-HTML-equivalent values by 2';
465
465
  // Defects discounted.
466
- deficit.role = 2 * facts;
466
+ scores.role = 2 * facts;
467
467
  }
468
468
  else {
469
469
  inferences.role = 100;
@@ -484,7 +484,7 @@ exports.scorer = acts => {
484
484
  }
485
485
  );
486
486
  // Deficit: 2 per excess style + 0.2 per nonplurality element.
487
- deficit.styleDiff = Math.floor(deficits.reduce(
487
+ scores.styleDiff = Math.floor(deficits.reduce(
488
488
  (total, currentPair) => total + 2 * currentPair[0] + 0.2 * currentPair[1], 0
489
489
  ));
490
490
  }
@@ -497,7 +497,7 @@ exports.scorer = acts => {
497
497
  facts = test.result && test.result.totals && test.result.totals.navigations;
498
498
  if (facts) {
499
499
  rules.tabNav = 'multiply Home and End errors by 1 and other key-navigation errors by 3; sum';
500
- deficit.tabNav
500
+ scores.tabNav
501
501
  = 3 * facts.all.incorrect
502
502
  - 2 * (facts.specific.home.incorrect + facts.specific.end.incorrect);
503
503
  }
@@ -510,7 +510,7 @@ exports.scorer = acts => {
510
510
  facts = test.result && test.result.totals;
511
511
  if (facts) {
512
512
  rules.zIndex = 'multiply non-auto z indexes by 3';
513
- deficit.zIndex = 3 * facts.total;
513
+ scores.zIndex = 3 * facts.total;
514
514
  }
515
515
  else {
516
516
  inferences.zIndex = 100;
@@ -520,7 +520,7 @@ exports.scorer = acts => {
520
520
  });
521
521
  // Compute the inferred scores of package tests that failed and adjust the total score.
522
522
  const estimate = (tests, penalty) => {
523
- const packageScores = tests.map(test => deficit[test]).filter(score => score !== null);
523
+ const packageScores = tests.map(test => scores[test]).filter(score => score !== null);
524
524
  const scoreCount = packageScores.length;
525
525
  let meanScore;
526
526
  if (scoreCount) {
@@ -532,9 +532,9 @@ exports.scorer = acts => {
532
532
  meanScore = 100;
533
533
  }
534
534
  tests.forEach(test => {
535
- if (deficit[test] === null) {
535
+ if (scores[test] === null) {
536
536
  inferences[test] = meanScore + penalty;
537
- deficit.total += inferences[test];
537
+ scores.total += inferences[test];
538
538
  }
539
539
  });
540
540
  };
@@ -550,6 +550,6 @@ exports.scorer = acts => {
550
550
  diffStyles,
551
551
  logWeights,
552
552
  inferences,
553
- deficit
553
+ scores
554
554
  };
555
555
  };