testaro 4.6.1 → 4.7.2
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/commands.js
CHANGED
|
@@ -166,8 +166,9 @@ exports.commands = {
|
|
|
166
166
|
focInd: [
|
|
167
167
|
'Perform a focInd test',
|
|
168
168
|
{
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
revealAll: [true, 'boolean', '', 'whether to make all elements visible first'],
|
|
170
|
+
allowedDelay: [true, 'number', '', 'milliseconds to wait for an outline'],
|
|
171
|
+
withItems: [true, 'boolean']
|
|
171
172
|
}
|
|
172
173
|
],
|
|
173
174
|
focOp: [
|
package/package.json
CHANGED
package/tests/focInd.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/*
|
|
2
2
|
focInd
|
|
3
3
|
This test reports focusable elements without focus indicators, with non-outline focus
|
|
4
|
-
indicators, and with outline focus indicators.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
indicators, and with outline focus indicators. An outline is recognized if it has non-zero
|
|
5
|
+
line thickness and non-transparent color. The test is based on the assumption that outlines are
|
|
6
|
+
the standard and thus most familiar focus indicator. Other focus indicators are assumed better
|
|
7
|
+
than none, but more likely to be misunderstood. For example, underlines may be mistaken for
|
|
8
|
+
selection indicators. Some pages delay the appearance of focus indicators. This test waits for
|
|
9
|
+
focus indicators to appear if specified and, if there is a delay, reports on its magnitude.
|
|
9
10
|
|
|
10
11
|
Bug: This test fails to recognize outlines when run with firefox.
|
|
11
12
|
*/
|
|
12
|
-
exports.reporter = async (page,
|
|
13
|
+
exports.reporter = async (page, revealAll, allowedDelay, withItems) => {
|
|
13
14
|
// If required, make all elements visible.
|
|
14
15
|
if (revealAll) {
|
|
15
16
|
await require('../procs/allVis').allVis(page);
|
|
16
17
|
}
|
|
17
18
|
// Get data on the focusable visible elements with and without indicators.
|
|
18
|
-
const data = await page.$$eval('body *:visible', (elements,
|
|
19
|
+
const data = await page.$$eval('body *:visible', async (elements, args) => {
|
|
20
|
+
const allowedDelay = args[0];
|
|
21
|
+
const withItems = args[1];
|
|
19
22
|
// Initialize the data.
|
|
20
23
|
const data = {
|
|
21
24
|
totals: {
|
|
@@ -31,6 +34,7 @@ exports.reporter = async (page, withItems, revealAll) => {
|
|
|
31
34
|
},
|
|
32
35
|
outlinePresent: {
|
|
33
36
|
total: 0,
|
|
37
|
+
meanDelay: 0,
|
|
34
38
|
tagNames: {}
|
|
35
39
|
}
|
|
36
40
|
}
|
|
@@ -43,9 +47,13 @@ exports.reporter = async (page, withItems, revealAll) => {
|
|
|
43
47
|
outlinePresent: []
|
|
44
48
|
};
|
|
45
49
|
}
|
|
46
|
-
|
|
50
|
+
// Adds facts about an element to the result.
|
|
51
|
+
const addElementFacts = (element, status, delay = null) => {
|
|
47
52
|
const type = data.totals.types[status];
|
|
48
53
|
type.total++;
|
|
54
|
+
if (status === 'outlinePresent') {
|
|
55
|
+
type.meanDelay = Math.round(((type.total - 1) * type.meanDelay + delay) / type.total);
|
|
56
|
+
}
|
|
49
57
|
const tagName = element.tagName;
|
|
50
58
|
if (type.tagNames[tagName]) {
|
|
51
59
|
type.tagNames[tagName]++;
|
|
@@ -54,46 +62,91 @@ exports.reporter = async (page, withItems, revealAll) => {
|
|
|
54
62
|
type.tagNames[tagName] = 1;
|
|
55
63
|
}
|
|
56
64
|
if (withItems) {
|
|
57
|
-
|
|
65
|
+
const elementData = {
|
|
58
66
|
tagName,
|
|
59
67
|
text: element.textContent.trim().replace(/\s{2,}/g, ' ').slice(0, 100)
|
|
60
|
-
}
|
|
68
|
+
};
|
|
69
|
+
if (status === 'outlinePresent') {
|
|
70
|
+
elementData.delay = delay;
|
|
71
|
+
}
|
|
72
|
+
data.items[status].push(elementData);
|
|
61
73
|
}
|
|
62
74
|
};
|
|
63
|
-
|
|
75
|
+
// For each visible element descendant of the body:
|
|
76
|
+
for(const element of elements) {
|
|
77
|
+
// If it is Tab-focusable:
|
|
64
78
|
if (element.tabIndex === 0) {
|
|
79
|
+
// Increment the total of focusable elements.
|
|
65
80
|
data.totals.total++;
|
|
66
|
-
|
|
81
|
+
// Get a live style declaration of its properties.
|
|
82
|
+
const styleDec = window.getComputedStyle(element);
|
|
83
|
+
// Freeze a copy to preserve the style properties when not focused.
|
|
84
|
+
const styleBlurred = Object.assign({}, styleDec);
|
|
85
|
+
// Focus it, potentially changing the properties in its style declaration.
|
|
67
86
|
element.focus({preventScroll: true});
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
let hasOutline = false;
|
|
88
|
+
// If it has no outline when not focused:
|
|
89
|
+
if (styleBlurred.outlineWidth === '0px') {
|
|
90
|
+
// If an outline appeared immediately on focus:
|
|
91
|
+
if (styleDec.outlineWidth !== '0px' && styleDec.outlineColor !== 'rgba(0, 0, 0, 0)') {
|
|
92
|
+
// Add facts about the element to the result.
|
|
93
|
+
addElementFacts(element, 'outlinePresent', 0);
|
|
94
|
+
hasOutline = true;
|
|
95
|
+
}
|
|
96
|
+
// Otherwise, if a wait for an outline is allowed:
|
|
97
|
+
else if (allowedDelay) {
|
|
98
|
+
// Determine how long an outline takes to appear or whether it times out.
|
|
99
|
+
const outlineDelay = new Promise(resolve => {
|
|
100
|
+
const focusTime = Date.now();
|
|
101
|
+
const deadline = focusTime + allowedDelay;
|
|
102
|
+
const interval = setInterval(() => {
|
|
103
|
+
if (
|
|
104
|
+
styleDec.outlineWidth !== '0px' && styleDec.outlineColor !== 'rgba(0, 0, 0, 0)'
|
|
105
|
+
) {
|
|
106
|
+
resolve(Date.now() - focusTime);
|
|
107
|
+
clearInterval(interval);
|
|
108
|
+
}
|
|
109
|
+
else if (Date.now() > deadline) {
|
|
110
|
+
resolve(null);
|
|
111
|
+
clearInterval(interval);
|
|
112
|
+
}
|
|
113
|
+
}, 100);
|
|
114
|
+
});
|
|
115
|
+
// If it appeared before the wait limit:
|
|
116
|
+
const delay = await outlineDelay;
|
|
117
|
+
if (delay) {
|
|
118
|
+
// Add facts about the element to the result.
|
|
119
|
+
addElementFacts(element, 'outlinePresent', delay);
|
|
120
|
+
hasOutline = true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
74
123
|
}
|
|
75
|
-
|
|
76
|
-
|
|
124
|
+
// If no allowed outline appeared:
|
|
125
|
+
if (! hasOutline) {
|
|
126
|
+
// Returns whether a style property differs between focused and not focused.
|
|
127
|
+
const diff = prop => styleDec[prop] !== styleBlurred[prop];
|
|
128
|
+
// Determine whether the element has another allowed focus indicator.
|
|
129
|
+
const hasDiffOutline = styleDec.outlineWidth !== '0px'
|
|
130
|
+
&& styleDec.outlineColor !== 'rgba(0, 0, 0, 0)'
|
|
131
|
+
&& (diff('outlineStyle') || diff('outlineWidth'));
|
|
132
|
+
const hasDiffBorder = styleDec.borderWidth !== '0px'
|
|
133
|
+
&& styleDec.borderColor !== 'rgba(0, 0, 0, 0)'
|
|
134
|
+
&& (diff('borderStyle') || diff('borderWidth'));
|
|
77
135
|
const hasIndicator
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|| diff('fontSize')
|
|
87
|
-
|| diff('fontStyle')
|
|
88
|
-
|| diff('textDecorationLine')
|
|
89
|
-
|| diff('textDecorationStyle')
|
|
90
|
-
|| diff('textDecorationThickness');
|
|
136
|
+
= hasDiffOutline
|
|
137
|
+
|| hasDiffBorder
|
|
138
|
+
|| diff('fontSize')
|
|
139
|
+
|| diff('fontStyle')
|
|
140
|
+
|| diff('textDecorationLine')
|
|
141
|
+
|| diff('textDecorationStyle')
|
|
142
|
+
|| diff('textDecorationThickness');
|
|
143
|
+
// Add the determination to the result.
|
|
91
144
|
const status = hasIndicator ? 'nonOutlinePresent' : 'indicatorMissing';
|
|
92
145
|
addElementFacts(element, status);
|
|
93
146
|
}
|
|
94
147
|
}
|
|
95
|
-
}
|
|
148
|
+
};
|
|
96
149
|
return data;
|
|
97
|
-
}, withItems);
|
|
150
|
+
}, [allowedDelay, withItems]);
|
|
98
151
|
return {result: data};
|
|
99
152
|
};
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
{
|
|
16
16
|
"type": "test",
|
|
17
17
|
"which": "focInd",
|
|
18
|
-
"what": "focus indication",
|
|
19
|
-
"withItems": false,
|
|
20
18
|
"revealAll": false,
|
|
19
|
+
"allowedDelay": 0,
|
|
20
|
+
"withItems": false,
|
|
21
|
+
"what": "focus indication",
|
|
21
22
|
"expect": [
|
|
22
23
|
["totals.total", "=", 4],
|
|
23
24
|
["totals.types.indicatorMissing.total", "=", 0],
|
|
@@ -36,15 +37,19 @@
|
|
|
36
37
|
{
|
|
37
38
|
"type": "test",
|
|
38
39
|
"which": "focInd",
|
|
39
|
-
"what": "focus indication",
|
|
40
|
-
"withItems": false,
|
|
41
40
|
"revealAll": false,
|
|
41
|
+
"allowedDelay": 150,
|
|
42
|
+
"withItems": true,
|
|
43
|
+
"what": "focus indication",
|
|
42
44
|
"expect": [
|
|
43
|
-
["totals.total", "=",
|
|
44
|
-
["totals.types.indicatorMissing.total", "=",
|
|
45
|
-
["totals.types.indicatorMissing.tagNames.
|
|
46
|
-
["totals.types.
|
|
45
|
+
["totals.total", "=", 9],
|
|
46
|
+
["totals.types.indicatorMissing.total", "=", 3],
|
|
47
|
+
["totals.types.indicatorMissing.tagNames.A", "=", 1],
|
|
48
|
+
["totals.types.indicatorMissing.tagNames.INPUT", "=", 2],
|
|
49
|
+
["totals.types.nonOutlinePresent.total", "=", 3],
|
|
50
|
+
["totals.types.nonOutlinePresent.tagNames.A", "=", 1],
|
|
47
51
|
["totals.types.nonOutlinePresent.tagNames.BUTTON", "=", 1],
|
|
52
|
+
["totals.types.nonOutlinePresent.tagNames.INPUT", "=", 1],
|
|
48
53
|
["totals.types.outlinePresent.total", "=", 3],
|
|
49
54
|
["totals.types.outlinePresent.tagNames.A", "=", 1],
|
|
50
55
|
["totals.types.outlinePresent.tagNames.BUTTON", "=", 1],
|
|
@@ -6,26 +6,61 @@
|
|
|
6
6
|
<meta name="description" content="tester">
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
8
|
<style>
|
|
9
|
-
|
|
9
|
+
#button:focus, #checkbox:focus {
|
|
10
|
+
outline: 3px solid blue;
|
|
11
|
+
outline-offset: 2px;
|
|
12
|
+
}
|
|
13
|
+
#checkbox {
|
|
14
|
+
transition-property: outline;
|
|
15
|
+
transition-delay: 35ms;
|
|
16
|
+
transition-duration: 40ms;
|
|
17
|
+
}
|
|
18
|
+
#outlinedInput {
|
|
19
|
+
outline: 2px solid black;
|
|
20
|
+
}
|
|
21
|
+
#outlinedInput:focus {
|
|
22
|
+
outline: 2px solid brown;
|
|
23
|
+
}
|
|
24
|
+
#slowLink {
|
|
25
|
+
transition-property: border;
|
|
26
|
+
transition-delay: 125ms;
|
|
27
|
+
}
|
|
28
|
+
#slowLink:focus, #sluggishLink:focus {
|
|
29
|
+
border: 2px solid green;
|
|
10
30
|
outline: none;
|
|
11
31
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
32
|
+
#sluggishLink {
|
|
33
|
+
transition-property: border;
|
|
34
|
+
transition-delay: 525ms;
|
|
15
35
|
}
|
|
16
36
|
#special:focus {
|
|
17
37
|
outline: none;
|
|
18
38
|
text-decoration-line: underline overline;
|
|
19
|
-
text-decoration-color:
|
|
39
|
+
text-decoration-color: darkorange;
|
|
40
|
+
}
|
|
41
|
+
#textInput:focus {
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
44
|
+
#thickOutlineInput {
|
|
45
|
+
outline: 1px solid black;
|
|
46
|
+
}
|
|
47
|
+
#thickOutlineInput:focus {
|
|
48
|
+
outline: 4px solid black;
|
|
20
49
|
}
|
|
21
50
|
</style>
|
|
22
51
|
</head>
|
|
23
52
|
<body>
|
|
24
53
|
<main>
|
|
25
54
|
<h1>Page with mixed focus indication</h1>
|
|
26
|
-
<p>This paragraph contains a link to <a href="https://en.wikipedia.org">information</a>,
|
|
27
|
-
<p>This paragraph contains a
|
|
28
|
-
<p>This paragraph contains a
|
|
55
|
+
<p>This paragraph contains a link to <a href="https://en.wikipedia.org">English information</a>, which exhibits a default focus indicator.</p>
|
|
56
|
+
<p>This paragraph contains a <button id="button" type="button">button</button> with a custom outline as its focus indicator.</p>
|
|
57
|
+
<p>This paragraph contains a <label>text input <input id="textInput" type="text"></label> with the focus indicator suppressed.</p>
|
|
58
|
+
<p>This paragraph contains a <label>text input <input id="outlinedInput" type="text"></label> with a custom outline, which changes only color when the input is focused.</p>
|
|
59
|
+
<p>This paragraph contains a <label>text input <input id="thickOutlineInput" type="text"></label> with a custom outline, which changes only thickness when the input is focused.</p>
|
|
60
|
+
<p>This paragraph contains a checkbox with an enhanced focus-indication outline that finishes appearing 75 ms after the checkbox becomes focused. <label><input id="checkbox" type="checkbox"> I am a bad page.</label></p>
|
|
61
|
+
<p>This paragraph contains a link to <a id="slowLink" href="https://fr.wikipedia.org">French information</a> with a custom border as its only focus indicator. The border appears 125 ms after the link becomes focused.</p>
|
|
62
|
+
<p>This paragraph contains a link to <a id="sluggishLink" href="https://de.wikipedia.org">German information</a> with a custom border as its only focus indicator. The border appears 525 ms after the link becomes focused.</p>
|
|
63
|
+
<p>This paragraph contains a button with a focus indicator consisting solely of an underline and an overline. <button id="special" type="button">special button</button></p>
|
|
29
64
|
</main>
|
|
30
65
|
</body>
|
|
31
66
|
</html>
|