testilo 3.9.0 → 3.9.3

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 +225 -87
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "3.9.0",
3
+ "version": "3.9.3",
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,8 +58,25 @@ 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
+ /^Bad value for attribute id on element .+: An ID must not be the empty string.+$/,
66
+ /^Duplicate ID .+$|^The first occurrence of ID .* was here.*$/,
67
+ /^Start tag .+ seen but an element of the same type was already open.*$/,
68
+ /^End tag .+ violates nesting rules.*$/,
69
+ /^Attribute .+ is not serializable as XML 1\.0.*$/,
70
+ /^Attribute .+ not allowed on element meta at this point.*$/,
61
71
  /^Attribute .+ not allowed on element .+ at this point.*$/,
62
- /^CSS: “background-image”: .+ is not a “background-image” value.*$/
72
+ /^Bad value .+ for attribute .+ on element meta.*$/,
73
+ /^Bad value .+ for attribute .+ on element .+$/,
74
+ /^Bad value .+ for the attribute .+$/,
75
+ /^Attribute .+ not allowed here.*$/,
76
+ /^The .+ role is unnecessary for element .+$/,
77
+ /^CSS: .+: Property .+ doesn't exist.*$/,
78
+ /^CSS: .+: only 0 can be a length. You must put a unit after your number.*$/,
79
+ /^Element .+ not allowed as child of element .+ in this context.*$/
63
80
  ]
64
81
  };
65
82
  const groups = {
@@ -67,7 +84,7 @@ const groups = {
67
84
  weight: 0,
68
85
  packages: {
69
86
  nuVal: {
70
- 'Element mediaelementwrapper not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
87
+ 'Element mediaelementwrapper not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
71
88
  quality: 0,
72
89
  what: 'Bug in nuVal'
73
90
  }
@@ -114,6 +131,12 @@ const groups = {
114
131
  quality: 1,
115
132
  what: 'Element id attribute value is not unique within the document'
116
133
  }
134
+ },
135
+ nuVal: {
136
+ '^Duplicate ID .+$|^The first occurrence of ID .* was here.*$': {
137
+ quality: 1,
138
+ what: 'Duplicate id'
139
+ }
117
140
  }
118
141
  }
119
142
  },
@@ -328,7 +351,7 @@ const groups = {
328
351
  }
329
352
  },
330
353
  nuVal: {
331
- 'An img element must have an alt attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.': {
354
+ 'An img element must have an alt attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.': {
332
355
  quality: 1,
333
356
  what: 'img element has no alt attribute'
334
357
  }
@@ -371,18 +394,29 @@ const groups = {
371
394
  weight: 4,
372
395
  packages: {
373
396
  nuVal: {
374
- 'Element img is missing required attribute src”.': {
397
+ 'Element img is missing required attribute src.': {
375
398
  quality: 1,
376
399
  what: 'img element has no src attribute'
377
400
  }
378
401
  }
379
402
  }
380
403
  },
404
+ backgroundBad: {
405
+ weight: 4,
406
+ packages: {
407
+ nuVal: {
408
+ '^CSS: background: .+ is not a color value.*$': {
409
+ quality: 1,
410
+ what: 'CSS background color is misdefined'
411
+ }
412
+ }
413
+ }
414
+ },
381
415
  backgroundImageBad: {
382
416
  weight: 4,
383
417
  packages: {
384
418
  nuVal: {
385
- '^CSS: background-image”: .+ is not a background-image value.*$': {
419
+ '^CSS: background-image: .+ is not a background-image value.*$': {
386
420
  quality: 1,
387
421
  what: 'CSS background image is misdefined'
388
422
  }
@@ -780,7 +814,7 @@ const groups = {
780
814
  weight: 1,
781
815
  packages: {
782
816
  nuVal: {
783
- 'Possible misuse of aria-label”. (If you disagree with this warning, file an issue report or send e-mail to www-validator@w3.org.)': {
817
+ 'Possible misuse of aria-label. (If you disagree with this warning, file an issue report or send e-mail to www-validator@w3.org.)': {
784
818
  quality: 1,
785
819
  what: 'aria-label attribute may be misused'
786
820
  }
@@ -867,7 +901,7 @@ const groups = {
867
901
  }
868
902
  },
869
903
  nuVal: {
870
- 'The aria-labelledby attribute must point to an element in the same document.': {
904
+ 'The aria-labelledby attribute must point to an element in the same document.': {
871
905
  quality: 1,
872
906
  what: 'aria-labelledby attribute references an element not in the document'
873
907
  }
@@ -1154,7 +1188,7 @@ const groups = {
1154
1188
  weight: 4,
1155
1189
  packages: {
1156
1190
  nuVal: {
1157
- 'Attribute alt not allowed on element button at this point.': {
1191
+ 'Attribute alt not allowed on element button at this point.': {
1158
1192
  quality: 1,
1159
1193
  what: 'button element has an alt attribute'
1160
1194
  }
@@ -1456,7 +1490,7 @@ const groups = {
1456
1490
  weight: 4,
1457
1491
  packages: {
1458
1492
  nuVal: {
1459
- 'Element title not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
1493
+ 'Element title not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
1460
1494
  quality: 1,
1461
1495
  what: 'title element is a child of the body element'
1462
1496
  }
@@ -1473,7 +1507,7 @@ const groups = {
1473
1507
  weight: 4,
1474
1508
  packages: {
1475
1509
  nuVal: {
1476
- '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”.': {
1510
+ '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.': {
1477
1511
  quality: 1,
1478
1512
  what: 'link element with a body ancestor has no itemprop or valid rel attribute'
1479
1513
  }
@@ -1484,37 +1518,33 @@ const groups = {
1484
1518
  weight: 3,
1485
1519
  packages: {
1486
1520
  nuVal: {
1487
- 'Attribute “name” not allowed on element meta at this point.': {
1521
+ '^Attribute .+ not allowed on element meta at this point.*$': {
1488
1522
  quality: 1,
1489
- what: 'name attribute is not allowed on a meta element here'
1523
+ what: 'Attribute is not allowed on a meta element here'
1490
1524
  },
1491
- 'Attribute “rel” not allowed on element “meta” at this point.': {
1492
- quality: 1,
1493
- what: 'rel attribute is not allowed on a meta element here'
1494
- },
1495
- 'Attribute “href” not allowed on element “meta” at this point.': {
1496
- quality: 1,
1497
- what: 'href attribute is not allowed on a meta element here'
1498
- },
1499
- 'Element “meta” is missing one or more of the following attributes: “charset”, “content”, “http-equiv”, “itemprop”, “name”, “property”.': {
1525
+ 'Element meta is missing one or more of the following attributes: charset, content, http-equiv, itemprop, name, property.': {
1500
1526
  quality: 1,
1501
1527
  what: 'meta element is missing a charset, content, http-equiv, itemprop, name, or property attribute'
1502
1528
  },
1503
- 'A document must not include more than one meta element with its name attribute set to the value description”.': {
1529
+ 'A document must not include more than one meta element with its name attribute set to the value description.': {
1504
1530
  quality: 1,
1505
1531
  what: 'meta element with name="description" is not the only one'
1506
1532
  },
1507
- 'Attribute http-equiv not allowed on element “meta” at this point.': {
1508
- quality: 1,
1509
- what: 'http-equiv attribute is not allowed on a meta element here'
1510
- },
1511
- 'A “meta” element with an “http-equiv” attribute whose value is “X-UA-Compatible” must have a “content” attribute with the value “IE=edge”.': {
1533
+ 'A meta element with an http-equiv attribute whose value is X-UA-Compatible must have a content attribute with the value IE=edge.': {
1512
1534
  quality: 1,
1513
1535
  what: 'meta element with http-equiv="X-UA-Compatible" has no content="IE=edge"'
1514
1536
  },
1515
- 'Element meta is missing one or more of the following attributes: itemprop”, property”.': {
1537
+ 'Element meta is missing one or more of the following attributes: itemprop, property.': {
1516
1538
  quality: 1,
1517
1539
  what: 'meta element is missing an itemprop or property attribute'
1540
+ },
1541
+ 'A charset attribute on a meta element found after the first 1024 bytes.': {
1542
+ quality: 1,
1543
+ what: 'charset attribute on a meta element appears after 1024 bytes'
1544
+ },
1545
+ '^Bad value .+ for attribute .+ on element meta.*$': {
1546
+ quality: 1,
1547
+ what: 'attribute of a meta element has an invalid value'
1518
1548
  }
1519
1549
  }
1520
1550
  }
@@ -1523,7 +1553,7 @@ const groups = {
1523
1553
  weight: 4,
1524
1554
  packages: {
1525
1555
  nuVal: {
1526
- 'Element script must not have attribute defer unless attribute src is also specified.': {
1556
+ 'Element script must not have attribute defer unless attribute src is also specified.': {
1527
1557
  quality: 1,
1528
1558
  what: 'script element has a defer attribute without a src attribute'
1529
1559
  }
@@ -1534,7 +1564,7 @@ const groups = {
1534
1564
  weight: 4,
1535
1565
  packages: {
1536
1566
  nuVal: {
1537
- 'The itemtype attribute must not be specified on elements that do not have an itemscope attribute specified.': {
1567
+ 'The itemtype attribute must not be specified on elements that do not have an itemscope attribute specified.': {
1538
1568
  quality: 1,
1539
1569
  what: 'Element has an itemtype attribute without an itemscope attribute'
1540
1570
  }
@@ -1652,7 +1682,7 @@ const groups = {
1652
1682
  }
1653
1683
  },
1654
1684
  nuVal: {
1655
- 'Bad value dialog for attribute role on element li”.': {
1685
+ 'Bad value dialog for attribute role on element li.': {
1656
1686
  quality: 1,
1657
1687
  what: 'dialog role is not valid for an li element'
1658
1688
  }
@@ -1675,21 +1705,9 @@ const groups = {
1675
1705
  }
1676
1706
  },
1677
1707
  nuVal: {
1678
- 'The “banner” role is unnecessary for element “header”.': {
1679
- quality: 1,
1680
- what: 'banner role is redundant for a header element'
1681
- },
1682
- 'The “contentinfo” role is unnecessary for element “footer”.': {
1683
- quality: 1,
1684
- what: 'contentinfo role is redundant for a footer element'
1685
- },
1686
- 'The “main” role is unnecessary for element “main”.': {
1687
- quality: 1,
1688
- what: 'main role is redundant for a main element'
1689
- },
1690
- 'The “navigation” role is unnecessary for element “nav”.': {
1708
+ '^The .+ role is unnecessary for element .+$': {
1691
1709
  quality: 1,
1692
- what: 'navigation role is redundant for a nav element'
1710
+ what: 'explicit role is redundant for its element'
1693
1711
  }
1694
1712
  }
1695
1713
  }
@@ -1710,7 +1728,7 @@ const groups = {
1710
1728
  }
1711
1729
  },
1712
1730
  nuVal: {
1713
- 'Element a is missing required attribute aria-valuenow”.': {
1731
+ 'Element a is missing required attribute aria-valuenow.': {
1714
1732
  quality: 1,
1715
1733
  what: 'a element has no aria-valuenow attribute'
1716
1734
  }
@@ -1850,6 +1868,12 @@ const groups = {
1850
1868
  quality: 1,
1851
1869
  what: 'ARIA property value is invalid'
1852
1870
  }
1871
+ },
1872
+ nuVal: {
1873
+ 'The aria-hidden attribute must not be specified on the noscript element.': {
1874
+ quality: 1,
1875
+ what: 'noscript element has an aria-hidden attribute'
1876
+ }
1853
1877
  }
1854
1878
  }
1855
1879
  },
@@ -2032,7 +2056,7 @@ const groups = {
2032
2056
  weight: 4,
2033
2057
  packages: {
2034
2058
  nuVal: {
2035
- 'Bad value “” for attribute id on element “a”: An ID must not be the empty string.': {
2059
+ '^Bad value for attribute id on element .+: An ID must not be the empty string.+$': {
2036
2060
  quality: 1,
2037
2061
  what: 'id attribute has an empty value'
2038
2062
  }
@@ -2066,6 +2090,12 @@ const groups = {
2066
2090
  what: 'Heading element provides no descriptive text'
2067
2091
  }
2068
2092
  },
2093
+ nuVal: {
2094
+ 'Empty heading.': {
2095
+ quality: 1,
2096
+ what: 'Empty heading'
2097
+ }
2098
+ },
2069
2099
  wave: {
2070
2100
  'e:heading_empty': {
2071
2101
  quality: 1,
@@ -2089,11 +2119,11 @@ const groups = {
2089
2119
  weight: 1,
2090
2120
  packages: {
2091
2121
  nuVal: {
2092
- 'The type attribute is unnecessary for JavaScript resources.': {
2122
+ 'The type attribute is unnecessary for JavaScript resources.': {
2093
2123
  quality: 1,
2094
2124
  what: 'type attribute is unnecessary for a JavaScript resource'
2095
2125
  },
2096
- 'The type attribute for the style element is not needed and should be omitted.': {
2126
+ 'The type attribute for the style element is not needed and should be omitted.': {
2097
2127
  quality: 1,
2098
2128
  what: 'type attribute is unnecessary for a style element'
2099
2129
  }
@@ -2185,8 +2215,14 @@ const groups = {
2185
2215
  }
2186
2216
  },
2187
2217
  docType: {
2188
- weight: 1,
2218
+ weight: 3,
2189
2219
  packages: {
2220
+ nuVal: {
2221
+ 'Start tag seen without seeing a doctype first. Expected <!DOCTYPE html>.': {
2222
+ quality: 1,
2223
+ what: 'Page does not start with <!DOCTYPE html>'
2224
+ }
2225
+ },
2190
2226
  testaro: {
2191
2227
  docType: {
2192
2228
  quality: 1,
@@ -2229,7 +2265,7 @@ const groups = {
2229
2265
  }
2230
2266
  },
2231
2267
  nuVal: {
2232
- 'Element head is missing a required instance of child element title”.': {
2268
+ 'Element head is missing a required instance of child element title.': {
2233
2269
  quality: 1,
2234
2270
  what: 'head element has no child title element'
2235
2271
  }
@@ -2263,6 +2299,12 @@ const groups = {
2263
2299
  what: 'Heading level is incorrect'
2264
2300
  }
2265
2301
  },
2302
+ nuVal: {
2303
+ '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).': {
2304
+ quality: 1,
2305
+ what: 'Page contains more than 1 h1 element'
2306
+ }
2307
+ },
2266
2308
  tenon: {
2267
2309
  155: {
2268
2310
  quality: 1,
@@ -2328,11 +2370,26 @@ const groups = {
2328
2370
  }
2329
2371
  }
2330
2372
  },
2373
+ articleHeadingless: {
2374
+ weight: 1,
2375
+ packages: {
2376
+ nuVal: {
2377
+ 'Article lacks heading. Consider using h2-h6 elements to add identifying headings to all articles.': {
2378
+ quality: 1,
2379
+ what: 'article has no heading'
2380
+ }
2381
+ }
2382
+ }
2383
+ },
2331
2384
  sectionHeadingless: {
2332
2385
  weight: 1,
2333
2386
  packages: {
2334
2387
  nuVal: {
2335
- 'Section lacks heading. Consider using h2”-“h6 elements to add identifying headings to all sections.': {
2388
+ 'Section lacks heading. Consider using h2-h6 elements to add identifying headings to all sections.': {
2389
+ quality: 1,
2390
+ what: 'section has no heading'
2391
+ },
2392
+ '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.': {
2336
2393
  quality: 1,
2337
2394
  what: 'section has no heading'
2338
2395
  }
@@ -2499,7 +2556,7 @@ const groups = {
2499
2556
  }
2500
2557
  },
2501
2558
  nuVal: {
2502
- 'Element li not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
2559
+ 'Element li not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
2503
2560
  quality: 1,
2504
2561
  what: 'li element is a child of a div element'
2505
2562
  }
@@ -3455,7 +3512,7 @@ const groups = {
3455
3512
  weight: 2,
3456
3513
  packages: {
3457
3514
  nuVal: {
3458
- '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.': {
3515
+ '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.': {
3459
3516
  quality: 1,
3460
3517
  what: 'iframe element has vulnerable sandbox="allow-scripts allow-same-origin"'
3461
3518
  }
@@ -3535,6 +3592,22 @@ const groups = {
3535
3592
  '^Attribute .+ not allowed on element .+ at this point.*$': {
3536
3593
  quality: 1,
3537
3594
  what: 'attribute not allowed on this element'
3595
+ },
3596
+ '^Bad value .+ for attribute .+ on element .+$': {
3597
+ quality: 1,
3598
+ what: 'attribute on this element has an invalid value'
3599
+ },
3600
+ '^Bad value .+ for the attribute .+$': {
3601
+ quality: 1,
3602
+ what: 'attribute has an invalid value'
3603
+ },
3604
+ '^Attribute .+ not allowed here.*$': {
3605
+ quality: 1,
3606
+ what: 'Attribute not allowed here'
3607
+ },
3608
+ '^Attribute .+ is not serializable as XML 1\\.0.*$': {
3609
+ quality: 1,
3610
+ what: 'Attribute is invalidly nonserializable'
3538
3611
  }
3539
3612
  }
3540
3613
  }
@@ -3653,7 +3726,7 @@ const groups = {
3653
3726
  weight: 4,
3654
3727
  packages: {
3655
3728
  nuVal: {
3656
- 'Element div not allowed as child of element button in this context. (Suppressing further errors from this subtree.)': {
3729
+ 'Element div not allowed as child of element button in this context. (Suppressing further errors from this subtree.)': {
3657
3730
  quality: 1,
3658
3731
  what: 'div element has a button element as its parent'
3659
3732
  }
@@ -3664,7 +3737,7 @@ const groups = {
3664
3737
  weight: 4,
3665
3738
  packages: {
3666
3739
  nuVal: {
3667
- 'Element p not allowed as child of element strong in this context. (Suppressing further errors from this subtree.)': {
3740
+ 'Element p not allowed as child of element strong in this context. (Suppressing further errors from this subtree.)': {
3668
3741
  quality: 1,
3669
3742
  what: 'p element has a strong element as its parent'
3670
3743
  }
@@ -3675,19 +3748,19 @@ const groups = {
3675
3748
  weight: 4,
3676
3749
  packages: {
3677
3750
  nuVal: {
3678
- 'Element style not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
3751
+ 'Element style not allowed as child of element body in this context. (Suppressing further errors from this subtree.)': {
3679
3752
  quality: 1,
3680
3753
  what: 'style element not allowed as a child of the body element'
3681
3754
  },
3682
- 'Element style not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
3755
+ 'Element style not allowed as child of element div in this context. (Suppressing further errors from this subtree.)': {
3683
3756
  quality: 1,
3684
3757
  what: 'style element not allowed as a child of this div element'
3685
3758
  },
3686
- 'Element style not allowed as child of element main in this context. (Suppressing further errors from this subtree.)': {
3759
+ 'Element style not allowed as child of element main in this context. (Suppressing further errors from this subtree.)': {
3687
3760
  quality: 1,
3688
3761
  what: 'style element not allowed as a child of this main element'
3689
3762
  },
3690
- 'Element style not allowed as child of element footer in this context. (Suppressing further errors from this subtree.)': {
3763
+ 'Element style not allowed as child of element footer in this context. (Suppressing further errors from this subtree.)': {
3691
3764
  quality: 1,
3692
3765
  what: 'style element not allowed as a child of this footer element'
3693
3766
  }
@@ -3953,21 +4026,41 @@ const groups = {
3953
4026
  }
3954
4027
  },
3955
4028
  nuVal: {
3956
- 'The charset attribute on the script element is obsolete.': {
4029
+ 'The charset attribute on the script element is obsolete.': {
3957
4030
  quality: 1,
3958
4031
  what: 'charset attribute is obsolete on a script element'
3959
4032
  },
3960
- '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.)': {
4033
+ '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.)': {
3961
4034
  quality: 1,
3962
4035
  what: 'charset attribute has a value other than utf-8 and is unnecessary'
3963
4036
  },
3964
- 'The “frameborder” attribute on the “iframe” element is obsolete. Use CSS instead.': {
4037
+ 'The language attribute on the script element is obsolete. You can safely omit it.': {
4038
+ quality: 1,
4039
+ what: 'language attribute is obsolete on a script element'
4040
+ },
4041
+ 'The language attribute on the script element is obsolete. Use the type attribute instead.': {
4042
+ quality: 1,
4043
+ what: 'language attribute is obsolete on a script element'
4044
+ },
4045
+ 'Using the meta element to specify the document-wide default language is obsolete. Consider specifying the language on the root element instead.': {
4046
+ quality: 1,
4047
+ what: 'language declaration in a meta element is obsolete'
4048
+ },
4049
+ 'The frameborder attribute on the iframe element is obsolete. Use CSS instead.': {
3965
4050
  quality: 1,
3966
4051
  what: 'frameborder attribute is obsolete'
3967
4052
  },
3968
- 'The name attribute is obsolete. Consider putting an id attribute on the nearest container instead.': {
4053
+ 'The name attribute is obsolete. Consider putting an id attribute on the nearest container instead.': {
3969
4054
  quality: 1,
3970
4055
  what: 'name attribute is obsolete'
4056
+ },
4057
+ 'The allowtransparency attribute on the iframe element is obsolete. Use CSS instead.': {
4058
+ quality: 1,
4059
+ what: 'allowtransparency attribute on an iframe element is obsolete'
4060
+ },
4061
+ 'The scrolling attribute on the iframe element is obsolete. Use CSS instead.': {
4062
+ quality: 1,
4063
+ what: 'scrolling attribute on an iframe element is obsolete'
3971
4064
  }
3972
4065
  },
3973
4066
  wave: {
@@ -3982,33 +4075,61 @@ const groups = {
3982
4075
  weight: 3,
3983
4076
  packages: {
3984
4077
  nuVal: {
3985
- 'CSS: “-webkit-box-flex”: Parse Error.': {
4078
+ 'CSS: -webkit-box-flex: Parse Error.': {
3986
4079
  quality: 1,
3987
4080
  what: 'Invalid -webkit-box-flex in CSS'
3988
4081
  },
3989
- 'CSS: “-webkit-flex”: Parse Error.': {
4082
+ 'CSS: -webkit-flex: Parse Error.': {
3990
4083
  quality: 1,
3991
4084
  what: 'Invalid -webkit-flex in CSS'
3992
4085
  },
3993
- 'CSS: “-ms-flex”: Parse Error.': {
4086
+ 'CSS: -ms-flex: Parse Error.': {
3994
4087
  quality: 1,
3995
4088
  what: 'Invalid -ms-flex in CSS'
3996
4089
  },
3997
- 'CSS: “-moz-box-flex”: Parse Error.': {
4090
+ 'CSS: -moz-box-flex: Parse Error.': {
3998
4091
  quality: 1,
3999
4092
  what: 'Invalid -moz-box-flex in CSS'
4000
4093
  },
4001
- 'CSS: flex”: Parse Error.': {
4094
+ 'CSS: flex: Parse Error.': {
4002
4095
  quality: 1,
4003
4096
  what: 'Invalid flex in CSS'
4004
4097
  },
4005
- 'Stray end tag “head”.': {
4098
+ '^CSS: cursor: .+ is not a cursor value.*$': {
4099
+ quality: 1,
4100
+ what: 'Invalid cursor in CSS'
4101
+ },
4102
+ '^CSS: transform: .+ is not a transform value.*$': {
4103
+ quality: 1,
4104
+ what: 'Invalid transform in CSS'
4105
+ },
4106
+ '^CSS: .+: Property .+ doesn\'t exist.*$': {
4107
+ quality: 1,
4108
+ what: 'Invalid property in CSS'
4109
+ },
4110
+ '^CSS: .+: only 0 can be a length. You must put a unit after your number.*$': {
4111
+ quality: 1,
4112
+ what: 'Length in CSS is nonzero but has no unit'
4113
+ },
4114
+ 'CSS: Parse Error.': {
4115
+ quality: 1,
4116
+ what: 'Invalid CSS'
4117
+ },
4118
+ 'Stray end tag head.': {
4006
4119
  quality: 1,
4007
4120
  what: 'Invalid closing head tag'
4008
4121
  },
4009
- 'Start tag “body” seen but an element of the same type was already open.': {
4122
+ '^Start tag .+ seen but an element of the same type was already open.*$': {
4123
+ quality: 1,
4124
+ what: 'Element is invalidly a descendant of another such element'
4125
+ },
4126
+ '^End tag .+ violates nesting rules.*$': {
4127
+ quality: 1,
4128
+ what: 'End tag violates nesting rules'
4129
+ },
4130
+ '^Element .+ not allowed as child of element .+ in this context.*$': {
4010
4131
  quality: 1,
4011
- what: 'body element is a descendant of a body element'
4132
+ what: 'Element not allowed as a child of its parent here'
4012
4133
  }
4013
4134
  }
4014
4135
  }
@@ -4024,6 +4145,17 @@ const groups = {
4024
4145
  }
4025
4146
  }
4026
4147
  },
4148
+ fatalError: {
4149
+ weight: 50,
4150
+ packages: {
4151
+ nuVal: {
4152
+ 'Cannot recover after last error. Any further errors will be ignored.': {
4153
+ quality: 1,
4154
+ what: 'Testing was interrupted by a fatal error'
4155
+ }
4156
+ }
4157
+ }
4158
+ }
4027
4159
  };
4028
4160
 
4029
4161
  // VARIABLES
@@ -4086,7 +4218,7 @@ exports.scorer = async report => {
4086
4218
  if (verdict && rule) {
4087
4219
  const {ruleID} = rule;
4088
4220
  if (ruleID) {
4089
- // Add 4 per failure, 1 per warning (cantTell).
4221
+ // Add 4 per failure, 1 per warning (cantTell).
4090
4222
  addDetail(which, ruleID, verdict === 'failed' ? 4 : 1);
4091
4223
  }
4092
4224
  }
@@ -4171,7 +4303,7 @@ exports.scorer = async report => {
4171
4303
  items.forEach(issue => {
4172
4304
  const {ruleId, level} = issue;
4173
4305
  if (ruleId && level) {
4174
- // Add 4 per violation, 1 per warning (recommendation).
4306
+ // Add 4 per violation, 1 per warning (recommendation).
4175
4307
  addDetail(which, ruleId, level === 'violation' ? 4 : 1);
4176
4308
  }
4177
4309
  });
@@ -4217,7 +4349,7 @@ exports.scorer = async report => {
4217
4349
  testIDs.forEach(testID => {
4218
4350
  const {count} = items[testID];
4219
4351
  if (count) {
4220
- // Add 4 per error, 3 per contrast error, 1 per warning (alert).
4352
+ // Add 4 per error, 3 per contrast error, 1 per warning (alert).
4221
4353
  addDetail(
4222
4354
  which, `${issueClass[0]}:${testID}`, count * classScores[issueClass]
4223
4355
  );
@@ -4433,19 +4565,21 @@ exports.scorer = async report => {
4433
4565
  // For each package with any scores:
4434
4566
  Object.keys(packageDetails).forEach(packageName => {
4435
4567
  const matchers = testMatchers[packageName];
4568
+ let testClass = '';
4436
4569
  // For each test with any scores in the package:
4437
4570
  Object.keys(packageDetails[packageName]).forEach(testID => {
4438
- // If the package has varying test names:
4439
- if (matchers) {
4440
- // If the test name belongs to a class:
4441
- const testCode = matchers.find(matcher => matcher.test(testID));
4442
- if (testCode) {
4443
- // Change the test name to the name of its class.
4444
- testID = testCode.source;
4571
+ // Determine whether the test is in a group.
4572
+ let groupName = testGroups[packageName][testID];
4573
+ // If not:
4574
+ if (! groupName) {
4575
+ // Determine whether the package has test classes and the class is in a group.
4576
+ testClass = matchers && matchers.find(matcher => matcher.test(testID));
4577
+ if (testClass) {
4578
+ testID = testClass.source;
4579
+ groupName = testGroups[packageName][testID];
4445
4580
  }
4446
4581
  }
4447
- // If the test is in a group:
4448
- const groupName = testGroups[packageName][testID];
4582
+ // If the test or its class is in a group:
4449
4583
  if (groupName) {
4450
4584
  // Determine the preweighted or group-weighted score.
4451
4585
  if (! groupDetails.groups[groupName]) {
@@ -4467,6 +4601,10 @@ exports.scorer = async report => {
4467
4601
  score: roundedScore,
4468
4602
  what: groups[groupName].packages[packageName][testID].what
4469
4603
  };
4604
+ }
4605
+ // Otherwise, if the package has varying test names and the test belongs to a class:
4606
+ else if (matchers && (testCode = matchers.find(matcher => matcher.test(testID)))) {
4607
+
4470
4608
  }
4471
4609
  // Otherwise, i.e. if the test is solo:
4472
4610
  else {