testilo 3.9.2 → 3.9.5

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/procs/score/sp15a.js +358 -126
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "3.9.2",
3
+ "version": "3.9.5",
4
4
  "description": "Client that scores and digests Testaro reports",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -10,8 +10,8 @@
10
10
  This proc applies specified weights to the component scores before summing them. An issue reported
11
11
  by a test is given a score. That score is determined by:
12
12
  Whether the issue is reported as an error or a warning.
13
- How important the issue is, if the test package is pre-weighted (axe, tenon, and testaro)
14
- Whether the test belongs to a group or is a solo test.
13
+ How important the issue is, if the test package is pre-weighted (axe, tenon, and testaro)
14
+ Whether the test belongs to a group or is a solo test.
15
15
  How heavily the group is weighted, if the test package is not pre-weighted and the test belongs
16
16
  to a group
17
17
 
@@ -27,7 +27,7 @@
27
27
  Browser logging produces a log score, and the prevention of tests produces a prevention score.
28
28
  They, too, are added to the total score.
29
29
 
30
- Each grouped test has a quality property, typically set to 1. The value of this property can be
30
+ Each grouped test has a quality property, typically set to 1. The value of this property can be
31
31
  modified when the test is found to be higher or lower in quality than usual.
32
32
  */
33
33
 
@@ -58,22 +58,42 @@ const otherPackages = ['alfa', 'axe', 'continuum', 'htmlcs', 'ibm', 'nuVal', 'te
58
58
  const preWeightedPackages = ['axe', 'tenon', 'testaro'];
59
59
  const testMatchers = {
60
60
  nuVal: [
61
- /^CSS: “background-image”: .+ is not a “background-image” value.*$/,
62
- /^CSS: “background”: .+ is not a “color” value.*$/,
63
- /^CSS: “cursor”: .+ is not a “cursor” value.*$/,
64
- /^CSS: “transform”: .+ is not a “transform” value.*$/,
65
- /^Duplicate ID .+$|^The first occurrence of ID .+ was here.*$/,
61
+ /^CSS: .+: .+ is not a .+ value.*$/,
62
+ /^CSS: .+: Too many values or values are not recognized.+$/,
63
+ /^CSS: .+: Parse Error.*$/,
64
+ /^CSS: .+: Invalid type: .+$/,
65
+ /^CSS: .+: The types are incompatible.*$/,
66
+ /^CSS: .+: Unknown dimension.*$/,
67
+ /^The role attribute must not be used on a .+ element which has a table ancestor with no role attribute, or with a role attribute whose value is table, grid, or treegrid.*$/,
68
+ /^Bad value for attribute .+ on element .+: An ID must not be the empty string.+$/,
69
+ /^Bad value for attribute aria-owns on element .+: An IDREFS value must contain at least one non-whitespace character.*$/,
70
+ /^Bad value for attribute src on element .+: Must be non-empty.*$/,
71
+ /^Bad value for attribute tabindex on element .+: The empty string is not a valid integer.*$/,
72
+ /^The aria-hidden attribute must not be specified on the .+ element.*$/,
73
+ /^Element meta is missing one or more of the following attributes: .+$/,
74
+ /^Duplicate ID .+$|^The first occurrence of ID .* was here.*$/,
66
75
  /^Start tag .+ seen but an element of the same type was already open.*$/,
76
+ /^Bad start tag in .+$/,
67
77
  /^End tag .+ violates nesting rules.*$/,
78
+ /^Stray end tag .+$/,
79
+ /^Element name .+ cannot be represented as XML 1\.0.*$/,
68
80
  /^Attribute .+ is not serializable as XML 1\.0.*$/,
69
- /^Attribute .+ not allowed on element meta at this point.*$/,
81
+ /^Attribute .+ not allowed on element meta at this point.*$/,
70
82
  /^Attribute .+ not allowed on element .+ at this point.*$/,
71
- /^Bad value .+ for attribute .+ on element meta”.*$/,
83
+ /^Bad value .+ for attribute .+ on element meta.*$/,
72
84
  /^Bad value .+ for attribute .+ on element .+$/,
85
+ /^Bad value .+ for the attribute .+$/,
73
86
  /^Attribute .+ not allowed here.*$/,
87
+ /^Attribute .+ is only allowed when .+$/,
88
+ /^The .+ attribute on the .+ element is obsolete.+$/,
89
+ /^The .+ role is unnecessary for element .+$/,
74
90
  /^CSS: .+: Property .+ doesn't exist.*$/,
75
- /^CSS: .+: only 0 can be a length”. You must put a unit after your number.*$/,
76
- /^Element .+ not allowed as child of element .+ in this context.*$/
91
+ /^CSS: .+: only 0 can be a length. You must put a unit after your number.*$/,
92
+ /^CSS: .+: only 0 can be a unit. You must put a unit after your number.*$/,
93
+ /^Element .+ not allowed as child of element .+ in this context.*$/,
94
+ /^Forbidden code point U+.+$/,
95
+ /^Internal encoding declaration .+ disagrees with the actual encoding of the document.*$/,
96
+ /^Potentially bad value .+ for attribute sandbox on element iframe: Setting both allow-scripts and allow-same-origin is not recommended, because it effectively enables an embedded page to break out of all sandboxing.*$/
77
97
  ]
78
98
  };
79
99
  const groups = {
@@ -81,7 +101,7 @@ const groups = {
81
101
  weight: 0,
82
102
  packages: {
83
103
  nuVal: {
84
- 'Element mediaelementwrapper not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
104
+ 'Element mediaelementwrapper not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
85
105
  quality: 0,
86
106
  what: 'Bug in nuVal'
87
107
  }
@@ -130,7 +150,7 @@ const groups = {
130
150
  }
131
151
  },
132
152
  nuVal: {
133
- '^Duplicate ID .+$|^The first occurrence of ID .+ was here.*$': {
153
+ '^Duplicate ID .+$|^The first occurrence of ID .* was here.*$': {
134
154
  quality: 1,
135
155
  what: 'Duplicate id'
136
156
  }
@@ -348,7 +368,7 @@ const groups = {
348
368
  }
349
369
  },
350
370
  nuVal: {
351
- 'An img element must have an alt attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.': {
371
+ 'An img element must have an alt attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.': {
352
372
  quality: 1,
353
373
  what: 'img element has no alt attribute'
354
374
  }
@@ -391,18 +411,29 @@ const groups = {
391
411
  weight: 4,
392
412
  packages: {
393
413
  nuVal: {
394
- 'Element img is missing required attribute src”.': {
414
+ 'Element img is missing required attribute src.': {
395
415
  quality: 1,
396
416
  what: 'img element has no src attribute'
397
417
  }
398
418
  }
399
419
  }
400
420
  },
421
+ sourceEmpty: {
422
+ weight: 4,
423
+ packages: {
424
+ nuVal: {
425
+ '^Bad value for attribute src on element .+: Must be non-empty.*$': {
426
+ quality: 1,
427
+ what: 'src attribute is empty'
428
+ }
429
+ }
430
+ }
431
+ },
401
432
  backgroundBad: {
402
433
  weight: 4,
403
434
  packages: {
404
435
  nuVal: {
405
- '^CSS: background”: .+ is not a color value.*$': {
436
+ '^CSS: background: .+ is not a color value.*$': {
406
437
  quality: 1,
407
438
  what: 'CSS background color is misdefined'
408
439
  }
@@ -413,7 +444,7 @@ const groups = {
413
444
  weight: 4,
414
445
  packages: {
415
446
  nuVal: {
416
- '^CSS: background-image”: .+ is not a background-image value.*$': {
447
+ '^CSS: background-image: .+ is not a background-image value.*$': {
417
448
  quality: 1,
418
449
  what: 'CSS background image is misdefined'
419
450
  }
@@ -482,7 +513,7 @@ const groups = {
482
513
  }
483
514
  },
484
515
  decorativeElementExposed: {
485
- weight: 1,
516
+ weight: 2,
486
517
  packages: {
487
518
  alfa: {
488
519
  r67: {
@@ -493,6 +524,12 @@ const groups = {
493
524
  quality: 1,
494
525
  what: 'Element marked as decorative is in the accessibility tree or has no none/presentation role'
495
526
  }
527
+ },
528
+ nuVal: {
529
+ 'An img element which has an alt attribute whose value is the empty string must not have a role attribute.': {
530
+ quality: 1,
531
+ what: 'img element with alt="" has a role attribute'
532
+ }
496
533
  }
497
534
  }
498
535
  },
@@ -529,6 +566,12 @@ const groups = {
529
566
  what: 'Page detected as HTML, but has no lang attribute'
530
567
  }
531
568
  },
569
+ nuVal: {
570
+ 'Consider adding a lang attribute to the html start tag to declare the language of this document.': {
571
+ quality: 1,
572
+ what: 'html start tag has no lang attribute to declare the language of the page'
573
+ }
574
+ },
532
575
  wave: {
533
576
  'e:language_missing': {
534
577
  quality: 1,
@@ -785,10 +828,6 @@ const groups = {
785
828
  }
786
829
  },
787
830
  wave: {
788
- 'a:label_orphaned': {
789
- quality: 1,
790
- what: 'Orphaned form label'
791
- },
792
831
  'a:link_internal_broken': {
793
832
  quality: 1,
794
833
  what: 'Broken same-page link'
@@ -796,13 +835,19 @@ const groups = {
796
835
  }
797
836
  }
798
837
  },
799
- labelForWrongRisk: {
800
- weight: 1,
838
+ labelForBad: {
839
+ weight: 3,
801
840
  packages: {
802
841
  htmlcs: {
803
842
  'w:AA.1_3_1.H44.NotFormControl': {
804
843
  quality: 1,
805
- what: 'Label for attribute may reference the wrong element, because it is not a form control'
844
+ what: 'referent of the for attribute of the label is not a form control, so may be wrong'
845
+ }
846
+ },
847
+ nuVal: {
848
+ 'The value of the for attribute of the label element must be the ID of a non-hidden form control.': {
849
+ quality: 1,
850
+ what: 'for attribute of the label element does not reference a non-hidden form control'
806
851
  }
807
852
  }
808
853
  }
@@ -811,7 +856,7 @@ const groups = {
811
856
  weight: 1,
812
857
  packages: {
813
858
  nuVal: {
814
- 'Possible misuse of aria-label”. (If you disagree with this warning, file an issue report or send e-mail to www-validator@w3.org.)': {
859
+ 'Possible misuse of aria-label. (If you disagree with this warning, file an issue report or send e-mail to www-validator@w3.org.)': {
815
860
  quality: 1,
816
861
  what: 'aria-label attribute may be misused'
817
862
  }
@@ -843,6 +888,12 @@ const groups = {
843
888
  quality: 1,
844
889
  what: 'aria-controls attribute references an invalid or duplicate ID'
845
890
  }
891
+ },
892
+ nuVal: {
893
+ 'The aria-controls attribute must point to an element in the same document.': {
894
+ quality: 1,
895
+ what: 'aria-controls attribute references an element not in the document'
896
+ }
846
897
  }
847
898
  }
848
899
  },
@@ -898,9 +949,13 @@ const groups = {
898
949
  }
899
950
  },
900
951
  nuVal: {
901
- 'The aria-labelledby attribute must point to an element in the same document.': {
952
+ 'The aria-labelledby attribute must point to an element in the same document.': {
902
953
  quality: 1,
903
954
  what: 'aria-labelledby attribute references an element not in the document'
955
+ },
956
+ 'The aria-describedby attribute must point to an element in the same document.': {
957
+ quality: 1,
958
+ what: 'aria-describedby attribute references an element not in the document'
904
959
  }
905
960
  },
906
961
  wave: {
@@ -982,6 +1037,12 @@ const groups = {
982
1037
  what: 'Hyperlink has no text description'
983
1038
  }
984
1039
  },
1040
+ nuVal: {
1041
+ 'Bad value for attribute href on element link: Must be non-empty.': {
1042
+ quality: 1,
1043
+ what: 'link element has an empty href attribute'
1044
+ }
1045
+ },
985
1046
  tenon: {
986
1047
  57: {
987
1048
  quality: 1,
@@ -1185,7 +1246,7 @@ const groups = {
1185
1246
  weight: 4,
1186
1247
  packages: {
1187
1248
  nuVal: {
1188
- 'Attribute alt not allowed on element button at this point.': {
1249
+ 'Attribute alt not allowed on element button at this point.': {
1189
1250
  quality: 1,
1190
1251
  what: 'button element has an alt attribute'
1191
1252
  }
@@ -1351,6 +1412,12 @@ const groups = {
1351
1412
  quality: 1,
1352
1413
  what: 'meta element in the head sets the viewport maximum-scale to less than 2'
1353
1414
  }
1415
+ },
1416
+ nuVal: {
1417
+ 'Consider avoiding viewport values that prevent users from resizing documents.': {
1418
+ quality: 1,
1419
+ what: 'viewport value prevents users from resizing the document'
1420
+ }
1354
1421
  }
1355
1422
  }
1356
1423
  },
@@ -1487,7 +1554,7 @@ const groups = {
1487
1554
  weight: 4,
1488
1555
  packages: {
1489
1556
  nuVal: {
1490
- 'Element title not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
1557
+ 'Element title not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
1491
1558
  quality: 1,
1492
1559
  what: 'title element is a child of the body element'
1493
1560
  }
@@ -1504,9 +1571,13 @@ const groups = {
1504
1571
  weight: 4,
1505
1572
  packages: {
1506
1573
  nuVal: {
1507
- 'A link element must not appear as a descendant of a body element unless the link element has an itemprop attribute or has a rel attribute whose value contains dns-prefetch”, modulepreload”, pingback”, preconnect”, prefetch”, preload”, prerender”, or stylesheet”.': {
1574
+ 'A link element must not appear as a descendant of a body element unless the link element has an itemprop attribute or has a rel attribute whose value contains dns-prefetch, modulepreload, pingback, preconnect, prefetch, preload, prerender, or stylesheet.': {
1508
1575
  quality: 1,
1509
1576
  what: 'link element with a body ancestor has no itemprop or valid rel attribute'
1577
+ },
1578
+ 'A link element with an as attribute must have a rel attribute that contains the value preload or the value modulepreload or the value prefetch.': {
1579
+ quality: 1,
1580
+ what: 'link element with an as attribute has no rel attribute with preload, modulepreload, or prefetch as its value'
1510
1581
  }
1511
1582
  }
1512
1583
  }
@@ -1515,44 +1586,56 @@ const groups = {
1515
1586
  weight: 3,
1516
1587
  packages: {
1517
1588
  nuVal: {
1518
- '^Attribute .+ not allowed on element meta at this point.*$': {
1589
+ '^Attribute .+ not allowed on element meta at this point.*$': {
1519
1590
  quality: 1,
1520
1591
  what: 'Attribute is not allowed on a meta element here'
1521
1592
  },
1522
- 'Element meta is missing one or more of the following attributes: “charset”, “content”, “http-equiv”, “itemprop”, “name”, “property”.': {
1593
+ '^Element meta is missing one or more of the following attributes: .+$': {
1523
1594
  quality: 1,
1524
- what: 'meta element is missing a charset, content, http-equiv, itemprop, name, or property attribute'
1595
+ what: 'meta element is missing a required attribute'
1525
1596
  },
1526
- 'A document must not include more than one meta element with its name attribute set to the value description”.': {
1597
+ 'A document must not include more than one meta element with its name attribute set to the value description.': {
1527
1598
  quality: 1,
1528
1599
  what: 'meta element with name="description" is not the only one'
1529
1600
  },
1530
- 'A meta element with an http-equiv attribute whose value is “X-UA-Compatible” must have a “content” attribute with the value “IE=edge”.': {
1601
+ 'A document must not include both a meta element with an http-equiv attribute whose value is content-type, and a meta element with a charset attribute.': {
1602
+ quality: 1,
1603
+ what: 'meta element with http-equiv="content-type" is incompatible with the meta element with a charset attribute'
1604
+ },
1605
+ 'A document must not include more than one meta element with a http-equiv attribute whose value is content-type.': {
1606
+ quality: 1,
1607
+ what: 'Page has more than 1 meta element with http-equiv="content-type"'
1608
+ },
1609
+ 'A meta element with an http-equiv attribute whose value is X-UA-Compatible must have a content attribute with the value IE=edge.': {
1531
1610
  quality: 1,
1532
1611
  what: 'meta element with http-equiv="X-UA-Compatible" has no content="IE=edge"'
1533
1612
  },
1534
- 'Element “meta” is missing one or more of the following attributes: “itemprop”, “property”.': {
1613
+ 'A document must not include more than one meta element with a charset attribute.': {
1535
1614
  quality: 1,
1536
- what: 'meta element is missing an itemprop or property attribute'
1615
+ what: 'More than 1 meta element has a charset attribute'
1537
1616
  },
1538
- 'A charset attribute on a meta element found after the first 1024 bytes.': {
1617
+ 'A charset attribute on a meta element found after the first 1024 bytes.': {
1539
1618
  quality: 1,
1540
1619
  what: 'charset attribute on a meta element appears after 1024 bytes'
1541
1620
  },
1542
- '^Bad value .+ for attribute .+ on element meta”.*$': {
1621
+ '^Bad value .+ for attribute .+ on element meta.*$': {
1543
1622
  quality: 1,
1544
1623
  what: 'attribute of a meta element has an invalid value'
1545
1624
  }
1546
1625
  }
1547
1626
  }
1548
1627
  },
1549
- scriptDeferBad: {
1628
+ scriptElementBad: {
1550
1629
  weight: 4,
1551
1630
  packages: {
1552
1631
  nuVal: {
1553
- 'Element script must not have attribute defer unless attribute src is also specified.': {
1632
+ 'Element script must not have attribute defer unless attribute src is also specified.': {
1554
1633
  quality: 1,
1555
1634
  what: 'script element has a defer attribute without a src attribute'
1635
+ },
1636
+ '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.': {
1637
+ quality: 1,
1638
+ what: 'script element has a src attribute but its type is not empty, a JS MIME type, or module'
1556
1639
  }
1557
1640
  }
1558
1641
  }
@@ -1561,7 +1644,7 @@ const groups = {
1561
1644
  weight: 4,
1562
1645
  packages: {
1563
1646
  nuVal: {
1564
- 'The itemtype attribute must not be specified on elements that do not have an itemscope attribute specified.': {
1647
+ 'The itemtype attribute must not be specified on elements that do not have an itemscope attribute specified.': {
1565
1648
  quality: 1,
1566
1649
  what: 'Element has an itemtype attribute without an itemscope attribute'
1567
1650
  }
@@ -1679,9 +1762,17 @@ const groups = {
1679
1762
  }
1680
1763
  },
1681
1764
  nuVal: {
1682
- 'Bad value dialog for attribute role on element li”.': {
1765
+ 'Bad value dialog for attribute role on element li.': {
1683
1766
  quality: 1,
1684
1767
  what: 'dialog role is not valid for an li element'
1768
+ },
1769
+ 'An img element with no alt attribute must not have a role attribute.': {
1770
+ quality: 1,
1771
+ what: 'img element has a role attribute but no alt attribute'
1772
+ },
1773
+ '^The role attribute must not be used on a .+ element which has a table ancestor with no role attribute, or with a role attribute whose value is table, grid, or treegrid.*$': {
1774
+ quality: 1,
1775
+ what: 'Table cell has a role attribute'
1685
1776
  }
1686
1777
  },
1687
1778
  testaro: {
@@ -1702,21 +1793,13 @@ const groups = {
1702
1793
  }
1703
1794
  },
1704
1795
  nuVal: {
1705
- 'The “banner” role is unnecessary for element “header”.': {
1706
- quality: 1,
1707
- what: 'banner role is redundant for a header element'
1708
- },
1709
- 'The “contentinfo” role is unnecessary for element “footer”.': {
1710
- quality: 1,
1711
- what: 'contentinfo role is redundant for a footer element'
1712
- },
1713
- 'The “main” role is unnecessary for element “main”.': {
1796
+ '^The .+ role is unnecessary for element .+$': {
1714
1797
  quality: 1,
1715
- what: 'main role is redundant for a main element'
1798
+ what: 'explicit role is redundant for its element'
1716
1799
  },
1717
- 'The “navigation” role is unnecessary for element “nav”.': {
1800
+ 'The textbox role is unnecessary for an input element that has no list attribute and whose type is text.': {
1718
1801
  quality: 1,
1719
- what: 'navigation role is redundant for a nav element'
1802
+ what: 'explicit role is redundant for a text-type input element without a list attribute'
1720
1803
  }
1721
1804
  }
1722
1805
  }
@@ -1737,9 +1820,13 @@ const groups = {
1737
1820
  }
1738
1821
  },
1739
1822
  nuVal: {
1740
- 'Element a is missing required attribute aria-valuenow”.': {
1823
+ 'Element a is missing required attribute aria-valuenow.': {
1741
1824
  quality: 1,
1742
1825
  what: 'a element has no aria-valuenow attribute'
1826
+ },
1827
+ 'Element a is missing one or more of the following attributes: aria-checked, role.': {
1828
+ quality: 1,
1829
+ what: 'a element has no aria-checked attribute or has no role attribute'
1743
1830
  }
1744
1831
  }
1745
1832
  }
@@ -1879,9 +1966,17 @@ const groups = {
1879
1966
  }
1880
1967
  },
1881
1968
  nuVal: {
1882
- 'The aria-hidden attribute must not be specified on the noscript element.': {
1969
+ 'The aria-hidden attribute must not be specified on the noscript element.': {
1883
1970
  quality: 1,
1884
1971
  what: 'noscript element has an aria-hidden attribute'
1972
+ },
1973
+ 'Attribute aria-activedescendant value should either refer to a descendant element, or should be accompanied by attribute aria-owns.': {
1974
+ quality: 1,
1975
+ what: 'element has no aria-owns attribute but its aria-activedescendant attribute references a non-descendant'
1976
+ },
1977
+ 'The aria-checked attribute should not be used on an input element which has a type attribute whose value is checkbox.': {
1978
+ quality: 1,
1979
+ what: 'input element with type="checkbox" has an aria-checked attribute'
1885
1980
  }
1886
1981
  }
1887
1982
  }
@@ -1894,6 +1989,12 @@ const groups = {
1894
1989
  quality: 1,
1895
1990
  what: 'ARIA attribute is used when there is a corresponding HTML attribute'
1896
1991
  }
1992
+ },
1993
+ nuVal: {
1994
+ 'Attribute aria-required is unnecessary for elements that have attribute required.': {
1995
+ quality: 1,
1996
+ what: 'aria-required attribute is redundant with required attribute'
1997
+ }
1897
1998
  }
1898
1999
  }
1899
2000
  },
@@ -1926,19 +2027,25 @@ const groups = {
1926
2027
  axe: {
1927
2028
  'autocomplete-valid': {
1928
2029
  quality: 1,
1929
- what: 'Autocomplete attribute is used incorrectly'
2030
+ what: 'autocomplete attribute is used incorrectly'
1930
2031
  }
1931
2032
  },
1932
2033
  htmlcs: {
1933
2034
  'e:AA.1_3_5.H98': {
1934
2035
  quality: 1,
1935
- what: 'Autocomplete attribute and the input type are mismatched'
2036
+ what: 'autocomplete attribute and the input type are mismatched'
1936
2037
  }
1937
2038
  },
1938
2039
  ibm: {
1939
2040
  WCAG21_Input_Autocomplete: {
1940
2041
  quality: 1,
1941
- what: 'Autocomplete attribute token is not appropriate for the input form field'
2042
+ what: 'autocomplete attribute token is not appropriate for the input form field'
2043
+ }
2044
+ },
2045
+ nuVal: {
2046
+ 'Bad value for attribute autocomplete on element input: Must not be empty.': {
2047
+ quality: 1,
2048
+ what: 'autocomplete attribute has an empty value'
1942
2049
  }
1943
2050
  }
1944
2051
  }
@@ -1955,7 +2062,7 @@ const groups = {
1955
2062
  }
1956
2063
  },
1957
2064
  contrastAA: {
1958
- weight: 3,
2065
+ weight: 4,
1959
2066
  packages: {
1960
2067
  alfa: {
1961
2068
  r69: {
@@ -2065,9 +2172,24 @@ const groups = {
2065
2172
  weight: 4,
2066
2173
  packages: {
2067
2174
  nuVal: {
2068
- 'Bad value “” for attribute “id” on element “a”: An ID must not be the empty string.': {
2175
+ '^Bad value for attribute .+ on element .+: An ID must not be the empty string.+$': {
2069
2176
  quality: 1,
2070
2177
  what: 'id attribute has an empty value'
2178
+ },
2179
+ '^Bad value for attribute aria-owns on element .+: An IDREFS value must contain at least one non-whitespace character.*$': {
2180
+ quality: 1,
2181
+ what: 'aria-owns attribute has an empty value'
2182
+ }
2183
+ }
2184
+ }
2185
+ },
2186
+ targetEmpty: {
2187
+ weight: 4,
2188
+ packages: {
2189
+ nuVal: {
2190
+ 'Bad value for attribute target on element a: Browsing context name must be at least one character long.': {
2191
+ quality: 1,
2192
+ what: 'target attribute on an a element is empty'
2071
2193
  }
2072
2194
  }
2073
2195
  }
@@ -2128,11 +2250,11 @@ const groups = {
2128
2250
  weight: 1,
2129
2251
  packages: {
2130
2252
  nuVal: {
2131
- 'The type attribute is unnecessary for JavaScript resources.': {
2253
+ 'The type attribute is unnecessary for JavaScript resources.': {
2132
2254
  quality: 1,
2133
2255
  what: 'type attribute is unnecessary for a JavaScript resource'
2134
2256
  },
2135
- 'The type attribute for the style element is not needed and should be omitted.': {
2257
+ 'The type attribute for the style element is not needed and should be omitted.': {
2136
2258
  quality: 1,
2137
2259
  what: 'type attribute is unnecessary for a style element'
2138
2260
  }
@@ -2224,8 +2346,14 @@ const groups = {
2224
2346
  }
2225
2347
  },
2226
2348
  docType: {
2227
- weight: 1,
2349
+ weight: 3,
2228
2350
  packages: {
2351
+ nuVal: {
2352
+ 'Start tag seen without seeing a doctype first. Expected <!DOCTYPE html>.': {
2353
+ quality: 1,
2354
+ what: 'Page does not start with <!DOCTYPE html>'
2355
+ }
2356
+ },
2229
2357
  testaro: {
2230
2358
  docType: {
2231
2359
  quality: 1,
@@ -2268,7 +2396,7 @@ const groups = {
2268
2396
  }
2269
2397
  },
2270
2398
  nuVal: {
2271
- 'Element head is missing a required instance of child element title”.': {
2399
+ 'Element head is missing a required instance of child element title.': {
2272
2400
  quality: 1,
2273
2401
  what: 'head element has no child title element'
2274
2402
  }
@@ -2303,7 +2431,7 @@ const groups = {
2303
2431
  }
2304
2432
  },
2305
2433
  nuVal: {
2306
- 'Consider using the h1 element as a top-level heading only (all h1 elements are treated as top-level headings by many screen readers and other tools).': {
2434
+ 'Consider using the h1 element as a top-level heading only (all h1 elements are treated as top-level headings by many screen readers and other tools).': {
2307
2435
  quality: 1,
2308
2436
  what: 'Page contains more than 1 h1 element'
2309
2437
  }
@@ -2373,11 +2501,26 @@ const groups = {
2373
2501
  }
2374
2502
  }
2375
2503
  },
2504
+ articleHeadingless: {
2505
+ weight: 1,
2506
+ packages: {
2507
+ nuVal: {
2508
+ 'Article lacks heading. Consider using h2-h6 elements to add identifying headings to all articles.': {
2509
+ quality: 1,
2510
+ what: 'article has no heading'
2511
+ }
2512
+ }
2513
+ }
2514
+ },
2376
2515
  sectionHeadingless: {
2377
2516
  weight: 1,
2378
2517
  packages: {
2379
2518
  nuVal: {
2380
- 'Section lacks heading. Consider using h2”-“h6 elements to add identifying headings to all sections.': {
2519
+ 'Section lacks heading. Consider using h2-h6 elements to add identifying headings to all sections.': {
2520
+ quality: 1,
2521
+ what: 'section has no heading'
2522
+ },
2523
+ 'Section lacks heading. Consider using h2-h6 elements to add identifying headings to all sections, or else use a div element instead for any cases where no heading is needed.': {
2381
2524
  quality: 1,
2382
2525
  what: 'section has no heading'
2383
2526
  }
@@ -2521,6 +2664,12 @@ const groups = {
2521
2664
  quality: 1,
2522
2665
  what: 'List component with a group role has a non-listitem child'
2523
2666
  }
2667
+ },
2668
+ nuVal: {
2669
+ 'Element dl is missing a required child element.': {
2670
+ quality: 1,
2671
+ what: 'dl element has no child element.'
2672
+ }
2524
2673
  }
2525
2674
  }
2526
2675
  },
@@ -2544,7 +2693,7 @@ const groups = {
2544
2693
  }
2545
2694
  },
2546
2695
  nuVal: {
2547
- 'Element li not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
2696
+ 'Element li not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
2548
2697
  quality: 1,
2549
2698
  what: 'li element is a child of a div element'
2550
2699
  }
@@ -2606,6 +2755,28 @@ const groups = {
2606
2755
  }
2607
2756
  }
2608
2757
  },
2758
+ optionOrphan: {
2759
+ weight: 4,
2760
+ packages: {
2761
+ nuVal: {
2762
+ 'An element with role=option must be contained in, or owned by, an element with role=listbox.': {
2763
+ quality: 1,
2764
+ what: 'element with an option role is not contained by an element with a listbox role'
2765
+ }
2766
+ }
2767
+ }
2768
+ },
2769
+ optionNoText: {
2770
+ weight: 4,
2771
+ packages: {
2772
+ nuVal: {
2773
+ 'Element option without attribute label must not be empty.': {
2774
+ quality: 1,
2775
+ what: 'option element is empty but has no label attribute'
2776
+ }
2777
+ }
2778
+ }
2779
+ },
2609
2780
  selectFlatRisk: {
2610
2781
  weight: 1,
2611
2782
  packages: {
@@ -2772,7 +2943,7 @@ const groups = {
2772
2943
  }
2773
2944
  },
2774
2945
  cellHeadersAmbiguityRisk: {
2775
- weight: 3,
2946
+ weight: 2,
2776
2947
  packages: {
2777
2948
  htmlcs: {
2778
2949
  'w:AA.1_3_1.H43.ScopeAmbiguous': {
@@ -2936,7 +3107,7 @@ const groups = {
2936
3107
  }
2937
3108
  },
2938
3109
  targetSize: {
2939
- weight: 2,
3110
+ weight: 3,
2940
3111
  packages: {
2941
3112
  tenon: {
2942
3113
  152: {
@@ -2972,6 +3143,20 @@ const groups = {
2972
3143
  what: 'Link contains an input, keygen, select, textarea, or button'
2973
3144
  }
2974
3145
  },
3146
+ nuVal: {
3147
+ 'The element a must not appear as a descendant of an element with the attribute role=link.': {
3148
+ quality: 1,
3149
+ what: 'a element is a descendant of an element with a link role'
3150
+ },
3151
+ 'An element with the attribute tabindex must not appear as a descendant of the a element.': {
3152
+ quality: 1,
3153
+ what: 'descendant of an a element has a tabindex attribute'
3154
+ },
3155
+ 'An element with the attribute tabindex must not appear as a descendant of an element with the attribute role=link.': {
3156
+ quality: 1,
3157
+ what: 'descendant of an element with a link role has a tabindex attribute'
3158
+ }
3159
+ },
2975
3160
  testaro: {
2976
3161
  embAc: {
2977
3162
  quality: 1,
@@ -3151,7 +3336,7 @@ const groups = {
3151
3336
  }
3152
3337
  }
3153
3338
  },
3154
- banners: {
3339
+ bannerNot1: {
3155
3340
  weight: 2,
3156
3341
  packages: {
3157
3342
  axe: {
@@ -3190,7 +3375,7 @@ const groups = {
3190
3375
  }
3191
3376
  }
3192
3377
  },
3193
- footerMultiple: {
3378
+ footerNot1: {
3194
3379
  weight: 2,
3195
3380
  packages: {
3196
3381
  axe: {
@@ -3500,9 +3685,9 @@ const groups = {
3500
3685
  weight: 2,
3501
3686
  packages: {
3502
3687
  nuVal: {
3503
- 'Potentially bad value “allow-scripts allow-same-origin” for attribute sandbox on element iframe”: Setting both allow-scripts and allow-same-origin is not recommended, because it effectively enables an embedded page to break out of all sandboxing.': {
3688
+ '^Potentially bad value .+ for attribute sandbox on element iframe: Setting both allow-scripts and allow-same-origin is not recommended, because it effectively enables an embedded page to break out of all sandboxing.*$': {
3504
3689
  quality: 1,
3505
- what: 'iframe element has vulnerable sandbox="allow-scripts allow-same-origin"'
3690
+ what: 'iframe element has a vulnerable sandbox value containing both allow-scripts and allow-same-origin'
3506
3691
  }
3507
3692
  }
3508
3693
  }
@@ -3585,6 +3770,10 @@ const groups = {
3585
3770
  quality: 1,
3586
3771
  what: 'attribute on this element has an invalid value'
3587
3772
  },
3773
+ '^Bad value .+ for the attribute .+$': {
3774
+ quality: 1,
3775
+ what: 'attribute has an invalid value'
3776
+ },
3588
3777
  '^Attribute .+ not allowed here.*$': {
3589
3778
  quality: 1,
3590
3779
  what: 'Attribute not allowed here'
@@ -3592,6 +3781,10 @@ const groups = {
3592
3781
  '^Attribute .+ is not serializable as XML 1\\.0.*$': {
3593
3782
  quality: 1,
3594
3783
  what: 'Attribute is invalidly nonserializable'
3784
+ },
3785
+ '^Attribute .+ is only allowed when .+$': {
3786
+ quality: 1,
3787
+ what: 'Attribute is invalid here'
3595
3788
  }
3596
3789
  }
3597
3790
  }
@@ -3710,7 +3903,7 @@ const groups = {
3710
3903
  weight: 4,
3711
3904
  packages: {
3712
3905
  nuVal: {
3713
- 'Element div not allowed as child of element button in this context. (Suppressing further errors from this subtree.)': {
3906
+ 'Element div not allowed as child of element button in this context. (Suppressing further errors from this subtree.)': {
3714
3907
  quality: 1,
3715
3908
  what: 'div element has a button element as its parent'
3716
3909
  }
@@ -3721,7 +3914,7 @@ const groups = {
3721
3914
  weight: 4,
3722
3915
  packages: {
3723
3916
  nuVal: {
3724
- 'Element p not allowed as child of element strong in this context. (Suppressing further errors from this subtree.)': {
3917
+ 'Element p not allowed as child of element strong in this context. (Suppressing further errors from this subtree.)': {
3725
3918
  quality: 1,
3726
3919
  what: 'p element has a strong element as its parent'
3727
3920
  }
@@ -3732,19 +3925,19 @@ const groups = {
3732
3925
  weight: 4,
3733
3926
  packages: {
3734
3927
  nuVal: {
3735
- 'Element style not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
3928
+ 'Element style not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
3736
3929
  quality: 1,
3737
3930
  what: 'style element not allowed as a child of the body element'
3738
3931
  },
3739
- 'Element style not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
3932
+ 'Element style not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
3740
3933
  quality: 1,
3741
3934
  what: 'style element not allowed as a child of this div element'
3742
3935
  },
3743
- 'Element style not allowed as child of element main in this context. (Suppressing further errors from this subtree.)': {
3936
+ 'Element style not allowed as child of element main in this context. (Suppressing further errors from this subtree.)': {
3744
3937
  quality: 1,
3745
3938
  what: 'style element not allowed as a child of this main element'
3746
3939
  },
3747
- 'Element style not allowed as child of element footer in this context. (Suppressing further errors from this subtree.)': {
3940
+ 'Element style not allowed as child of element footer in this context. (Suppressing further errors from this subtree.)': {
3748
3941
  quality: 1,
3749
3942
  what: 'style element not allowed as a child of this footer element'
3750
3943
  }
@@ -3790,6 +3983,17 @@ const groups = {
3790
3983
  }
3791
3984
  }
3792
3985
  },
3986
+ tabIndexBad: {
3987
+ weight: 4,
3988
+ packages: {
3989
+ nuVal: {
3990
+ '^Bad value for attribute tabindex on element .+: The empty string is not a valid integer.*$': {
3991
+ quality: 1,
3992
+ what: 'tabindex attribute has an empty value instead of an integer'
3993
+ }
3994
+ }
3995
+ }
3996
+ },
3793
3997
  tabIndexMissing: {
3794
3998
  weight: 4,
3795
3999
  packages: {
@@ -4010,37 +4214,29 @@ const groups = {
4010
4214
  }
4011
4215
  },
4012
4216
  nuVal: {
4013
- 'The “charset” attribute on the “script” element is obsolete.': {
4217
+ 'The center element is obsolete. Use CSS instead.': {
4014
4218
  quality: 1,
4015
- what: 'charset attribute is obsolete on a script element'
4219
+ what: 'center element is obsolete'
4016
4220
  },
4017
- 'The only allowed value for the “charset” attribute for the “script” element is “utf-8”. (But the attribute is not needed and should be omitted altogether.)': {
4221
+ 'The font element is obsolete. Use CSS instead.': {
4018
4222
  quality: 1,
4019
- what: 'charset attribute has a value other than utf-8 and is unnecessary'
4223
+ what: 'font element is obsolete'
4020
4224
  },
4021
- 'The “language” attribute on the “script” element is obsolete. You can safely omit it.': {
4225
+ '^The .+ attribute on the .+ element is obsolete.+$': {
4022
4226
  quality: 1,
4023
- what: 'language attribute is obsolete on a script element'
4227
+ what: 'attribute is obsolete on its element'
4024
4228
  },
4025
- 'The “language” attribute on the script element is obsolete. Use the “type” attribute instead.': {
4229
+ 'The only allowed value for the charset attribute for the script element is utf-8. (But the attribute is not needed and should be omitted altogether.)': {
4026
4230
  quality: 1,
4027
- what: 'language attribute is obsolete on a script element'
4231
+ what: 'charset attribute has a value other than utf-8 and is unnecessary'
4028
4232
  },
4029
- 'The “frameborder” attribute on the “iframe” element is obsolete. Use CSS instead.': {
4233
+ 'Using the meta element to specify the document-wide default language is obsolete. Consider specifying the language on the root element instead.': {
4030
4234
  quality: 1,
4031
- what: 'frameborder attribute is obsolete'
4235
+ what: 'language declaration in a meta element is obsolete'
4032
4236
  },
4033
- 'The name attribute is obsolete. Consider putting an id attribute on the nearest container instead.': {
4237
+ 'The name attribute is obsolete. Consider putting an id attribute on the nearest container instead.': {
4034
4238
  quality: 1,
4035
4239
  what: 'name attribute is obsolete'
4036
- },
4037
- 'The “allowtransparency” attribute on the “iframe” element is obsolete. Use CSS instead.': {
4038
- quality: 1,
4039
- what: 'allowtransparency attribute on an iframe element is obsolete'
4040
- },
4041
- 'The “scrolling” attribute on the “iframe” element is obsolete. Use CSS instead.': {
4042
- quality: 1,
4043
- what: 'scrolling attribute on an iframe element is obsolete'
4044
4240
  }
4045
4241
  },
4046
4242
  wave: {
@@ -4055,54 +4251,70 @@ const groups = {
4055
4251
  weight: 3,
4056
4252
  packages: {
4057
4253
  nuVal: {
4058
- 'CSS: “-webkit-box-flex”: Parse Error.': {
4254
+ 'CSS: font-size: One operand must be a number.': {
4059
4255
  quality: 1,
4060
- what: 'Invalid -webkit-box-flex in CSS'
4256
+ what: 'CSS font-size property has no numeric operand'
4061
4257
  },
4062
- 'CSS: “-webkit-flex”: Parse Error.': {
4258
+ '^CSS: .+: Parse Error.*$': {
4063
4259
  quality: 1,
4064
- what: 'Invalid -webkit-flex in CSS'
4260
+ what: 'Invalid CSS'
4065
4261
  },
4066
- 'CSS: “-ms-flex”: Parse Error.': {
4262
+ '^CSS: .+: .+ is not a .+ value.*$': {
4067
4263
  quality: 1,
4068
- what: 'Invalid -ms-flex in CSS'
4264
+ what: 'Invalid value in CSS'
4069
4265
  },
4070
- 'CSS: “-moz-box-flex”: Parse Error.': {
4266
+ '^CSS: .+: Property .+ doesn\'t exist.*$': {
4071
4267
  quality: 1,
4072
- what: 'Invalid -moz-box-flex in CSS'
4268
+ what: 'Invalid property in CSS'
4073
4269
  },
4074
- 'CSS: “flex”: Parse Error.': {
4270
+ '^CSS: .+: only 0 can be a length. You must put a unit after your number.*$': {
4075
4271
  quality: 1,
4076
- what: 'Invalid flex in CSS'
4272
+ what: 'Length in CSS is nonzero but has no unit'
4077
4273
  },
4078
- '^CSS: “cursor”: .+ is not a “cursor” value.*$': {
4274
+ '^CSS: .+: only 0 can be a unit. You must put a unit after your number.*$': {
4079
4275
  quality: 1,
4080
- what: 'Invalid cursor in CSS'
4276
+ what: 'Number in CSS is nonzero but has no unit'
4081
4277
  },
4082
- '^CSS: “transform”: .+ is not a “transform” value.*$': {
4278
+ 'CSS: Parse Error.': {
4083
4279
  quality: 1,
4084
- what: 'Invalid transform in CSS'
4280
+ what: 'Invalid CSS'
4085
4281
  },
4086
- '^CSS: .+: Property .+ doesn\'t exist.*$': {
4282
+ '^CSS: .+: Too many values or values are not recognized.+$': {
4087
4283
  quality: 1,
4088
- what: 'Invalid property in CSS'
4284
+ what: 'Invalid CSS value or too many values'
4089
4285
  },
4090
- '^CSS: .+: only “0” can be a “length”. You must put a unit after your number.*$': {
4286
+ '^CSS: .+: Invalid type: .+$': {
4091
4287
  quality: 1,
4092
- what: 'Length in CSS is nonzero but has no unit'
4288
+ what: 'Invalid type of CSS value'
4093
4289
  },
4094
- 'CSS: Parse Error.': {
4290
+ '^CSS: .+: The types are incompatible.*$': {
4095
4291
  quality: 1,
4096
- what: 'Invalid CSS'
4292
+ what: 'Incompatible types of CSS values'
4293
+ },
4294
+ '^CSS: .+: Unknown dimension.*$': {
4295
+ quality: 1,
4296
+ what: 'Unknown CSS dimension'
4097
4297
  },
4098
- 'Stray end tag “head”.': {
4298
+ '^The aria-hidden attribute must not be specified on the .+ element.*$': {
4099
4299
  quality: 1,
4100
- what: 'Invalid closing head tag'
4300
+ what: 'aria-hidden attribute is invalid for its element'
4301
+ },
4302
+ 'The aria-hidden attribute must not be specified on an input element whose type attribute has the value hidden.': {
4303
+ quality: 1,
4304
+ what: 'aria-hidden attribute is invalid for an input element with type="hidden"'
4305
+ },
4306
+ '^Stray end tag .+$': {
4307
+ quality: 1,
4308
+ what: 'Invalid closing tag'
4101
4309
  },
4102
4310
  '^Start tag .+ seen but an element of the same type was already open.*$': {
4103
4311
  quality: 1,
4104
4312
  what: 'Element is invalidly a descendant of another such element'
4105
4313
  },
4314
+ '^Bad start tag in .+$': {
4315
+ quality: 1,
4316
+ what: 'Invalid start tag'
4317
+ },
4106
4318
  '^End tag .+ violates nesting rules.*$': {
4107
4319
  quality: 1,
4108
4320
  what: 'End tag violates nesting rules'
@@ -4110,6 +4322,26 @@ const groups = {
4110
4322
  '^Element .+ not allowed as child of element .+ in this context.*$': {
4111
4323
  quality: 1,
4112
4324
  what: 'Element not allowed as a child of its parent here'
4325
+ },
4326
+ 'Saw <!-- within a comment. Probable cause: Nested comment (not allowed).': {
4327
+ quality: 1,
4328
+ what: 'Comment is nested within a comment'
4329
+ },
4330
+ 'The document is not mappable to XML 1.0 due to two consecutive hyphens in a comment.': {
4331
+ quality: 1,
4332
+ what: 'Comment contains --'
4333
+ },
4334
+ '^Element name .+ cannot be represented as XML 1\\.0.*$': {
4335
+ quality: 1,
4336
+ what: 'Invalid element name'
4337
+ },
4338
+ '^Forbidden code point U+.+$': {
4339
+ quality: 1,
4340
+ what: 'Invalid Unicode code point'
4341
+ },
4342
+ '^Internal encoding declaration .+ disagrees with the actual encoding of the document.*$': {
4343
+ quality: 1,
4344
+ what: 'Encoding declaration disagrees with the actual encoding of the page'
4113
4345
  }
4114
4346
  }
4115
4347
  }
@@ -4198,7 +4430,7 @@ exports.scorer = async report => {
4198
4430
  if (verdict && rule) {
4199
4431
  const {ruleID} = rule;
4200
4432
  if (ruleID) {
4201
- // Add 4 per failure, 1 per warning (cantTell).
4433
+ // Add 4 per failure, 1 per warning (cantTell).
4202
4434
  addDetail(which, ruleID, verdict === 'failed' ? 4 : 1);
4203
4435
  }
4204
4436
  }
@@ -4283,7 +4515,7 @@ exports.scorer = async report => {
4283
4515
  items.forEach(issue => {
4284
4516
  const {ruleId, level} = issue;
4285
4517
  if (ruleId && level) {
4286
- // Add 4 per violation, 1 per warning (recommendation).
4518
+ // Add 4 per violation, 1 per warning (recommendation).
4287
4519
  addDetail(which, ruleId, level === 'violation' ? 4 : 1);
4288
4520
  }
4289
4521
  });
@@ -4329,7 +4561,7 @@ exports.scorer = async report => {
4329
4561
  testIDs.forEach(testID => {
4330
4562
  const {count} = items[testID];
4331
4563
  if (count) {
4332
- // Add 4 per error, 3 per contrast error, 1 per warning (alert).
4564
+ // Add 4 per error, 3 per contrast error, 1 per warning (alert).
4333
4565
  addDetail(
4334
4566
  which, `${issueClass[0]}:${testID}`, count * classScores[issueClass]
4335
4567
  );