testilo 40.1.0 → 41.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
@@ -99,12 +99,7 @@ Targets can be specified in a more complex way, too. That allows you to create j
99
99
  what: 'Acme Clothes',
100
100
  url: 'https://acmeclothes.com/',
101
101
  actGroups: {
102
- public: [
103
- {
104
- type: 'launch',
105
- what: 'Acme Clothes home page',
106
- }
107
- ],
102
+ public: [],
108
103
  private: [
109
104
  {
110
105
  type: 'launch',
@@ -141,13 +136,13 @@ Targets can be specified in a more complex way, too. That allows you to create j
141
136
 
142
137
  As shown, a batch, unlike a target list, defines named groups of acts. They can be substituted for script placeholders, so various complex operations can be performed on each target.
143
138
 
144
- In this example, the `public` act group contains only 1 act, of type `launch`. A `launch` act in an act group is permitted to have only two properties, `what` and `url`. If either of these is omitted, its value is inherited from the corresponding property of the target. In the `public` act group in this case, the `what` value is specified, but the `url` value will be `https://acmeclothes.com/`, inherited from the target.
139
+ In this example, the `public` act group contains no acts. The `private` act group contains 5 acts. A `launch` act in an act group is permitted to have only two properties, `what` and `url`. If either of these is omitted, its value is inherited from the corresponding property of the target.
145
140
 
146
141
  A batch is a JavaScript object. It can be converted to JSON and stored in a file.
147
142
 
148
143
  ### Target list to batch
149
144
 
150
- If you have a target list, the `batch` module of Testilo can convert it to a simple batch. The batch will contain, for each target, only one act group, named `main`, containing only a `launch` act. The target’s entry in the target list will determine the `what` and `url` properties of the target, and the `launch` acts will not override the values of those properties.
145
+ If you have a target list, the `batch` module of Testilo can convert it to a simple batch. The batch will contain, for each target, only one act group, named `main`, containing no acts.
151
146
 
152
147
  #### Invocation
153
148
 
@@ -170,7 +165,7 @@ const batchObj = batch(id, what, targets);
170
165
 
171
166
  The `id` argument to `batch()` is an identifier for the target list. The `what` variable describes the target list. The `targets` variable is an array of arrays, with each array containing the 2 items (description and URL) defining one target.
172
167
 
173
- The `batch()` function of the `batch` module generates a batch and returns it as an object. Within the batch, each target is given a sequential (base-62 alphanumeric) string as an ID.
168
+ The `batch()` function of the `batch` module generates a batch and returns it as an object. Within the batch, each target is given a sequential (base-36 alphanumeric) string as an ID.
174
169
 
175
170
  The invoking module can further dispose of the batch as needed.
176
171
 
@@ -288,7 +283,7 @@ In its simplest form, `script()` requires 3 string arguments:
288
283
  1. A description of the script
289
284
  1. A device ID
290
285
 
291
- Called in this way, `script()` produces a script that tells Testaro to perform the tests for all of the evaluation rules defined by all of the tools integrated by Testaro.
286
+ Called in this way, `script()` produces a script that tells Testaro to perform the tests for all of the evaluation rules defined by all of the tools integrated by Testaro. In this case, the script launches a new Webkit browser before performing the tests of each tool.
292
287
 
293
288
  #### With options
294
289
 
@@ -384,6 +379,7 @@ When the `script` module creates a script for you, it does not ask you for all o
384
379
  - `sendReportTo`: `process.env.SEND_REPORT_TO`, or `''` if none
385
380
  - `sources.id`: script ID
386
381
  - `sources.requester`: `process.env.REQUESTER`, or `''` if none
382
+ - test acts: `launch` = {}
387
383
  - `axe` test act: `detailLevel` = 2
388
384
  - `ibm` test act: `withItems` = `true`, `withNewContent` = `true`
389
385
  - `qualWeb` test act: `withNewContent` = `false`
package/batch.js CHANGED
@@ -55,11 +55,7 @@ exports.batch = (id, what, targetList) => {
55
55
  batch.targets[target[0]] = {
56
56
  url: target[1],
57
57
  actGroups: {
58
- main: [
59
- {
60
- type: 'launch'
61
- }
62
- ]
58
+ main: []
63
59
  }
64
60
  };
65
61
  });
package/merge.js CHANGED
@@ -34,15 +34,6 @@ const {alphaNumOf, dateOf, getRandomString, getNowStamp} = require('./procs/util
34
34
 
35
35
  // ########## CONSTANTS
36
36
 
37
- // Tools that alter the page.
38
- const contaminantNames = new Set([
39
- 'alfa',
40
- 'aslint',
41
- 'axe',
42
- 'ed11y',
43
- 'htmlcs',
44
- 'testaro'
45
- ]);
46
37
  // Length of the random merger ID.
47
38
  const mergeIDLength = 3;
48
39
 
@@ -85,12 +76,8 @@ exports.merge = (script, batch, executionTimeStamp) => {
85
76
  // Identify it as the current one.
86
77
  lastPlaceholder = act;
87
78
  }
88
- // Otherwise, if it is a non-final target-modifying test act:
89
- else if (
90
- act.type === 'test'
91
- && contaminantNames.has(act.which)
92
- && actIndex < acts.length - 1
93
- ) {
79
+ // Otherwise, if it is a test act:
80
+ else if (act.type === 'test') {
94
81
  // Change it to an array of itself and the current placeholder.
95
82
  acts[actIndex] = JSON.parse(JSON.stringify([act, lastPlaceholder]));
96
83
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "40.1.0",
3
+ "version": "41.0.0",
4
4
  "description": "Prepares Testaro jobs and processes Testaro reports",
5
5
  "main": "call.js",
6
6
  "scripts": {
@@ -25,14 +25,15 @@
25
25
  Tabulates tool rules from an issue classification.
26
26
  */
27
27
 
28
- const {issues} = require('../score/tic40');
28
+ const {issues} = require('../score/tic45');
29
29
 
30
30
  const counts = {
31
31
  total: 0
32
32
  };
33
- // For each issue:
34
- Object.values(issues).forEach(issue => {
33
+ // For each issue other than ignorable:
34
+ Object.keys(issues).filter(issueName => issueName !== 'ignorable').forEach(issueName => {
35
35
  // For each tool with any rules of the issue:
36
+ const issue = issues[issueName];
36
37
  Object.keys(issue.tools).forEach(toolName => {
37
38
  if (! counts[toolName]) {
38
39
  counts[toolName] = 0;
@@ -457,55 +457,15 @@ exports.issues = {
457
457
  }
458
458
  },
459
459
  htmlcs: {
460
- 'AAA.4_1_2.H91.InputText.Name': {
460
+ 'AAA.4_1_2.H91.Input.Name': {
461
461
  variable: false,
462
462
  quality: 1,
463
463
  what: 'Text input has no accessible name'
464
464
  },
465
- 'AAA.4_1_2.H91.InputEmail.Name': {
466
- variable: false,
467
- quality: 1,
468
- what: 'Email input has no accessible name'
469
- },
470
- 'AAA.4_1_2.H91.InputPhone.Name': {
471
- variable: false,
472
- quality: 1,
473
- what: 'Telephone input has no accessible name'
474
- },
475
- 'AAA.4_1_2.H91.InputFile.Name': {
476
- variable: false,
477
- quality: 1,
478
- what: 'File input element has no accessible name'
479
- },
480
- 'AAA.4_1_2.H91.InputTel.Name': {
481
- variable: false,
482
- quality: 1,
483
- what: 'Telephone input has no accessible name'
484
- },
485
- 'AAA.4_1_2.H91.InputNumber.Name': {
486
- variable: false,
487
- quality: 1,
488
- what: 'Number input has no accessible name'
489
- },
490
- 'AAA.4_1_2.H91.InputPassword.Name': {
491
- variable: false,
492
- quality: 1,
493
- what: 'Password input has no accessible name'
494
- },
495
- 'AAA.4_1_2.H91.InputSearch.Name': {
496
- variable: false,
497
- quality: 1,
498
- what: 'Search input has no accessible name'
499
- },
500
- 'AAA.4_1_2.H91.InputCheckbox.Name': {
501
- variable: false,
502
- quality: 1,
503
- what: 'Checkbox input has no accessible name'
504
- },
505
- 'AAA.4_1_2.H91.InputRadio.Name': {
506
- variable: false,
465
+ '^AAA.4_1_2.H91.Input[-a-zA-Z]+.Name$': {
466
+ variable: true,
507
467
  quality: 1,
508
- what: 'Radio input has no accessible name'
468
+ what: 'input element has no accessible name'
509
469
  }
510
470
  }
511
471
  }
@@ -746,6 +706,26 @@ exports.issues = {
746
706
  variable: false,
747
707
  quality: 1,
748
708
  what: 'alt attribute of the element states the image is an image'
709
+ },
710
+ altImageOfLinked: {
711
+ variable: false,
712
+ quality: 1,
713
+ what: 'alt attribute of the intra-link element states the image is an image instead of describing the link purpose'
714
+ }
715
+ }
716
+ }
717
+ },
718
+ decorativeAlt: {
719
+ summary: 'decorative image is named',
720
+ why: 'User gets an uninformative image description or misses an informative image',
721
+ wcag: '1.1.1',
722
+ weight: 1,
723
+ tools: {
724
+ ibm: {
725
+ img_alt_decorative: {
726
+ variable: false,
727
+ quality: 1,
728
+ what: 'element is marked as an uninformative image but has an alt attribute'
749
729
  }
750
730
  }
751
731
  }
@@ -843,6 +823,66 @@ exports.issues = {
843
823
  }
844
824
  }
845
825
  },
826
+ borderBad: {
827
+ summary: 'CSS border invalid',
828
+ why: 'Border is displayed improperly',
829
+ wcag: '4.1',
830
+ weight: 4,
831
+ tools: {
832
+ nuVal: {
833
+ '^CSS: border-.+ negative values are not allowed.*$': {
834
+ variable: true,
835
+ quality: 1,
836
+ what: 'CSS border includes a negative-valued property'
837
+ }
838
+ }
839
+ }
840
+ },
841
+ flexBad: {
842
+ summary: 'CSS flex invalid',
843
+ why: 'Content is displayed improperly',
844
+ wcag: '4.1',
845
+ weight: 4,
846
+ tools: {
847
+ nuVal: {
848
+ '^CSS: flex: .+ negative values are not allowed.*$': {
849
+ variable: true,
850
+ quality: 1,
851
+ what: 'CSS flex value is negative'
852
+ }
853
+ }
854
+ }
855
+ },
856
+ paddingBad: {
857
+ summary: 'CSS padding invalid',
858
+ why: 'Content is displayed improperly',
859
+ wcag: '4.1',
860
+ weight: 4,
861
+ tools: {
862
+ nuVal: {
863
+ '^CSS: padding[-a-z]*: .+ negative values are not allowed\.$': {
864
+ variable: true,
865
+ quality: 1,
866
+ what: 'One of the CSS padding values is negative'
867
+ }
868
+ }
869
+ }
870
+ },
871
+ gapBad: {
872
+ summary: 'CSS padding invalid',
873
+ why: 'Content is displayed improperly',
874
+ wcag: '4.1',
875
+ weight: 4,
876
+ tools: {
877
+ nuVal: {
878
+ '^CSS: gap: .+ negative values are not allowed\.$': {
879
+ variable: true,
880
+ quality: 1,
881
+ what: 'CSS gap value is negative'
882
+ }
883
+ }
884
+ }
885
+ },
846
886
  backgroundBad: {
847
887
  summary: 'CSS background invalid',
848
888
  why: 'Background is displayed improperly',
@@ -864,7 +904,7 @@ exports.issues = {
864
904
  variable: true,
865
905
  quality: 1,
866
906
  what: 'CSS background URL is invalid'
867
- },
907
+ }
868
908
  }
869
909
  }
870
910
  },
@@ -1133,6 +1173,13 @@ exports.issues = {
1133
1173
  what: 'Language specified in the lang attribute of the document does not appear to be well-formed'
1134
1174
  }
1135
1175
  },
1176
+ ibm: {
1177
+ html_lang_valid: {
1178
+ variable: false,
1179
+ quality: 1,
1180
+ what: 'lang attribute of the html element does not include a valid primary language'
1181
+ }
1182
+ },
1136
1183
  qualWeb: {
1137
1184
  'QW-ACT-R5': {
1138
1185
  variable: false,
@@ -1266,6 +1313,11 @@ exports.issues = {
1266
1313
  variable: false,
1267
1314
  quality: 1,
1268
1315
  what: 'object element contains no text alternative'
1316
+ },
1317
+ 'AAA.1_1_1.H53,ARIA6': {
1318
+ variable: false,
1319
+ quality: 1,
1320
+ what: 'object element contains no text alternative after all other alternatives are exhausted'
1269
1321
  }
1270
1322
  },
1271
1323
  ibm: {
@@ -1957,6 +2009,11 @@ exports.issues = {
1957
2009
  variable: false,
1958
2010
  quality: 1,
1959
2011
  what: 'link element has an empty href attribute'
2012
+ },
2013
+ 'Attribute href without an explicit value seen. The attribute may be dropped by IE7.': {
2014
+ variable: false,
2015
+ quality: 1,
2016
+ what: 'Element has an empty href attribute'
1960
2017
  }
1961
2018
  }
1962
2019
  }
@@ -2322,6 +2379,31 @@ exports.issues = {
2322
2379
  }
2323
2380
  }
2324
2381
  },
2382
+ selectBad: {
2383
+ summary: 'select element invalid',
2384
+ why: 'User cannot properly select among options',
2385
+ wcag: '4.1.2',
2386
+ weight: 4,
2387
+ tools: {
2388
+ nuVal: {
2389
+ 'The document role is not allowed for element select without a multiple attribute and without a size attribute whose value is greater than 1.': {
2390
+ variable: false,
2391
+ quality: 1,
2392
+ what: 'select element is not multiple or has no size greater than 1 but has a document role'
2393
+ },
2394
+ 'The first child option element of a select element with a required attribute, and without a multiple attribute, and without a size attribute whose value is greater than 1, must have either an empty value attribute, or must have no text content. Consider either adding a placeholder option label, or adding a size attribute with a value equal to the number of option elements.': {
2395
+ variable: false,
2396
+ quality: 1,
2397
+ what: 'option element has a nonempty value'
2398
+ },
2399
+ 'The select element cannot have more than one selected option descendant unless the multiple attribute is specified.': {
2400
+ variable: false,
2401
+ quality: 1,
2402
+ what: 'Element is select and has no multiple attribute, but has more than 1 selected option'
2403
+ }
2404
+ }
2405
+ }
2406
+ },
2325
2407
  buttonAlt: {
2326
2408
  summary: 'button has alt',
2327
2409
  why: 'User cannot get help explaing a button',
@@ -2782,17 +2864,17 @@ exports.issues = {
2782
2864
  }
2783
2865
  }
2784
2866
  },
2785
- textSpacingFrozen: {
2786
- summary: 'text spacing frozen',
2787
- why: 'User cannot adjust the text spacing for readability',
2867
+ horizontalSpacingFrozen: {
2868
+ summary: 'horizontal text spacing frozen',
2869
+ why: 'User cannot adjust the horizontal text spacing for readability',
2788
2870
  wcag: '1.4.12',
2789
2871
  weight: 4,
2790
2872
  tools: {
2791
2873
  alfa: {
2792
- r93: {
2874
+ r91: {
2793
2875
  variable: false,
2794
2876
  quality: 1,
2795
- what: 'Style attribute with !important prevents adjusting line height'
2877
+ what: 'Style attribute with !important makes letter spacing insufficient'
2796
2878
  }
2797
2879
  },
2798
2880
  axe: {
@@ -2802,17 +2884,19 @@ exports.issues = {
2802
2884
  what: 'Inline text spacing is not adjustable with a custom stylesheet'
2803
2885
  }
2804
2886
  },
2887
+ ibm: {
2888
+ text_spacing_valid: {
2889
+ variable: false,
2890
+ quality: 1,
2891
+ what: 'CSS !important is used in an inline letter-spacing style'
2892
+ }
2893
+ },
2805
2894
  qualWeb: {
2806
2895
  'QW-ACT-R67': {
2807
2896
  variable: false,
2808
2897
  quality: 1,
2809
2898
  what: 'Letter spacing in a style attribute is !important'
2810
2899
  },
2811
- 'QW-ACT-R68': {
2812
- variable: false,
2813
- quality: 1,
2814
- what: 'Line height in a style attribute is !important'
2815
- },
2816
2900
  'QW-ACT-R69': {
2817
2901
  variable: false,
2818
2902
  quality: 1,
@@ -2821,6 +2905,28 @@ exports.issues = {
2821
2905
  }
2822
2906
  }
2823
2907
  },
2908
+ verticalSpacingFrozen: {
2909
+ summary: 'vertical text spacing frozen',
2910
+ why: 'User cannot adjust the vertical text spacing for readability',
2911
+ wcag: '1.4.12',
2912
+ weight: 4,
2913
+ tools: {
2914
+ alfa: {
2915
+ r93: {
2916
+ variable: false,
2917
+ quality: 1,
2918
+ what: 'Style attribute with !important prevents adjusting line height'
2919
+ }
2920
+ },
2921
+ qualWeb: {
2922
+ 'QW-ACT-R68': {
2923
+ variable: false,
2924
+ quality: 1,
2925
+ what: 'Line height in a style attribute is !important'
2926
+ }
2927
+ }
2928
+ }
2929
+ },
2824
2930
  lineHeightAbsolute: {
2825
2931
  summary: 'line height absolute',
2826
2932
  why: 'User cannot adjust the line height of text for readability',
@@ -2858,6 +2964,21 @@ exports.issues = {
2858
2964
  }
2859
2965
  }
2860
2966
  },
2967
+ lineHeightBad: {
2968
+ summary: 'line height misdefined',
2969
+ why: 'Text is difficult to read',
2970
+ wcag: '1.4.8',
2971
+ weight: 4,
2972
+ tools: {
2973
+ nuVal: {
2974
+ '^CSS: line-height: .* negative values are not allowed.*$': {
2975
+ variable: true,
2976
+ quality: 1,
2977
+ what: 'Text line height is negative'
2978
+ }
2979
+ }
2980
+ }
2981
+ },
2861
2982
  overflowHidden: {
2862
2983
  summary: 'overflow hidden',
2863
2984
  why: 'User cannot enlarge the text for readability',
@@ -2908,6 +3029,21 @@ exports.issues = {
2908
3029
  }
2909
3030
  }
2910
3031
  },
3032
+ elementBad: {
3033
+ summary: 'nonexistent element',
3034
+ why: 'User cannot understand the content',
3035
+ wcag: '4.1.2',
3036
+ weight: 4,
3037
+ tools: {
3038
+ nuVal: {
3039
+ '^Saw a start tag [a-z]+\.$': {
3040
+ variable: true,
3041
+ quality: 1,
3042
+ what: 'Element does not exist in HTML'
3043
+ }
3044
+ }
3045
+ }
3046
+ },
2911
3047
  titleBad: {
2912
3048
  summary: 'title attribute invalid',
2913
3049
  why: 'User cannot hover to get help explaining an item',
@@ -3030,12 +3166,17 @@ exports.issues = {
3030
3166
  'Element script must not have attribute defer unless attribute src is also specified.': {
3031
3167
  variable: false,
3032
3168
  quality: 1,
3033
- what: 'script element has a defer attribute without a src attribute'
3169
+ what: 'Element is script and has a defer attribute but no src attribute'
3170
+ },
3171
+ 'Element script should not have attribute fetchpriority unless attribute src is also specified.': {
3172
+ variable: false,
3173
+ quality: 1,
3174
+ what: 'Element is script and has a fetchpriority attribute but no src attribute'
3034
3175
  },
3035
3176
  'A script element with a src attribute must not have a type attribute whose value is anything other than the empty string, a JavaScript MIME type, or module.': {
3036
3177
  variable: false,
3037
3178
  quality: 1,
3038
- what: 'script element has a src attribute but its type is not empty, a JS MIME type, or module'
3179
+ what: 'Element is script and has a src attribute but its type is not empty, a JS MIME type, or module'
3039
3180
  }
3040
3181
  }
3041
3182
  }
@@ -3219,6 +3360,11 @@ exports.issues = {
3219
3360
  variable: false,
3220
3361
  quality: 1,
3221
3362
  what: 'Element has an event handler but no valid ARIA role'
3363
+ },
3364
+ combobox_haspopup_valid: {
3365
+ variable: false,
3366
+ quality: 1,
3367
+ what: 'Element has a combobox role but controls an element that has no listbox, grid, tree, or dialog role'
3222
3368
  }
3223
3369
  },
3224
3370
  nuVal: {
@@ -3668,7 +3814,7 @@ exports.issues = {
3668
3814
  aria_semantics_attribute: {
3669
3815
  variable: false,
3670
3816
  quality: 1,
3671
- what: 'ARIA attributes is invalid for the element or ARIA role to which it is assigned'
3817
+ what: 'ARIA attribute is invalid for the element or ARIA role to which it is assigned'
3672
3818
  },
3673
3819
  Rpt_Aria_ValidProperty: {
3674
3820
  variable: false,
@@ -3770,6 +3916,11 @@ exports.issues = {
3770
3916
  variable: true,
3771
3917
  quality: 1,
3772
3918
  what: 'ARIA attribute is redundant with the synonymous native attribute'
3919
+ },
3920
+ 'The aria-valuemax attribute must not be used on an element which has a max attribute.': {
3921
+ variable: false,
3922
+ quality: 1,
3923
+ what: 'Element has the max attribute but also the aria-valuemax attribute'
3773
3924
  }
3774
3925
  }
3775
3926
  }
@@ -4207,6 +4358,21 @@ exports.issues = {
4207
4358
  }
4208
4359
  }
4209
4360
  },
4361
+ headingsEmbedded: {
4362
+ summary: 'heading within a heading',
4363
+ why: 'User cannot understand the page organization',
4364
+ wcag: '4.1.2',
4365
+ weight: 4,
4366
+ tools: {
4367
+ nuVal: {
4368
+ 'Heading cannot be a child of another heading.': {
4369
+ variable: false,
4370
+ quality: 1,
4371
+ what: 'Heading is within a heading'
4372
+ }
4373
+ }
4374
+ }
4375
+ },
4210
4376
  headingEmpty: {
4211
4377
  summary: 'heading empty',
4212
4378
  why: 'User cannot get help on the topic of a part of the document',
@@ -5066,6 +5232,13 @@ exports.issues = {
5066
5232
  what: 'List element dl has a child element other than properly ordered dt or dt group, script, template, or div'
5067
5233
  }
5068
5234
  },
5235
+ ibm: {
5236
+ list_children_valid: {
5237
+ variable: false,
5238
+ quality: 1,
5239
+ what: 'Element has a group role but has a child whose role is not listitem'
5240
+ }
5241
+ },
5069
5242
  nuVal: {
5070
5243
  'Element dl is missing a required child element.': {
5071
5244
  variable: false,
@@ -5536,6 +5709,11 @@ exports.issues = {
5536
5709
  variable: true,
5537
5710
  quality: 1,
5538
5711
  what: 'Table row has a column count larger than that of the first row'
5712
+ },
5713
+ '^Table column \d+ established by element td has no cells beginning in it\.$': {
5714
+ variable: true,
5715
+ quality: 1,
5716
+ what: 'Element is td but the prior cells in its table column do not exist'
5539
5717
  }
5540
5718
  }
5541
5719
  }
@@ -5578,6 +5756,13 @@ exports.issues = {
5578
5756
  quality: 1,
5579
5757
  what: 'caption element not used to associate a caption with a data table'
5580
5758
  }
5759
+ },
5760
+ wave: {
5761
+ table_caption_possible: {
5762
+ variable: false,
5763
+ quality: 1,
5764
+ what: 'table cell apparently misused as the table caption'
5765
+ }
5581
5766
  }
5582
5767
  }
5583
5768
  },
@@ -5678,6 +5863,13 @@ exports.issues = {
5678
5863
  quality: 1,
5679
5864
  what: 'Complex table is missing headers attributes of cells'
5680
5865
  }
5866
+ },
5867
+ ibm: {
5868
+ table_headers_related: {
5869
+ variable: false,
5870
+ quality: 1,
5871
+ what: 'Element is a cell in a complex table but has no headers associated with headers or scope attributes'
5872
+ }
5681
5873
  }
5682
5874
  }
5683
5875
  },
@@ -5829,6 +6021,13 @@ exports.issues = {
5829
6021
  wcag: '1.3.1',
5830
6022
  weight: 2,
5831
6023
  tools: {
6024
+ axe: {
6025
+ 'empty-table-header': {
6026
+ variable: false,
6027
+ quality: 1,
6028
+ what: 'Element is a table header but has no text'
6029
+ }
6030
+ },
5832
6031
  ed11y: {
5833
6032
  tableEmptyHeaderCell: {
5834
6033
  variable: false,
@@ -5890,6 +6089,51 @@ exports.issues = {
5890
6089
  }
5891
6090
  }
5892
6091
  },
6092
+ divInTable: {
6093
+ summary: 'div embedded in table',
6094
+ why: 'Blocks of content within a table cell may confuse a user',
6095
+ wcag: '1.4',
6096
+ weight: 1,
6097
+ tools: {
6098
+ nuVal: {
6099
+ 'Start tag div seen in table.': {
6100
+ variable: false,
6101
+ quality: 1,
6102
+ what: 'div element is inside a table element'
6103
+ }
6104
+ }
6105
+ }
6106
+ },
6107
+ formInTable: {
6108
+ summary: 'form embedded in table',
6109
+ why: 'Navigation in a form may confuse a keyboard-only user',
6110
+ wcag: '2.1.1',
6111
+ weight: 1,
6112
+ tools: {
6113
+ nuVal: {
6114
+ 'Start tag form seen in table.': {
6115
+ variable: false,
6116
+ quality: 1,
6117
+ what: 'form element is inside a table element'
6118
+ }
6119
+ }
6120
+ }
6121
+ },
6122
+ inputInTable: {
6123
+ summary: 'input embedded in table',
6124
+ why: 'Entry of data in a form may confuse a keyboard-only user',
6125
+ wcag: '2.1.1',
6126
+ weight: 1,
6127
+ tools: {
6128
+ nuVal: {
6129
+ 'Start tag input seen in table.': {
6130
+ variable: false,
6131
+ quality: 1,
6132
+ what: 'input element is inside a table element'
6133
+ }
6134
+ }
6135
+ }
6136
+ },
5893
6137
  tableHeading: {
5894
6138
  summary: 'heading located in table',
5895
6139
  why: 'Complex relationships in a table may confuse a user',
@@ -6146,6 +6390,16 @@ exports.issues = {
6146
6390
  quality: 1,
6147
6391
  what: 'button element is a descendant of an element with a button role'
6148
6392
  },
6393
+ 'An element with the attribute role=button must not appear as a descendant of an element with the attribute role=button.': {
6394
+ variable: false,
6395
+ quality: 1,
6396
+ what: 'Element with a button role is a descendant of an element with a button role'
6397
+ },
6398
+ 'An element with the attribute role=button must not appear as a descendant of the button element.': {
6399
+ variable: false,
6400
+ quality: 1,
6401
+ what: 'Element with a button role is a descendant of a button element'
6402
+ },
6149
6403
  'The element label must not appear as a descendant of an element with the attribute role=button.': {
6150
6404
  variable: false,
6151
6405
  quality: 1,
@@ -6749,6 +7003,21 @@ exports.issues = {
6749
7003
  }
6750
7004
  }
6751
7005
  },
7006
+ applicationNoText: {
7007
+ summary: 'application not named',
7008
+ why: 'User cannot get help on how some of the document is organized',
7009
+ wcag: '1.3.6',
7010
+ weight: 4,
7011
+ tools: {
7012
+ ibm: {
7013
+ aria_application_labelled: {
7014
+ variable: false,
7015
+ quality: 1,
7016
+ what: 'Element with an application role has no purpose label'
7017
+ }
7018
+ }
7019
+ }
7020
+ },
6752
7021
  applicationConfusion: {
6753
7022
  summary: 'applications not distinctly named',
6754
7023
  why: 'User cannot get help on how some of the document is organized',
@@ -7616,6 +7885,13 @@ exports.issues = {
7616
7885
  quality: 1,
7617
7886
  what: 'Element has a refresh delay (no exception)'
7618
7887
  }
7888
+ },
7889
+ wave: {
7890
+ meta_refresh: {
7891
+ variable: false,
7892
+ quality: 1,
7893
+ what: 'Page refreshes or redirects'
7894
+ }
7619
7895
  }
7620
7896
  }
7621
7897
  },
@@ -8409,6 +8685,36 @@ exports.issues = {
8409
8685
  }
8410
8686
  }
8411
8687
  },
8688
+ atRuleInvalid: {
8689
+ summary: 'invalid at-rule',
8690
+ why: 'Document cannot be properly displayed in particular contexts',
8691
+ wcag: '4.1',
8692
+ weight: 3,
8693
+ tools: {
8694
+ nuVal: {
8695
+ '^CSS: Unrecognized at-rule @.+$': {
8696
+ variable: true,
8697
+ quality: 1,
8698
+ what: 'At-rule not recognized by CSS'
8699
+ },
8700
+ 'CSS: This profile has a very specific syntax for @charset: @charset followed by exactly one space, followed by the name of the encoding in quotes, followed immediately by a semicolon.': {
8701
+ variable: false,
8702
+ quality: 1,
8703
+ what: 'CSS @charset at-rule has an invalid format'
8704
+ },
8705
+ 'CSS: The @charset rule may only occur at the start of the style sheet. Please check that there are no spaces before it.': {
8706
+ variable: false,
8707
+ quality: 1,
8708
+ what: 'CSS @charset at-rule is not at the start of its style sheet'
8709
+ },
8710
+ 'CSS: @import are not allowed after any valid statement other than @charset and @import.': {
8711
+ variable: false,
8712
+ quality: 1,
8713
+ what: 'CSS @import at-rule is after an at-rule other than @charset or @import'
8714
+ }
8715
+ }
8716
+ }
8717
+ },
8412
8718
  cssInvalid: {
8413
8719
  summary: 'CSS invalid',
8414
8720
  why: 'Document cannot be properly displayed',
@@ -8516,6 +8822,11 @@ exports.issues = {
8516
8822
  quality: 1,
8517
8823
  what: 'Space is misused as a CSS operator'
8518
8824
  },
8825
+ '^CSS: .+: , is an incorrect operator\.$': {
8826
+ variable: true,
8827
+ quality: 1,
8828
+ what: 'Comma is misused as a CSS operator'
8829
+ },
8519
8830
  '^CSS: Unknown pseudo-element or pseudo-class :.+$': {
8520
8831
  variable: true,
8521
8832
  quality: 1,
@@ -8526,11 +8837,6 @@ exports.issues = {
8526
8837
  quality: 1,
8527
8838
  what: 'Unrecognized media value'
8528
8839
  },
8529
- 'CSS: This profile has a very specific syntax for @charset: @charset followed by exactly one space, followed by the name of the encoding in quotes, followed immediately by a semicolon.': {
8530
- variable: false,
8531
- quality: 1,
8532
- what: 'CSS @charset at-rule has an invalid format'
8533
- },
8534
8840
  '^CSS: .+ is not a :lang.+ value.*$': {
8535
8841
  variable: true,
8536
8842
  quality: 1,
@@ -8541,16 +8847,6 @@ exports.issues = {
8541
8847
  quality: 1,
8542
8848
  what: 'semicolon missing in CSS'
8543
8849
  },
8544
- 'CSS: The @charset rule may only occur at the start of the style sheet. Please check that there are no spaces before it.': {
8545
- variable: false,
8546
- quality: 1,
8547
- what: 'CSS @charset at-rule is not at the start of its style sheet'
8548
- },
8549
- 'CSS: @import are not allowed after any valid statement other than @charset and @import.': {
8550
- variable: false,
8551
- quality: 1,
8552
- what: 'CSS @import at-rule is after an at-rule other than @charset or @import'
8553
- },
8554
8850
  '^CSS: perspective: .+ is not valid, only values greater than 0 allowed.*$': {
8555
8851
  variable: true,
8556
8852
  quality: 0.5,
@@ -8566,6 +8862,11 @@ exports.issues = {
8566
8862
  quality: 0.5,
8567
8863
  what: 'CSS transition property has a value greater than 1'
8568
8864
  },
8865
+ 'CSS: -webkit-mask: too few values for the property linear-gradient.': {
8866
+ variable: false,
8867
+ quality: 1,
8868
+ what: 'CSS webkit-mask linear-gradient property has too few values'
8869
+ },
8569
8870
  '^CSS: In CSS1, a class name could start with a digit .+, unless it was a dimension .+ In CSS2, such classes are parsed as unknown dimensions .+ To make .+ a valid class, CSS2 requires the first digit to be escaped: .+$': {
8570
8871
  variable: true,
8571
8872
  quality: 0.5,
@@ -8584,13 +8885,18 @@ exports.issues = {
8584
8885
  '^Stray start tag .+$': {
8585
8886
  variable: true,
8586
8887
  quality: 1,
8587
- what: 'Invalid opening tag'
8888
+ what: 'Invalid start tag'
8588
8889
  },
8589
8890
  '^Stray end tag .+$': {
8590
8891
  variable: true,
8591
8892
  quality: 1,
8592
8893
  what: 'Invalid closing tag'
8593
8894
  },
8895
+ '^End tag [a-z]+\.$': {
8896
+ variable: true,
8897
+ quality: 1,
8898
+ what: 'Closing tag of an ineligible element'
8899
+ },
8594
8900
  '^Start tag .+ seen but an element of the same type was already open.*$': {
8595
8901
  variable: true,
8596
8902
  quality: 1,
@@ -8620,6 +8926,11 @@ exports.issues = {
8620
8926
  variable: true,
8621
8927
  quality: 1,
8622
8928
  what: 'End tag for an element that is not in scope'
8929
+ },
8930
+ 'End tag had attributes.': {
8931
+ variable: false,
8932
+ quality: 1,
8933
+ what: 'End tag has an attribute'
8623
8934
  }
8624
8935
  }
8625
8936
  }
@@ -8709,6 +9020,21 @@ exports.issues = {
8709
9020
  }
8710
9021
  }
8711
9022
  },
9023
+ entityBad: {
9024
+ summary: 'named character reference invalid',
9025
+ why: 'User may be unable to read all the document text',
9026
+ wcag: '4.1',
9027
+ weight: 4,
9028
+ tools: {
9029
+ nuVal: {
9030
+ 'Named character reference was not terminated by a semicolon. (Or & should have been escaped as &amp;.)': {
9031
+ variable: false,
9032
+ quality: 1,
9033
+ what: '& not escaped or used in an unterminated character reference'
9034
+ }
9035
+ }
9036
+ }
9037
+ },
8712
9038
  textContentBad: {
8713
9039
  summary: 'element text content invalid',
8714
9040
  why: 'User may be unable to read all the document text',
@@ -8801,10 +9127,10 @@ exports.issues = {
8801
9127
  quality: 1,
8802
9128
  what: 'Invalid element name'
8803
9129
  },
8804
- 'Quote \" in attribute name. Probable cause: Matching quote missing somewhere earlier.': {
8805
- variable: false,
9130
+ '^Quote . in attribute name\. Probable cause: Matching quote missing somewhere earlier\.$': {
9131
+ variable: true,
8806
9132
  quality: 1,
8807
- what: 'Attribute name includes a double quotation mark'
9133
+ what: 'Attribute name includes an apostrophe or double quotation mark'
8808
9134
  },
8809
9135
  'Element script must not have attribute async unless attribute src is also specified or unless attribute type is specified with value module.': {
8810
9136
  variable: false,
@@ -8826,11 +9152,6 @@ exports.issues = {
8826
9152
  quality: 1,
8827
9153
  what: 'Element has an invalid ancestor'
8828
9154
  },
8829
- 'The first child option element of a select element with a required attribute, and without a multiple attribute, and without a size attribute whose value is greater than 1, must have either an empty value attribute, or must have no text content. Consider either adding a placeholder option label, or adding a size attribute with a value equal to the number of option elements.': {
8830
- variable: false,
8831
- quality: 1,
8832
- what: 'option element has a nonempty value'
8833
- },
8834
9155
  'Element script must not have attribute charset unless attribute src is also specified.': {
8835
9156
  variable: false,
8836
9157
  quality: 1,
@@ -8850,6 +9171,11 @@ exports.issues = {
8850
9171
  variable: true,
8851
9172
  quality: 1,
8852
9173
  what: 'Element is invalid because its namespace is not HTML'
9174
+ },
9175
+ 'A slash was not immediately followed by >.': {
9176
+ variable: false,
9177
+ quality: 1,
9178
+ what: 'Element start tag contains a nonfinal slash'
8853
9179
  }
8854
9180
  },
8855
9181
  qualWeb: {
@@ -8906,15 +9232,20 @@ exports.issues = {
8906
9232
  weight: 4,
8907
9233
  tools: {
8908
9234
  nuVal: {
9235
+ '^Internal encoding declaration named an unsupported chararacter encoding .*$': {
9236
+ variable: true,
9237
+ quality: 1,
9238
+ what: 'Encoding declaration names an unsupported character encoding'
9239
+ },
8909
9240
  'Text run is not in Unicode Normalization Form C.': {
8910
9241
  variable: false,
8911
9242
  quality: 1,
8912
- what: 'Text run is not in Unicode Normalization Form C.'
9243
+ what: 'Text run is not in Unicode Normalization Form C'
8913
9244
  },
8914
9245
  '^The value of attribute .+ on element .+ from namespace .+ is not in Unicode Normalization Form C.*$': {
8915
9246
  variable: true,
8916
9247
  quality: 1,
8917
- what: 'Value of attribute is not in Unicode Normalization Form C.'
9248
+ what: 'Value of attribute is not in Unicode Normalization Form C'
8918
9249
  },
8919
9250
  '^Forbidden code point U+.*$': {
8920
9251
  variable: true,
package/procs/util.js CHANGED
@@ -34,9 +34,19 @@ const alphaNumChars = (() => {
34
34
  return digits.concat(lowers);
35
35
  })();
36
36
  // Tools.
37
- const toolIDs = exports.toolIDs = [
38
- 'alfa', 'aslint', 'axe', 'ed11y', 'htmlcs', 'ibm', 'nuVal', 'qualWeb', 'testaro', 'wave', 'wax'
39
- ];
37
+ const tools = exports.tools = {
38
+ alfa: 'Alfa',
39
+ aslint: 'ASLint',
40
+ axe: 'Axe',
41
+ ed11y: 'Editoria11y',
42
+ htmlcs: 'HTML CodeSniffer',
43
+ ibm: 'Accessibility Checker',
44
+ nuVal: 'Nu Html Checker',
45
+ qualWeb: 'QualWeb',
46
+ testaro: 'Testaro',
47
+ wave: 'WAVE',
48
+ wax: 'WallyAX'
49
+ };
40
50
 
41
51
  // FUNCTIONS
42
52
 
package/script.js CHANGED
@@ -32,7 +32,7 @@ require('dotenv').config();
32
32
  // Devices recognized by Playwright.
33
33
  const {devices} = require('playwright');
34
34
  // Utility module.
35
- const {isToolID, toolIDs} = require('./procs/util');
35
+ const {isToolID, tools} = require('./procs/util');
36
36
 
37
37
  // ########## FUNCTIONS
38
38
 
@@ -142,7 +142,7 @@ exports.script = (id, what, deviceID, options = {}) => {
142
142
  // Otherwise, i.e. if options are not specified:
143
143
  else {
144
144
  // Populate the data on tools and rules.
145
- toolIDs.forEach(toolID => {
145
+ Object.keys(tools).forEach(toolID => {
146
146
  toolsRulesData[toolID] = [];
147
147
  });
148
148
  }
@@ -151,7 +151,6 @@ exports.script = (id, what, deviceID, options = {}) => {
151
151
  id,
152
152
  what,
153
153
  strict: false,
154
- isolate: true,
155
154
  standard: 'only',
156
155
  observe: false,
157
156
  device: {
@@ -171,14 +170,9 @@ exports.script = (id, what, deviceID, options = {}) => {
171
170
  script: id,
172
171
  batch: '',
173
172
  mergeID: '',
174
- requester: process.env.REQUESTER || ''
173
+ requester: ''
175
174
  },
176
- acts: [
177
- {
178
- type: 'placeholder',
179
- which: 'main'
180
- }
181
- ]
175
+ acts: []
182
176
  };
183
177
  // Add the window options to the script.
184
178
  scriptObj.device.windowOptions = getWindowOptions(deviceID);
@@ -187,7 +181,9 @@ exports.script = (id, what, deviceID, options = {}) => {
187
181
  // Initialize a test act for it.
188
182
  const toolAct = {
189
183
  type: 'test',
190
- which: toolID
184
+ launch: {},
185
+ which: toolID,
186
+ what: tools[toolID]
191
187
  };
192
188
  // If rules were specified:
193
189
  const ruleIDs = toolsRulesData[toolID];