testilo 3.9.1 → 3.9.4

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 +425 -97
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "3.9.1",
3
+ "version": "3.9.4",
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,9 +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: .+: .+ 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.*$/,
75
+ /^Start tag .+ seen but an element of the same type was already open.*$/,
76
+ /^Bad start tag in .+$/,
77
+ /^End tag .+ violates nesting rules.*$/,
78
+ /^Stray end tag .+$/,
79
+ /^Element name .+ cannot be represented as XML 1\.0.*$/,
80
+ /^Attribute .+ is not serializable as XML 1\.0.*$/,
81
+ /^Attribute .+ not allowed on element meta at this point.*$/,
61
82
  /^Attribute .+ not allowed on element .+ at this point.*$/,
62
- /^Bad value .+ for attribute .+ on element meta”.*$/,
63
- /^CSS: “background-image”: .+ is not a “background-image” value.*$/
83
+ /^Bad value .+ for attribute .+ on element meta.*$/,
84
+ /^Bad value .+ for attribute .+ on element .+$/,
85
+ /^Bad value .+ for the attribute .+$/,
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 .+$/,
90
+ /^CSS: .+: Property .+ doesn't exist.*$/,
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.*$/
64
97
  ]
65
98
  };
66
99
  const groups = {
@@ -68,7 +101,7 @@ const groups = {
68
101
  weight: 0,
69
102
  packages: {
70
103
  nuVal: {
71
- '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.)': {
72
105
  quality: 0,
73
106
  what: 'Bug in nuVal'
74
107
  }
@@ -115,6 +148,12 @@ const groups = {
115
148
  quality: 1,
116
149
  what: 'Element id attribute value is not unique within the document'
117
150
  }
151
+ },
152
+ nuVal: {
153
+ '^Duplicate ID .+$|^The first occurrence of ID .* was here.*$': {
154
+ quality: 1,
155
+ what: 'Duplicate id'
156
+ }
118
157
  }
119
158
  }
120
159
  },
@@ -329,7 +368,7 @@ const groups = {
329
368
  }
330
369
  },
331
370
  nuVal: {
332
- '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.': {
333
372
  quality: 1,
334
373
  what: 'img element has no alt attribute'
335
374
  }
@@ -372,18 +411,40 @@ const groups = {
372
411
  weight: 4,
373
412
  packages: {
374
413
  nuVal: {
375
- 'Element img is missing required attribute src”.': {
414
+ 'Element img is missing required attribute src.': {
376
415
  quality: 1,
377
416
  what: 'img element has no src attribute'
378
417
  }
379
418
  }
380
419
  }
381
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
+ },
432
+ backgroundBad: {
433
+ weight: 4,
434
+ packages: {
435
+ nuVal: {
436
+ '^CSS: background: .+ is not a color value.*$': {
437
+ quality: 1,
438
+ what: 'CSS background color is misdefined'
439
+ }
440
+ }
441
+ }
442
+ },
382
443
  backgroundImageBad: {
383
444
  weight: 4,
384
445
  packages: {
385
446
  nuVal: {
386
- '^CSS: background-image”: .+ is not a background-image value.*$': {
447
+ '^CSS: background-image: .+ is not a background-image value.*$': {
387
448
  quality: 1,
388
449
  what: 'CSS background image is misdefined'
389
450
  }
@@ -452,7 +513,7 @@ const groups = {
452
513
  }
453
514
  },
454
515
  decorativeElementExposed: {
455
- weight: 1,
516
+ weight: 2,
456
517
  packages: {
457
518
  alfa: {
458
519
  r67: {
@@ -463,6 +524,12 @@ const groups = {
463
524
  quality: 1,
464
525
  what: 'Element marked as decorative is in the accessibility tree or has no none/presentation role'
465
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
+ }
466
533
  }
467
534
  }
468
535
  },
@@ -499,6 +566,12 @@ const groups = {
499
566
  what: 'Page detected as HTML, but has no lang attribute'
500
567
  }
501
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
+ },
502
575
  wave: {
503
576
  'e:language_missing': {
504
577
  quality: 1,
@@ -755,10 +828,6 @@ const groups = {
755
828
  }
756
829
  },
757
830
  wave: {
758
- 'a:label_orphaned': {
759
- quality: 1,
760
- what: 'Orphaned form label'
761
- },
762
831
  'a:link_internal_broken': {
763
832
  quality: 1,
764
833
  what: 'Broken same-page link'
@@ -766,13 +835,19 @@ const groups = {
766
835
  }
767
836
  }
768
837
  },
769
- labelForWrongRisk: {
770
- weight: 1,
838
+ labelForBad: {
839
+ weight: 3,
771
840
  packages: {
772
841
  htmlcs: {
773
842
  'w:AA.1_3_1.H44.NotFormControl': {
774
843
  quality: 1,
775
- 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'
776
851
  }
777
852
  }
778
853
  }
@@ -781,7 +856,7 @@ const groups = {
781
856
  weight: 1,
782
857
  packages: {
783
858
  nuVal: {
784
- '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.)': {
785
860
  quality: 1,
786
861
  what: 'aria-label attribute may be misused'
787
862
  }
@@ -813,6 +888,12 @@ const groups = {
813
888
  quality: 1,
814
889
  what: 'aria-controls attribute references an invalid or duplicate ID'
815
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
+ }
816
897
  }
817
898
  }
818
899
  },
@@ -868,9 +949,13 @@ const groups = {
868
949
  }
869
950
  },
870
951
  nuVal: {
871
- '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.': {
872
953
  quality: 1,
873
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'
874
959
  }
875
960
  },
876
961
  wave: {
@@ -952,6 +1037,12 @@ const groups = {
952
1037
  what: 'Hyperlink has no text description'
953
1038
  }
954
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
+ },
955
1046
  tenon: {
956
1047
  57: {
957
1048
  quality: 1,
@@ -1155,7 +1246,7 @@ const groups = {
1155
1246
  weight: 4,
1156
1247
  packages: {
1157
1248
  nuVal: {
1158
- 'Attribute alt not allowed on element button at this point.': {
1249
+ 'Attribute alt not allowed on element button at this point.': {
1159
1250
  quality: 1,
1160
1251
  what: 'button element has an alt attribute'
1161
1252
  }
@@ -1321,6 +1412,12 @@ const groups = {
1321
1412
  quality: 1,
1322
1413
  what: 'meta element in the head sets the viewport maximum-scale to less than 2'
1323
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
+ }
1324
1421
  }
1325
1422
  }
1326
1423
  },
@@ -1457,7 +1554,7 @@ const groups = {
1457
1554
  weight: 4,
1458
1555
  packages: {
1459
1556
  nuVal: {
1460
- '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.)': {
1461
1558
  quality: 1,
1462
1559
  what: 'title element is a child of the body element'
1463
1560
  }
@@ -1474,9 +1571,13 @@ const groups = {
1474
1571
  weight: 4,
1475
1572
  packages: {
1476
1573
  nuVal: {
1477
- '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.': {
1478
1575
  quality: 1,
1479
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'
1480
1581
  }
1481
1582
  }
1482
1583
  }
@@ -1485,52 +1586,56 @@ const groups = {
1485
1586
  weight: 3,
1486
1587
  packages: {
1487
1588
  nuVal: {
1488
- 'Attribute “name” not allowed on element meta at this point.': {
1589
+ '^Attribute .+ not allowed on element meta at this point.*$': {
1489
1590
  quality: 1,
1490
- what: 'name attribute is not allowed on a meta element here'
1591
+ what: 'Attribute is not allowed on a meta element here'
1491
1592
  },
1492
- 'Attribute “rel” not allowed on element “meta” at this point.': {
1593
+ '^Element meta is missing one or more of the following attributes: .+$': {
1493
1594
  quality: 1,
1494
- what: 'rel attribute is not allowed on a meta element here'
1595
+ what: 'meta element is missing a required attribute'
1495
1596
  },
1496
- 'Attribute “href” not allowed on element meta at this point.': {
1597
+ 'A document must not include more than one meta element with its name attribute set to the value description.': {
1497
1598
  quality: 1,
1498
- what: 'href attribute is not allowed on a meta element here'
1599
+ what: 'meta element with name="description" is not the only one'
1499
1600
  },
1500
- 'Element “meta” is missing one or more of the following attributes: “charset”, “content”, “http-equiv”, “itemprop”, “name”, “property”.': {
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.': {
1501
1602
  quality: 1,
1502
- what: 'meta element is missing a charset, content, http-equiv, itemprop, name, or property attribute'
1603
+ what: 'meta element with http-equiv="content-type" is incompatible with the meta element with a charset attribute'
1503
1604
  },
1504
- 'A document must not include more than one meta element with its “name” attribute set to the value “description”.': {
1605
+ 'A document must not include more than one meta element with a http-equiv attribute whose value is content-type.': {
1505
1606
  quality: 1,
1506
- what: 'meta element with name="description" is not the only one'
1607
+ what: 'Page has more than 1 meta element with http-equiv="content-type"'
1507
1608
  },
1508
- 'Attribute http-equiv not allowed on element “meta” at this point.': {
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.': {
1509
1610
  quality: 1,
1510
- what: 'http-equiv attribute is not allowed on a meta element here'
1611
+ what: 'meta element with http-equiv="X-UA-Compatible" has no content="IE=edge"'
1511
1612
  },
1512
- 'A “meta” element with an “http-equiv” attribute whose value is “X-UA-Compatible” must have a “content” attribute with the value “IE=edge”.': {
1613
+ 'A document must not include more than one meta element with a charset attribute.': {
1513
1614
  quality: 1,
1514
- what: 'meta element with http-equiv="X-UA-Compatible" has no content="IE=edge"'
1615
+ what: 'More than 1 meta element has a charset attribute'
1515
1616
  },
1516
- 'Element “meta” is missing one or more of the following attributes: “itemprop”, “property”.': {
1617
+ 'A charset attribute on a meta element found after the first 1024 bytes.': {
1517
1618
  quality: 1,
1518
- what: 'meta element is missing an itemprop or property attribute'
1619
+ what: 'charset attribute on a meta element appears after 1024 bytes'
1519
1620
  },
1520
- '^Bad value .+ for attribute .+ on element meta”.*$': {
1621
+ '^Bad value .+ for attribute .+ on element meta.*$': {
1521
1622
  quality: 1,
1522
1623
  what: 'attribute of a meta element has an invalid value'
1523
1624
  }
1524
1625
  }
1525
1626
  }
1526
1627
  },
1527
- scriptDeferBad: {
1628
+ scriptElementBad: {
1528
1629
  weight: 4,
1529
1630
  packages: {
1530
1631
  nuVal: {
1531
- '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.': {
1532
1633
  quality: 1,
1533
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'
1534
1639
  }
1535
1640
  }
1536
1641
  }
@@ -1539,7 +1644,7 @@ const groups = {
1539
1644
  weight: 4,
1540
1645
  packages: {
1541
1646
  nuVal: {
1542
- '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.': {
1543
1648
  quality: 1,
1544
1649
  what: 'Element has an itemtype attribute without an itemscope attribute'
1545
1650
  }
@@ -1657,9 +1762,17 @@ const groups = {
1657
1762
  }
1658
1763
  },
1659
1764
  nuVal: {
1660
- 'Bad value dialog for attribute role on element li”.': {
1765
+ 'Bad value dialog for attribute role on element li.': {
1661
1766
  quality: 1,
1662
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'
1663
1776
  }
1664
1777
  },
1665
1778
  testaro: {
@@ -1680,21 +1793,13 @@ const groups = {
1680
1793
  }
1681
1794
  },
1682
1795
  nuVal: {
1683
- 'The “banner” role is unnecessary for element “header”.': {
1684
- quality: 1,
1685
- what: 'banner role is redundant for a header element'
1686
- },
1687
- 'The “contentinfo” role is unnecessary for element “footer”.': {
1796
+ '^The .+ role is unnecessary for element .+$': {
1688
1797
  quality: 1,
1689
- what: 'contentinfo role is redundant for a footer element'
1798
+ what: 'explicit role is redundant for its element'
1690
1799
  },
1691
- 'The “main” role is unnecessary for element “main”.': {
1800
+ 'The textbox role is unnecessary for an input element that has no list attribute and whose type is text.': {
1692
1801
  quality: 1,
1693
- what: 'main role is redundant for a main element'
1694
- },
1695
- 'The “navigation” role is unnecessary for element “nav”.': {
1696
- quality: 1,
1697
- 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'
1698
1803
  }
1699
1804
  }
1700
1805
  }
@@ -1715,9 +1820,13 @@ const groups = {
1715
1820
  }
1716
1821
  },
1717
1822
  nuVal: {
1718
- 'Element a is missing required attribute aria-valuenow”.': {
1823
+ 'Element a is missing required attribute aria-valuenow.': {
1719
1824
  quality: 1,
1720
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'
1721
1830
  }
1722
1831
  }
1723
1832
  }
@@ -1855,6 +1964,20 @@ const groups = {
1855
1964
  quality: 1,
1856
1965
  what: 'ARIA property value is invalid'
1857
1966
  }
1967
+ },
1968
+ nuVal: {
1969
+ 'The aria-hidden attribute must not be specified on the noscript element.': {
1970
+ quality: 1,
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'
1980
+ }
1858
1981
  }
1859
1982
  }
1860
1983
  },
@@ -1866,6 +1989,12 @@ const groups = {
1866
1989
  quality: 1,
1867
1990
  what: 'ARIA attribute is used when there is a corresponding HTML attribute'
1868
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
+ }
1869
1998
  }
1870
1999
  }
1871
2000
  },
@@ -1898,19 +2027,25 @@ const groups = {
1898
2027
  axe: {
1899
2028
  'autocomplete-valid': {
1900
2029
  quality: 1,
1901
- what: 'Autocomplete attribute is used incorrectly'
2030
+ what: 'autocomplete attribute is used incorrectly'
1902
2031
  }
1903
2032
  },
1904
2033
  htmlcs: {
1905
2034
  'e:AA.1_3_5.H98': {
1906
2035
  quality: 1,
1907
- what: 'Autocomplete attribute and the input type are mismatched'
2036
+ what: 'autocomplete attribute and the input type are mismatched'
1908
2037
  }
1909
2038
  },
1910
2039
  ibm: {
1911
2040
  WCAG21_Input_Autocomplete: {
1912
2041
  quality: 1,
1913
- 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'
1914
2049
  }
1915
2050
  }
1916
2051
  }
@@ -2037,9 +2172,24 @@ const groups = {
2037
2172
  weight: 4,
2038
2173
  packages: {
2039
2174
  nuVal: {
2040
- '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.+$': {
2041
2176
  quality: 1,
2042
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'
2043
2193
  }
2044
2194
  }
2045
2195
  }
@@ -2071,6 +2221,12 @@ const groups = {
2071
2221
  what: 'Heading element provides no descriptive text'
2072
2222
  }
2073
2223
  },
2224
+ nuVal: {
2225
+ 'Empty heading.': {
2226
+ quality: 1,
2227
+ what: 'Empty heading'
2228
+ }
2229
+ },
2074
2230
  wave: {
2075
2231
  'e:heading_empty': {
2076
2232
  quality: 1,
@@ -2094,11 +2250,11 @@ const groups = {
2094
2250
  weight: 1,
2095
2251
  packages: {
2096
2252
  nuVal: {
2097
- 'The type attribute is unnecessary for JavaScript resources.': {
2253
+ 'The type attribute is unnecessary for JavaScript resources.': {
2098
2254
  quality: 1,
2099
2255
  what: 'type attribute is unnecessary for a JavaScript resource'
2100
2256
  },
2101
- '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.': {
2102
2258
  quality: 1,
2103
2259
  what: 'type attribute is unnecessary for a style element'
2104
2260
  }
@@ -2190,8 +2346,14 @@ const groups = {
2190
2346
  }
2191
2347
  },
2192
2348
  docType: {
2193
- weight: 1,
2349
+ weight: 3,
2194
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
+ },
2195
2357
  testaro: {
2196
2358
  docType: {
2197
2359
  quality: 1,
@@ -2234,7 +2396,7 @@ const groups = {
2234
2396
  }
2235
2397
  },
2236
2398
  nuVal: {
2237
- 'Element head is missing a required instance of child element title”.': {
2399
+ 'Element head is missing a required instance of child element title.': {
2238
2400
  quality: 1,
2239
2401
  what: 'head element has no child title element'
2240
2402
  }
@@ -2268,6 +2430,12 @@ const groups = {
2268
2430
  what: 'Heading level is incorrect'
2269
2431
  }
2270
2432
  },
2433
+ nuVal: {
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).': {
2435
+ quality: 1,
2436
+ what: 'Page contains more than 1 h1 element'
2437
+ }
2438
+ },
2271
2439
  tenon: {
2272
2440
  155: {
2273
2441
  quality: 1,
@@ -2333,11 +2501,26 @@ const groups = {
2333
2501
  }
2334
2502
  }
2335
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
+ },
2336
2515
  sectionHeadingless: {
2337
2516
  weight: 1,
2338
2517
  packages: {
2339
2518
  nuVal: {
2340
- '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.': {
2341
2524
  quality: 1,
2342
2525
  what: 'section has no heading'
2343
2526
  }
@@ -2481,6 +2664,12 @@ const groups = {
2481
2664
  quality: 1,
2482
2665
  what: 'List component with a group role has a non-listitem child'
2483
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
+ }
2484
2673
  }
2485
2674
  }
2486
2675
  },
@@ -2504,7 +2693,7 @@ const groups = {
2504
2693
  }
2505
2694
  },
2506
2695
  nuVal: {
2507
- '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.)': {
2508
2697
  quality: 1,
2509
2698
  what: 'li element is a child of a div element'
2510
2699
  }
@@ -2566,6 +2755,28 @@ const groups = {
2566
2755
  }
2567
2756
  }
2568
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
+ },
2569
2780
  selectFlatRisk: {
2570
2781
  weight: 1,
2571
2782
  packages: {
@@ -2932,6 +3143,20 @@ const groups = {
2932
3143
  what: 'Link contains an input, keygen, select, textarea, or button'
2933
3144
  }
2934
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
+ },
2935
3160
  testaro: {
2936
3161
  embAc: {
2937
3162
  quality: 1,
@@ -3460,9 +3685,9 @@ const groups = {
3460
3685
  weight: 2,
3461
3686
  packages: {
3462
3687
  nuVal: {
3463
- '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.*$': {
3464
3689
  quality: 1,
3465
- 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'
3466
3691
  }
3467
3692
  }
3468
3693
  }
@@ -3540,6 +3765,26 @@ const groups = {
3540
3765
  '^Attribute .+ not allowed on element .+ at this point.*$': {
3541
3766
  quality: 1,
3542
3767
  what: 'attribute not allowed on this element'
3768
+ },
3769
+ '^Bad value .+ for attribute .+ on element .+$': {
3770
+ quality: 1,
3771
+ what: 'attribute on this element has an invalid value'
3772
+ },
3773
+ '^Bad value .+ for the attribute .+$': {
3774
+ quality: 1,
3775
+ what: 'attribute has an invalid value'
3776
+ },
3777
+ '^Attribute .+ not allowed here.*$': {
3778
+ quality: 1,
3779
+ what: 'Attribute not allowed here'
3780
+ },
3781
+ '^Attribute .+ is not serializable as XML 1\\.0.*$': {
3782
+ quality: 1,
3783
+ what: 'Attribute is invalidly nonserializable'
3784
+ },
3785
+ '^Attribute .+ is only allowed when .+$': {
3786
+ quality: 1,
3787
+ what: 'Attribute is invalid here'
3543
3788
  }
3544
3789
  }
3545
3790
  }
@@ -3658,7 +3903,7 @@ const groups = {
3658
3903
  weight: 4,
3659
3904
  packages: {
3660
3905
  nuVal: {
3661
- '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.)': {
3662
3907
  quality: 1,
3663
3908
  what: 'div element has a button element as its parent'
3664
3909
  }
@@ -3669,7 +3914,7 @@ const groups = {
3669
3914
  weight: 4,
3670
3915
  packages: {
3671
3916
  nuVal: {
3672
- '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.)': {
3673
3918
  quality: 1,
3674
3919
  what: 'p element has a strong element as its parent'
3675
3920
  }
@@ -3680,19 +3925,19 @@ const groups = {
3680
3925
  weight: 4,
3681
3926
  packages: {
3682
3927
  nuVal: {
3683
- '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.)': {
3684
3929
  quality: 1,
3685
3930
  what: 'style element not allowed as a child of the body element'
3686
3931
  },
3687
- '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.)': {
3688
3933
  quality: 1,
3689
3934
  what: 'style element not allowed as a child of this div element'
3690
3935
  },
3691
- '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.)': {
3692
3937
  quality: 1,
3693
3938
  what: 'style element not allowed as a child of this main element'
3694
3939
  },
3695
- '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.)': {
3696
3941
  quality: 1,
3697
3942
  what: 'style element not allowed as a child of this footer element'
3698
3943
  }
@@ -3738,6 +3983,17 @@ const groups = {
3738
3983
  }
3739
3984
  }
3740
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
+ },
3741
3997
  tabIndexMissing: {
3742
3998
  weight: 4,
3743
3999
  packages: {
@@ -3958,19 +4214,27 @@ const groups = {
3958
4214
  }
3959
4215
  },
3960
4216
  nuVal: {
3961
- 'The “charset” attribute on the “script” element is obsolete.': {
4217
+ 'The center element is obsolete. Use CSS instead.': {
4218
+ quality: 1,
4219
+ what: 'center element is obsolete'
4220
+ },
4221
+ 'The font element is obsolete. Use CSS instead.': {
4222
+ quality: 1,
4223
+ what: 'font element is obsolete'
4224
+ },
4225
+ '^The .+ attribute on the .+ element is obsolete.+$': {
3962
4226
  quality: 1,
3963
- what: 'charset attribute is obsolete on a script element'
4227
+ what: 'attribute is obsolete on its element'
3964
4228
  },
3965
- '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.)': {
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.)': {
3966
4230
  quality: 1,
3967
4231
  what: 'charset attribute has a value other than utf-8 and is unnecessary'
3968
4232
  },
3969
- '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.': {
3970
4234
  quality: 1,
3971
- what: 'frameborder attribute is obsolete'
4235
+ what: 'language declaration in a meta element is obsolete'
3972
4236
  },
3973
- '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.': {
3974
4238
  quality: 1,
3975
4239
  what: 'name attribute is obsolete'
3976
4240
  }
@@ -3987,33 +4251,97 @@ const groups = {
3987
4251
  weight: 3,
3988
4252
  packages: {
3989
4253
  nuVal: {
3990
- 'CSS: “-webkit-box-flex”: Parse Error.': {
4254
+ 'CSS: font-size: One operand must be a number.': {
4255
+ quality: 1,
4256
+ what: 'CSS font-size property has no numeric operand'
4257
+ },
4258
+ '^CSS: .+: Parse Error.*$': {
4259
+ quality: 1,
4260
+ what: 'Invalid CSS'
4261
+ },
4262
+ '^CSS: .+: .+ is not a .+ value.*$': {
4263
+ quality: 1,
4264
+ what: 'Invalid value in CSS'
4265
+ },
4266
+ '^CSS: .+: Property .+ doesn\'t exist.*$': {
4267
+ quality: 1,
4268
+ what: 'Invalid property in CSS'
4269
+ },
4270
+ '^CSS: .+: only 0 can be a length. You must put a unit after your number.*$': {
4271
+ quality: 1,
4272
+ what: 'Length in CSS is nonzero but has no unit'
4273
+ },
4274
+ '^CSS: .+: only 0 can be a unit. You must put a unit after your number.*$': {
4275
+ quality: 1,
4276
+ what: 'Number in CSS is nonzero but has no unit'
4277
+ },
4278
+ 'CSS: Parse Error.': {
4279
+ quality: 1,
4280
+ what: 'Invalid CSS'
4281
+ },
4282
+ '^CSS: .+: Too many values or values are not recognized.+$': {
4283
+ quality: 1,
4284
+ what: 'Invalid CSS value or too many values'
4285
+ },
4286
+ '^CSS: .+: Invalid type: .+$': {
4287
+ quality: 1,
4288
+ what: 'Invalid type of CSS value'
4289
+ },
4290
+ '^CSS: .+: The types are incompatible.*$': {
4291
+ quality: 1,
4292
+ what: 'Incompatible types of CSS values'
4293
+ },
4294
+ '^CSS: .+: Unknown dimension.*$': {
4295
+ quality: 1,
4296
+ what: 'Unknown CSS dimension'
4297
+ },
4298
+ '^The aria-hidden attribute must not be specified on the .+ element.*$': {
4299
+ quality: 1,
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'
4309
+ },
4310
+ '^Start tag .+ seen but an element of the same type was already open.*$': {
4311
+ quality: 1,
4312
+ what: 'Element is invalidly a descendant of another such element'
4313
+ },
4314
+ '^Bad start tag in .+$': {
4315
+ quality: 1,
4316
+ what: 'Invalid start tag'
4317
+ },
4318
+ '^End tag .+ violates nesting rules.*$': {
3991
4319
  quality: 1,
3992
- what: 'Invalid -webkit-box-flex in CSS'
4320
+ what: 'End tag violates nesting rules'
3993
4321
  },
3994
- 'CSS: “-webkit-flex”: Parse Error.': {
4322
+ '^Element .+ not allowed as child of element .+ in this context.*$': {
3995
4323
  quality: 1,
3996
- what: 'Invalid -webkit-flex in CSS'
4324
+ what: 'Element not allowed as a child of its parent here'
3997
4325
  },
3998
- 'CSS: “-ms-flex”: Parse Error.': {
4326
+ 'Saw <!-- within a comment. Probable cause: Nested comment (not allowed).': {
3999
4327
  quality: 1,
4000
- what: 'Invalid -ms-flex in CSS'
4328
+ what: 'Comment is nested within a comment'
4001
4329
  },
4002
- 'CSS: “-moz-box-flex”: Parse Error.': {
4330
+ 'The document is not mappable to XML 1.0 due to two consecutive hyphens in a comment.': {
4003
4331
  quality: 1,
4004
- what: 'Invalid -moz-box-flex in CSS'
4332
+ what: 'Comment contains --'
4005
4333
  },
4006
- 'CSS: “flex”: Parse Error.': {
4334
+ '^Element name .+ cannot be represented as XML 1\\.0.*$': {
4007
4335
  quality: 1,
4008
- what: 'Invalid flex in CSS'
4336
+ what: 'Invalid element name'
4009
4337
  },
4010
- 'Stray end tag “head”.': {
4338
+ '^Forbidden code point U+.+$': {
4011
4339
  quality: 1,
4012
- what: 'Invalid closing head tag'
4340
+ what: 'Invalid Unicode code point'
4013
4341
  },
4014
- 'Start tag “body” seen but an element of the same type was already open.': {
4342
+ '^Internal encoding declaration .+ disagrees with the actual encoding of the document.*$': {
4015
4343
  quality: 1,
4016
- what: 'body element is a descendant of a body element'
4344
+ what: 'Encoding declaration disagrees with the actual encoding of the page'
4017
4345
  }
4018
4346
  }
4019
4347
  }
@@ -4102,7 +4430,7 @@ exports.scorer = async report => {
4102
4430
  if (verdict && rule) {
4103
4431
  const {ruleID} = rule;
4104
4432
  if (ruleID) {
4105
- // Add 4 per failure, 1 per warning (cantTell).
4433
+ // Add 4 per failure, 1 per warning (cantTell).
4106
4434
  addDetail(which, ruleID, verdict === 'failed' ? 4 : 1);
4107
4435
  }
4108
4436
  }
@@ -4187,7 +4515,7 @@ exports.scorer = async report => {
4187
4515
  items.forEach(issue => {
4188
4516
  const {ruleId, level} = issue;
4189
4517
  if (ruleId && level) {
4190
- // Add 4 per violation, 1 per warning (recommendation).
4518
+ // Add 4 per violation, 1 per warning (recommendation).
4191
4519
  addDetail(which, ruleId, level === 'violation' ? 4 : 1);
4192
4520
  }
4193
4521
  });
@@ -4233,7 +4561,7 @@ exports.scorer = async report => {
4233
4561
  testIDs.forEach(testID => {
4234
4562
  const {count} = items[testID];
4235
4563
  if (count) {
4236
- // 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).
4237
4565
  addDetail(
4238
4566
  which, `${issueClass[0]}:${testID}`, count * classScores[issueClass]
4239
4567
  );