testaro 4.5.2 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -37
- package/commands.js +1 -0
- package/package.json +1 -1
- package/procs/linksByType.js +40 -76
- package/run.js +1 -1
- package/tests/hover.js +20 -18
- package/tests/linkUl.js +23 -20
- package/tests/styleDiff.js +5 -5
- package/tests/tabNav.js +55 -56
- package/validation/tests/scripts/linkUl.json +16 -16
- package/validation/tests/scripts/styleDiff.json +10 -10
- package/validation/tests/targets/linkUl/bad.html +23 -4
- package/validation/tests/targets/linkUl/good.html +5 -5
- package/validation/tests/targets/linkUl/na.html +3 -3
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Testaro includes some of its own accessibility tests. In addition, it performs t
|
|
|
23
23
|
- [alfa](https://alfa.siteimprove.com/) (Siteimprove alfa)
|
|
24
24
|
- [Automated Accessibility Testing Tool](https://www.npmjs.com/package/aatt) (Paypal AATT, running HTML CodeSniffer)
|
|
25
25
|
- [axe-playwright](https://www.npmjs.com/package/axe-playwright) (Deque Axe-core)
|
|
26
|
-
- [Tenon](https://tenon.io/documentation/what-tenon-tests.php)
|
|
26
|
+
- [Tenon](https://tenon.io/documentation/what-tenon-tests.php) (Level Access)
|
|
27
27
|
- [WAVE API](https://wave.webaim.org/api/) (WebAIM WAVE)
|
|
28
28
|
|
|
29
29
|
As of this version, the counts of tests in the packages referenced above were:
|
|
@@ -560,6 +560,8 @@ The `tests` executor makes use of the scripts in the `validation/tests/scripts`
|
|
|
560
560
|
|
|
561
561
|
You can define additional Testaro commands and functionality. Contributions are welcome.
|
|
562
562
|
|
|
563
|
+
Please report any issues, including feature requests, at the [repository](https://github.com/jrpool/testaro/issues).
|
|
564
|
+
|
|
563
565
|
## Accessibility principles
|
|
564
566
|
|
|
565
567
|
The rationales motivating the Testaro-defined tests can be found in comments within the files of those tests, in the `tests` directory. Unavoidably, each test is opinionated. Testaro itself, however, can accommodate other tests representing different opinions. Testaro is intended to be neutral with respect to questions such as the criteria for accessibility, the severities of accessibility issues, whether accessibility is binary or graded, and the distinction between usability and accessibility.
|
|
@@ -594,53 +596,23 @@ The files in the `temp` directory are presumed ephemeral and are not tracked by
|
|
|
594
596
|
|
|
595
597
|
## Related packages
|
|
596
598
|
|
|
597
|
-
[Testilo](https://www.npmjs.com/package/testilo) is an application that
|
|
599
|
+
[Testilo](https://www.npmjs.com/package/testilo) is an application that:
|
|
600
|
+
- produces scores and adds them to the JSON report files of Testaro
|
|
601
|
+
- produces human-oriented HTML digests from scored reports
|
|
602
|
+
- produces human-oriented HTML reports comparing the scores of hosts
|
|
598
603
|
|
|
599
604
|
Testaro is derived from [Autotest](https://github.com/jrpool/autotest).
|
|
600
605
|
|
|
601
606
|
Testaro omits some functionalities of Autotest, such as:
|
|
602
607
|
- tests producing results intended to be human-inspected
|
|
603
|
-
- scoring
|
|
608
|
+
- scoring (performed now by Testilo)
|
|
604
609
|
- file operations for score aggregation, report revision, and HTML reports
|
|
605
610
|
- a web user interface
|
|
606
611
|
|
|
607
612
|
## Origin
|
|
608
613
|
|
|
609
|
-
Work on the custom tests in this package began in 2017, and work on the multi-package federation that Testaro implements began in early 2018. These two aspects were combined into the [Autotest](https://github.com/jrpool/autotest) package in early 2021 and into
|
|
614
|
+
Work on the custom tests in this package began in 2017, and work on the multi-package federation that Testaro implements began in early 2018. These two aspects were combined into the [Autotest](https://github.com/jrpool/autotest) package in early 2021 and into the more single-purpose packages, Testaro and Testilo, in January 2022.
|
|
610
615
|
|
|
611
616
|
## Etymology
|
|
612
617
|
|
|
613
618
|
“Testaro” means “collection of tests” in Esperanto.
|
|
614
|
-
|
|
615
|
-
## Future work
|
|
616
|
-
|
|
617
|
-
### Improvements
|
|
618
|
-
|
|
619
|
-
Further development is contemplated, is taking place, or is welcomed, on:
|
|
620
|
-
- addition of Tenon to the set of packages
|
|
621
|
-
- links with href="#"
|
|
622
|
-
- links and buttons styled non-distinguishably
|
|
623
|
-
- first focused element not first focusable element in DOM
|
|
624
|
-
- never-visible skip links
|
|
625
|
-
- buttons with no text content
|
|
626
|
-
- modal dialogs
|
|
627
|
-
- autocomplete attributes
|
|
628
|
-
- inclusion of other test packages, such as:
|
|
629
|
-
- FAE (https://github.com/opena11y/evaluation-library)
|
|
630
|
-
|
|
631
|
-
## Corrections
|
|
632
|
-
|
|
633
|
-
Issues found or reported with the current version that need diagnosis and correction include:
|
|
634
|
-
|
|
635
|
-
### hover
|
|
636
|
-
|
|
637
|
-
There seem to be a couple of problems with the hover test:
|
|
638
|
-
- The score for unhoverability is documented as 2 times the count of unhoverables, but is reported as 1 time that count.
|
|
639
|
-
- The list of unhoverables in the report is empty.
|
|
640
|
-
Observed after inquiry by Tobias Christian Jensen of Siteimprove on 2022-05-09.
|
|
641
|
-
|
|
642
|
-
### axe
|
|
643
|
-
|
|
644
|
-
Configuration to include best practices and experimental tests.
|
|
645
|
-
|
|
646
|
-
Investigation of tags, including wcag2a, wcag2aa, wcag21a, wcag21aa, best-practice, wcag***, ACT, cat.*.
|
package/commands.js
CHANGED
package/package.json
CHANGED
package/procs/linksByType.js
CHANGED
|
@@ -1,90 +1,54 @@
|
|
|
1
1
|
// Returns an object classifying the links in a page by layout.
|
|
2
2
|
exports.linksByType = async page => await page.evaluateHandle(() => {
|
|
3
3
|
// FUNCTION DEFINITIONS START
|
|
4
|
-
// Returns whether an element has fluid display.
|
|
5
|
-
const hasFluidDisplay = element => {
|
|
6
|
-
const display = window.getComputedStyle(element).display;
|
|
7
|
-
return display.startsWith('inline') || display.startsWith('flex');
|
|
8
|
-
};
|
|
9
|
-
// Returns whether an element and its children have fluid display.
|
|
10
|
-
const isFluid = element => {
|
|
11
|
-
if (hasFluidDisplay(element)) {
|
|
12
|
-
return Array.from(element.children).every(child => hasFluidDisplay(child));
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
// Returns whether all siblings of an element have fluid display.
|
|
19
|
-
const hasFluidSiblings = element => {
|
|
20
|
-
const preSib = element.previousElementSibling;
|
|
21
|
-
if (preSib) {
|
|
22
|
-
const postSib = element.nextElementSibling;
|
|
23
|
-
if (postSib) {
|
|
24
|
-
return isFluid(preSib) && isFluid(postSib);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
return isFluid(preSib);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
const postSib = element.nextElementSibling;
|
|
32
|
-
if (postSib) {
|
|
33
|
-
return isFluid(postSib);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
4
|
// Removes spacing characters from a text.
|
|
41
5
|
const despace = text => text.replace(/\s/g, '');
|
|
42
|
-
// Returns whether
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
6
|
+
// Returns whether a list is a list entirely of links.
|
|
7
|
+
const isLinkList = list => {
|
|
8
|
+
const listItems = Array.from(list.children);
|
|
9
|
+
if (listItems.length > 1) {
|
|
10
|
+
return listItems.length > 1 && listItems.every(item => {
|
|
11
|
+
if (item.tagName === 'LI') {
|
|
12
|
+
const {children} = item;
|
|
13
|
+
if (children.length === 1) {
|
|
14
|
+
const link = children[0];
|
|
15
|
+
if (link.tagName === 'A') {
|
|
16
|
+
const itemText = despace(item.textContent);
|
|
17
|
+
const linkText = despace(link.textContent);
|
|
18
|
+
return itemText.length === linkText.length;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
62
32
|
}
|
|
63
|
-
// Otherwise, i.e. if the element has no text:
|
|
64
33
|
else {
|
|
65
|
-
// Return no.
|
|
66
34
|
return false;
|
|
67
35
|
}
|
|
68
36
|
};
|
|
69
37
|
// FUNCTION DEFINITIONS END
|
|
70
|
-
//
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
inline: [],
|
|
77
|
-
block: []
|
|
78
|
-
};
|
|
79
|
-
// Populate it.
|
|
80
|
-
links.forEach(link => {
|
|
81
|
-
if (isFluid(link) && hasFluidSiblings(link) && hasAdjacentText(link)) {
|
|
82
|
-
linkTypes.inline.push(link);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
linkTypes.block.push(link);
|
|
38
|
+
// Identify the list links in the page.
|
|
39
|
+
const lists = Array.from(document.body.querySelectorAll('ul, ol'));
|
|
40
|
+
const listLinks = [];
|
|
41
|
+
lists.forEach(list => {
|
|
42
|
+
if (isLinkList(list)) {
|
|
43
|
+
listLinks.push(... Array.from(list.querySelectorAll('a')));
|
|
86
44
|
}
|
|
87
45
|
});
|
|
88
|
-
//
|
|
89
|
-
|
|
46
|
+
// Identify the adjacent links in the page.
|
|
47
|
+
const allLinks = Array.from(document.body.querySelectorAll('a'));
|
|
48
|
+
const adjacentLinks = allLinks.filter(link => ! listLinks.includes(link));
|
|
49
|
+
// Return the data.
|
|
50
|
+
return {
|
|
51
|
+
adjacent: adjacentLinks,
|
|
52
|
+
list: listLinks
|
|
53
|
+
};
|
|
90
54
|
});
|
package/run.js
CHANGED
|
@@ -36,7 +36,7 @@ const tests = {
|
|
|
36
36
|
hover: 'hover-caused content additions',
|
|
37
37
|
ibm: 'IBM Accessibility Checker',
|
|
38
38
|
labClash: 'labeling inconsistencies',
|
|
39
|
-
linkUl: '
|
|
39
|
+
linkUl: 'adjacent-link underlining',
|
|
40
40
|
menuNav: 'keyboard navigation between focusable menu items',
|
|
41
41
|
motion: 'motion',
|
|
42
42
|
radioSet: 'fieldset grouping of radio buttons',
|
package/tests/hover.js
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
has the tag name 'A' or 'BUTTON' or otherwise the descendants of the element. The only
|
|
10
10
|
elements counted as being made visible by hovering are those with tag names 'A', 'BUTTON',
|
|
11
11
|
'INPUT', and 'SPAN', and those with 'role="menuitem"' attributes. The test waits 700 ms after
|
|
12
|
-
each hover in case of delayed effects. Despite this delay, the test
|
|
13
|
-
practical by randomly sampling targets instead of hovering over all of them.
|
|
14
|
-
results may vary from one execution to another.
|
|
12
|
+
each hover in case of delayed effects. Despite this delay, the test can make the execution time
|
|
13
|
+
practical by randomly sampling targets instead of hovering over all of them. When sampling is
|
|
14
|
+
performed, the results may vary from one execution to another.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
// CONSTANTS
|
|
@@ -53,14 +53,14 @@ const getSample = (population, sampleSize) => {
|
|
|
53
53
|
return [];
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
|
+
// Returns the text of an element.
|
|
57
|
+
const textOf = async (element, limit) => {
|
|
58
|
+
let text = await element.textContent();
|
|
59
|
+
text = text.trim() || await element.innerHTML();
|
|
60
|
+
return text.trim().replace(/\s*/sg, '').slice(0, limit);
|
|
61
|
+
};
|
|
56
62
|
// Recursively finds and reports triggers and targets.
|
|
57
63
|
const find = async (withItems, page, triggers) => {
|
|
58
|
-
if (withItems) {
|
|
59
|
-
data.items = {
|
|
60
|
-
triggers: [],
|
|
61
|
-
unhoverables: []
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
64
|
// If any potential disclosure triggers remain:
|
|
65
65
|
if (triggers.length) {
|
|
66
66
|
// Identify the first of them.
|
|
@@ -181,12 +181,6 @@ const find = async (withItems, page, triggers) => {
|
|
|
181
181
|
}
|
|
182
182
|
catch (error) {
|
|
183
183
|
console.log('ERROR hovering');
|
|
184
|
-
// Returns the text of an element.
|
|
185
|
-
const textOf = async (element, limit) => {
|
|
186
|
-
let text = await element.textContent();
|
|
187
|
-
text = text.trim() || await element.innerHTML();
|
|
188
|
-
return text.trim().replace(/\s*/sg, '').slice(0, limit);
|
|
189
|
-
};
|
|
190
184
|
data.totals.unhoverables++;
|
|
191
185
|
if (withItems) {
|
|
192
186
|
data.items.unhoverables.push({
|
|
@@ -201,7 +195,16 @@ const find = async (withItems, page, triggers) => {
|
|
|
201
195
|
await find(withItems, page, triggers.slice(1));
|
|
202
196
|
}
|
|
203
197
|
};
|
|
204
|
-
|
|
198
|
+
// Performs hover test and reports results.
|
|
199
|
+
exports.reporter = async (page, sampleSize = Infinity, withItems) => {
|
|
200
|
+
// If details are to be reported:
|
|
201
|
+
if (withItems) {
|
|
202
|
+
// Add properties for details to the initialized result.
|
|
203
|
+
data.items = {
|
|
204
|
+
triggers: [],
|
|
205
|
+
unhoverables: []
|
|
206
|
+
};
|
|
207
|
+
}
|
|
205
208
|
// Identify the triggers.
|
|
206
209
|
const selectors = [
|
|
207
210
|
'body a:visible',
|
|
@@ -217,8 +220,7 @@ exports.reporter = async (page, withItems) => {
|
|
|
217
220
|
});
|
|
218
221
|
// If they number more than the sample size limit, sample them.
|
|
219
222
|
const triggerCount = triggers.length;
|
|
220
|
-
const
|
|
221
|
-
const triggerSample = triggerCount > sampleSize ? getSample(triggers, 15) : triggers;
|
|
223
|
+
const triggerSample = triggerCount > sampleSize ? getSample(triggers, sampleSize) : triggers;
|
|
222
224
|
// Find and document the hover-triggered disclosures.
|
|
223
225
|
await find(withItems, page, triggerSample);
|
|
224
226
|
// If the triggers were sampled:
|
package/tests/linkUl.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/*
|
|
2
2
|
linkUl
|
|
3
|
-
This test reports failures to underline
|
|
4
|
-
traditional style properties that identify links.
|
|
5
|
-
recognized without underlines, but
|
|
6
|
-
visually from surrounding text if not underlined. Underlining
|
|
7
|
-
provides an indicator valuable only to mouse users, and even they must traverse the text
|
|
8
|
-
a mouse merely to discover which passages are links.
|
|
3
|
+
This test reports failures to underline links that are adjacent to nonlink text. Underlining
|
|
4
|
+
and color are the traditional style properties that identify links. Lists of links containing
|
|
5
|
+
only links can be recognized without underlines, but other links are difficult or impossible to
|
|
6
|
+
distinguish visually from surrounding text if not underlined. Underlining adjacent links only on
|
|
7
|
+
hover provides an indicator valuable only to mouse users, and even they must traverse the text
|
|
8
|
+
with a mouse merely to discover which passages are links. This tests treats links as adjacent
|
|
9
|
+
unless they are in an ordered or unordered list of at least 2 links with no other text.
|
|
9
10
|
*/
|
|
10
11
|
exports.reporter = async (page, withItems) => {
|
|
11
12
|
// Identify the links in the page, by type.
|
|
@@ -17,14 +18,14 @@ exports.reporter = async (page, withItems) => {
|
|
|
17
18
|
// Returns a space-minimized copy of a string.
|
|
18
19
|
const compact = string => string.replace(/[\t\n]/g, '').replace(/\s{2,}/g, ' ').trim();
|
|
19
20
|
// FUNCTION DEFINITION END
|
|
20
|
-
// Identify the
|
|
21
|
-
const
|
|
22
|
-
const
|
|
21
|
+
// Identify the adjacent links.
|
|
22
|
+
const adjacentLinks = linkTypes.adjacent;
|
|
23
|
+
const adjacentLinkCount = adjacentLinks.length;
|
|
23
24
|
let underlined = 0;
|
|
24
|
-
const
|
|
25
|
-
const
|
|
25
|
+
const ulAdjacentLinkTexts = [];
|
|
26
|
+
const nulAdjacentLinkTexts = [];
|
|
26
27
|
// For each of them:
|
|
27
|
-
|
|
28
|
+
adjacentLinks.forEach(link => {
|
|
28
29
|
// Identify the text of the link if itemization is required.
|
|
29
30
|
const text = withItems ? compact(link.textContent) : '';
|
|
30
31
|
// If it is underlined:
|
|
@@ -33,22 +34,24 @@ exports.reporter = async (page, withItems) => {
|
|
|
33
34
|
underlined++;
|
|
34
35
|
// If required, add its text to the array of their texts.
|
|
35
36
|
if (withItems) {
|
|
36
|
-
|
|
37
|
+
ulAdjacentLinkTexts.push(text);
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
// Otherwise, if it is not underlined and itemization is required:
|
|
40
41
|
else if (withItems) {
|
|
41
42
|
// Add its text to the array of texts of non-underlined inline links.
|
|
42
|
-
|
|
43
|
+
nulAdjacentLinkTexts.push(text);
|
|
43
44
|
}
|
|
44
45
|
});
|
|
45
46
|
// Get the percentage of underlined links among all inline links.
|
|
46
|
-
const underlinedPercent =
|
|
47
|
+
const underlinedPercent = adjacentLinkCount
|
|
48
|
+
? Math.floor(100 * underlined / adjacentLinkCount)
|
|
49
|
+
: 'N/A';
|
|
47
50
|
const data = {
|
|
48
51
|
totals: {
|
|
49
|
-
links:
|
|
50
|
-
|
|
51
|
-
total:
|
|
52
|
+
links: adjacentLinks.length + linkTypes.list.length,
|
|
53
|
+
adjacent: {
|
|
54
|
+
total: adjacentLinkCount,
|
|
52
55
|
underlined,
|
|
53
56
|
underlinedPercent
|
|
54
57
|
}
|
|
@@ -56,8 +59,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
56
59
|
};
|
|
57
60
|
if (withItems) {
|
|
58
61
|
data.items = {
|
|
59
|
-
underlined:
|
|
60
|
-
notUnderlined:
|
|
62
|
+
underlined: ulAdjacentLinkTexts,
|
|
63
|
+
notUnderlined: nulAdjacentLinkTexts
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
return {result: data};
|
package/tests/styleDiff.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/*
|
|
2
2
|
styleDiff
|
|
3
3
|
This test reports style differences among links, buttons, and headings. It assumes
|
|
4
|
-
that an accessible page employs few or only one style for
|
|
5
|
-
for
|
|
4
|
+
that an accessible page employs few or only one style for adjacent links, and likewise
|
|
5
|
+
for list links, buttons, and headings at each level. The test considers only
|
|
6
6
|
particular style properties, listed in the 'mainStyles' and 'headingStyles' arrays.
|
|
7
7
|
*/
|
|
8
8
|
exports.reporter = async (page, withItems) => {
|
|
9
|
-
// Get an object with arrays of
|
|
9
|
+
// Get an object with arrays of list and adjacent links as properties.
|
|
10
10
|
const linkTypes = await require('../procs/linksByType').linksByType(page);
|
|
11
11
|
return await page.$eval('body', (body, args) => {
|
|
12
12
|
const withItems = args[0];
|
|
@@ -51,8 +51,8 @@ exports.reporter = async (page, withItems) => {
|
|
|
51
51
|
const elementClasses = {
|
|
52
52
|
headings: {},
|
|
53
53
|
other: {
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
aAdjacent: linkTypes.adjacent,
|
|
55
|
+
aList: linkTypes.list
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
// For each heading tag name:
|
package/tests/tabNav.js
CHANGED
|
@@ -4,70 +4,69 @@
|
|
|
4
4
|
Standards are based on https://www.w3.org/TR/wai-aria-practices-1.1/#tabpanel.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
//
|
|
7
|
+
// FUNCTIONS
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
specific: {
|
|
18
|
-
tab: {
|
|
19
|
-
total: 0,
|
|
20
|
-
correct: 0,
|
|
21
|
-
incorrect: 0
|
|
22
|
-
},
|
|
23
|
-
left: {
|
|
24
|
-
total: 0,
|
|
25
|
-
correct: 0,
|
|
26
|
-
incorrect: 0
|
|
27
|
-
},
|
|
28
|
-
right: {
|
|
29
|
-
total: 0,
|
|
30
|
-
correct: 0,
|
|
31
|
-
incorrect: 0
|
|
32
|
-
},
|
|
33
|
-
up: {
|
|
34
|
-
total: 0,
|
|
35
|
-
correct: 0,
|
|
36
|
-
incorrect: 0
|
|
37
|
-
},
|
|
38
|
-
down: {
|
|
39
|
-
total: 0,
|
|
40
|
-
correct: 0,
|
|
41
|
-
incorrect: 0
|
|
42
|
-
},
|
|
43
|
-
home: {
|
|
9
|
+
// Tests tab-list navigation and reports results.
|
|
10
|
+
exports.reporter = async (page, withItems) => {
|
|
11
|
+
// Initialize the results.
|
|
12
|
+
const data = {
|
|
13
|
+
totals: {
|
|
14
|
+
navigations: {
|
|
15
|
+
all: {
|
|
44
16
|
total: 0,
|
|
45
17
|
correct: 0,
|
|
46
18
|
incorrect: 0
|
|
47
19
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
20
|
+
specific: {
|
|
21
|
+
tab: {
|
|
22
|
+
total: 0,
|
|
23
|
+
correct: 0,
|
|
24
|
+
incorrect: 0
|
|
25
|
+
},
|
|
26
|
+
left: {
|
|
27
|
+
total: 0,
|
|
28
|
+
correct: 0,
|
|
29
|
+
incorrect: 0
|
|
30
|
+
},
|
|
31
|
+
right: {
|
|
32
|
+
total: 0,
|
|
33
|
+
correct: 0,
|
|
34
|
+
incorrect: 0
|
|
35
|
+
},
|
|
36
|
+
up: {
|
|
37
|
+
total: 0,
|
|
38
|
+
correct: 0,
|
|
39
|
+
incorrect: 0
|
|
40
|
+
},
|
|
41
|
+
down: {
|
|
42
|
+
total: 0,
|
|
43
|
+
correct: 0,
|
|
44
|
+
incorrect: 0
|
|
45
|
+
},
|
|
46
|
+
home: {
|
|
47
|
+
total: 0,
|
|
48
|
+
correct: 0,
|
|
49
|
+
incorrect: 0
|
|
50
|
+
},
|
|
51
|
+
end: {
|
|
52
|
+
total: 0,
|
|
53
|
+
correct: 0,
|
|
54
|
+
incorrect: 0
|
|
55
|
+
}
|
|
52
56
|
}
|
|
57
|
+
},
|
|
58
|
+
tabElements: {
|
|
59
|
+
total: 0,
|
|
60
|
+
correct: 0,
|
|
61
|
+
incorrect: 0
|
|
62
|
+
},
|
|
63
|
+
tabLists: {
|
|
64
|
+
total: 0,
|
|
65
|
+
correct: 0,
|
|
66
|
+
incorrect: 0
|
|
53
67
|
}
|
|
54
|
-
},
|
|
55
|
-
tabElements: {
|
|
56
|
-
total: 0,
|
|
57
|
-
correct: 0,
|
|
58
|
-
incorrect: 0
|
|
59
|
-
},
|
|
60
|
-
tabLists: {
|
|
61
|
-
total: 0,
|
|
62
|
-
correct: 0,
|
|
63
|
-
incorrect: 0
|
|
64
68
|
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// FUNCTIONS
|
|
69
|
-
|
|
70
|
-
exports.reporter = async (page, withItems) => {
|
|
69
|
+
};
|
|
71
70
|
if (withItems) {
|
|
72
71
|
data.tabElements = {
|
|
73
72
|
incorrect: [],
|
|
@@ -10,52 +10,52 @@
|
|
|
10
10
|
{
|
|
11
11
|
"type": "url",
|
|
12
12
|
"which": "__targets__/linkUl/good.html",
|
|
13
|
-
"what": "page with underlined
|
|
13
|
+
"what": "page with underlined adjacent links"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"type": "test",
|
|
17
17
|
"which": "linkUl",
|
|
18
|
-
"what": "link underlining",
|
|
18
|
+
"what": "adjacent-link underlining",
|
|
19
19
|
"withItems": false,
|
|
20
20
|
"expect": [
|
|
21
21
|
["totals.links", "=", 6],
|
|
22
|
-
["totals.
|
|
23
|
-
["totals.
|
|
24
|
-
["totals.
|
|
22
|
+
["totals.adjacent.total", "=", 2],
|
|
23
|
+
["totals.adjacent.underlined", "=", 2],
|
|
24
|
+
["totals.adjacent.underlinedPercent", "=", 100]
|
|
25
25
|
]
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"type": "url",
|
|
29
29
|
"which": "__targets__/linkUl/bad.html",
|
|
30
|
-
"what": "page
|
|
30
|
+
"what": "page with nonunderlined adjacent links"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"type": "test",
|
|
34
34
|
"which": "linkUl",
|
|
35
|
-
"what": "link underlining",
|
|
35
|
+
"what": "adjacent-link underlining",
|
|
36
36
|
"withItems": false,
|
|
37
37
|
"expect": [
|
|
38
|
-
["totals.links", "=",
|
|
39
|
-
["totals.
|
|
40
|
-
["totals.
|
|
41
|
-
["totals.
|
|
38
|
+
["totals.links", "=", 6],
|
|
39
|
+
["totals.adjacent.total", "=", 6],
|
|
40
|
+
["totals.adjacent.underlined", "=", 0],
|
|
41
|
+
["totals.adjacent.underlinedPercent", "=", 0]
|
|
42
42
|
]
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"type": "url",
|
|
46
46
|
"which": "__targets__/linkUl/na.html",
|
|
47
|
-
"what": "page without
|
|
47
|
+
"what": "page without adjacent links"
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"type": "test",
|
|
51
51
|
"which": "linkUl",
|
|
52
|
-
"what": "link underlining",
|
|
52
|
+
"what": "adjacent-link underlining",
|
|
53
53
|
"withItems": false,
|
|
54
54
|
"expect": [
|
|
55
55
|
["totals.links", "=", 2],
|
|
56
|
-
["totals.
|
|
57
|
-
["totals.
|
|
58
|
-
["totals.
|
|
56
|
+
["totals.adjacent.total", "=", 0],
|
|
57
|
+
["totals.adjacent.underlined", "=", 0],
|
|
58
|
+
["totals.adjacent.underlinedPercent", "=", "N/A"]
|
|
59
59
|
]
|
|
60
60
|
}
|
|
61
61
|
]
|
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
"what": "styleDiff",
|
|
19
19
|
"withItems": false,
|
|
20
20
|
"expect": [
|
|
21
|
-
["totals.
|
|
22
|
-
["totals.
|
|
21
|
+
["totals.aAdjacent.total", "=", 2],
|
|
22
|
+
["totals.aList.total", "=", 2],
|
|
23
23
|
["totals.button.total", "=", 2],
|
|
24
24
|
["totals.h1.total", "=", 1],
|
|
25
25
|
["totals.h2.total", "=", 4],
|
|
26
|
-
["totals.
|
|
27
|
-
["totals.
|
|
26
|
+
["totals.aAdjacent.subtotals"],
|
|
27
|
+
["totals.aList.subtotals"],
|
|
28
28
|
["totals.button.subtotals"],
|
|
29
29
|
["totals.h1.subtotals"],
|
|
30
30
|
["totals.h2.subtotals"]
|
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
"what": "styleDiff",
|
|
42
42
|
"withItems": false,
|
|
43
43
|
"expect": [
|
|
44
|
-
["totals.
|
|
45
|
-
["totals.
|
|
44
|
+
["totals.aAdjacent.total", "=", 2],
|
|
45
|
+
["totals.aList.total", "=", 2],
|
|
46
46
|
["totals.button.total", "=", 2],
|
|
47
47
|
["totals.h1.total", "=", 1],
|
|
48
48
|
["totals.h2.total", "=", 4],
|
|
49
|
-
["totals.
|
|
50
|
-
["totals.
|
|
51
|
-
["totals.
|
|
52
|
-
["totals.
|
|
49
|
+
["totals.aAdjacent.subtotals.0", "=", 1],
|
|
50
|
+
["totals.aAdjacent.subtotals.1", "=", 1],
|
|
51
|
+
["totals.aList.subtotals.0", "=", 1],
|
|
52
|
+
["totals.aList.subtotals.1", "=", 1],
|
|
53
53
|
["totals.button.subtotals.0", "=", 1],
|
|
54
54
|
["totals.button.subtotals.1", "=", 1],
|
|
55
55
|
["totals.h1.subtotals"],
|
|
@@ -2,15 +2,34 @@
|
|
|
2
2
|
<html lang="en-US">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
|
-
<title>Page without underlined
|
|
5
|
+
<title>Page without underlined adjacent links</title>
|
|
6
6
|
<meta name="description" content="tester">
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
+
<style>
|
|
9
|
+
.nude > li > a {
|
|
10
|
+
text-decoration: none;
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
8
13
|
</head>
|
|
9
14
|
<body>
|
|
10
15
|
<main>
|
|
11
|
-
<h1>Page without underlined
|
|
12
|
-
<p>This paragraph contains an
|
|
13
|
-
<p>This paragraph contains an
|
|
16
|
+
<h1>Page without underlined adjacent links</h1>
|
|
17
|
+
<p>This paragraph contains an adjacent link to <a style="text-decoration: overline" href="https://en.wikipedia.org">English information</a> that has an overline instead of an underline.</p>
|
|
18
|
+
<p>This paragraph contains an adjacent link to <a style="text-decoration: none" href="https://fr.wikipedia.org">French information</a> without any underline.</p>
|
|
19
|
+
<p>This paragraph introduces a list of nonunderlined links, but it contains only 1 link, so that link fails to be classified as a list link.</p>
|
|
20
|
+
<ul class="nude"</ul>
|
|
21
|
+
<li><a href="https://eus.wikipedia.org">Basque information</a></li>
|
|
22
|
+
</ul>
|
|
23
|
+
<p>This paragraph introduces a list of nonunderlined links, but it contains an item that is not a link, so its link fails to be classified as a list link.</p>
|
|
24
|
+
<ul class="nude">
|
|
25
|
+
<li><span>Spanish information is not available</span></li>
|
|
26
|
+
<li><a href="https://eo.wikipedia.org">Esperanto information</a></li>
|
|
27
|
+
</ul>
|
|
28
|
+
<p>This paragraph introduces a list of nonunderlined links, but it contains additional text, so its links fail to be classified as a list link.</p>
|
|
29
|
+
<ul class="nude">
|
|
30
|
+
<li><a href="https://fr.wikipedia.org">French information</a> is available, as well as</li>
|
|
31
|
+
<li><a href="https://tr.wikipedia.org">Turkish information</a></li>
|
|
32
|
+
</ul>
|
|
14
33
|
</main>
|
|
15
34
|
</body>
|
|
16
35
|
</html>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<html lang="en-US">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
|
-
<title>Page with underlined
|
|
5
|
+
<title>Page with underlined adjacent links</title>
|
|
6
6
|
<meta name="description" content="tester">
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
8
|
<style>
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<main>
|
|
16
|
-
<h1>Page with underlined
|
|
17
|
-
<p>This page contains
|
|
18
|
-
<p>The following links, however, are not
|
|
16
|
+
<h1>Page with underlined adjacent links</h1>
|
|
17
|
+
<p>This page contains adjacent links to <a href="https://en.wikipedia.org">English information</a> and <a style="text-decoration: underline wavy 2px" href="https://fr.wikipedia.org">French information</a>. The latter is weird, but still an underline.</p>
|
|
18
|
+
<p>The following links, however, are not adjacent, so can be (and are) devoid of underlines.</p>
|
|
19
19
|
<ul class="nude">
|
|
20
20
|
<li><a href="https://sp.wikipedia.org">Spanish information</a></li>
|
|
21
21
|
<li><a href="https://eo.wikipedia.org">Esperanto information</a></li>
|
|
22
22
|
</ul>
|
|
23
|
-
<p>The following links are not
|
|
23
|
+
<p>The following links are not adjacent, so are permitted to be devoid of underlines, but still have them.</p>
|
|
24
24
|
<ul>
|
|
25
25
|
<li><a href="https://eus.wikipedia.org">Basque information</a></li>
|
|
26
26
|
<li><a href="https://tr.wikipedia.org">Turkish information</a></li>
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<main>
|
|
11
|
-
<h1>Page without
|
|
12
|
-
<p>This page contains no
|
|
13
|
-
<p>The following links are
|
|
11
|
+
<h1>Page without adjacent links</h1>
|
|
12
|
+
<p>This page contains list links but no adjacent links.</p>
|
|
13
|
+
<p>The following links are list links.</p>
|
|
14
14
|
<ul>
|
|
15
15
|
<li><a href="https://eus.wikipedia.org">Basque information</a></li>
|
|
16
16
|
<li><a href="https://tr.wikipedia.org">Turkish information</a></li>
|