testaro 5.8.0 → 5.9.0
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 +9 -0
- package/package.json +1 -1
- package/run.js +3 -39
- package/tests/elements.js +128 -0
package/commands.js
CHANGED
|
@@ -150,6 +150,15 @@ exports.commands = {
|
|
|
150
150
|
rules: [true, 'array', 'areStrings', 'rule names, or empty if all']
|
|
151
151
|
}
|
|
152
152
|
],
|
|
153
|
+
elements: [
|
|
154
|
+
'Perform an elements test',
|
|
155
|
+
{
|
|
156
|
+
detailLevel: [true, 'number', '', '0 = counts, 1 = selves, 2 = also sibling nodes'],
|
|
157
|
+
tagName: [false, 'string', '', 'tag name of elements'],
|
|
158
|
+
onlyVisible: [false, 'boolean', '', 'whether to exclude invisible elements'],
|
|
159
|
+
attribute: [false, 'string', 'hasLength', 'required attribute or attribute=value']
|
|
160
|
+
}
|
|
161
|
+
],
|
|
153
162
|
embAc: [
|
|
154
163
|
'Perform an embAc test',
|
|
155
164
|
{
|
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -34,6 +34,7 @@ const tests = {
|
|
|
34
34
|
bulk: 'count of visible elements',
|
|
35
35
|
continuum: 'Level Access Continuum, community edition',
|
|
36
36
|
docType: 'document without a doctype property',
|
|
37
|
+
elements: 'data on specified elements',
|
|
37
38
|
embAc: 'active elements embedded in links or buttons',
|
|
38
39
|
focAll: 'focusable and Tab-focused elements',
|
|
39
40
|
focInd: 'focus indicators',
|
|
@@ -70,7 +71,7 @@ const browserTypeNames = {
|
|
|
70
71
|
'firefox': 'Firefox'
|
|
71
72
|
};
|
|
72
73
|
// Items that may be waited for.
|
|
73
|
-
const waitables = ['url', 'title', 'body'
|
|
74
|
+
const waitables = ['url', 'title', 'body'];
|
|
74
75
|
// Tenon data.
|
|
75
76
|
const tenonData = {
|
|
76
77
|
accessToken: '',
|
|
@@ -81,6 +82,7 @@ const errorWords = [
|
|
|
81
82
|
'content security policy',
|
|
82
83
|
'deprecated',
|
|
83
84
|
'error',
|
|
85
|
+
'expected',
|
|
84
86
|
'failed',
|
|
85
87
|
'invalid',
|
|
86
88
|
'missing',
|
|
@@ -812,44 +814,6 @@ const doActs = async (report, actIndex, page) => {
|
|
|
812
814
|
waitError(page, act, error, 'body');
|
|
813
815
|
}
|
|
814
816
|
}
|
|
815
|
-
else if (what === 'mailLink') {
|
|
816
|
-
try {
|
|
817
|
-
const addressJSHandle = await page.waitForFunction(
|
|
818
|
-
text => {
|
|
819
|
-
const mailLinks = document
|
|
820
|
-
&& document.body
|
|
821
|
-
&& document.body.querySelectorAll('a[href^="mailto:"]');
|
|
822
|
-
if (mailLinks && mailLinks.length) {
|
|
823
|
-
const textLC = text.toLowerCase();
|
|
824
|
-
const a11yLink = Array
|
|
825
|
-
.from(mailLinks)
|
|
826
|
-
.find(link => link.textContent.toLowerCase().includes(textLC));
|
|
827
|
-
if (a11yLink) {
|
|
828
|
-
return a11yLink.href.replace(/^mailto:/, '');
|
|
829
|
-
}
|
|
830
|
-
else {
|
|
831
|
-
return false;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
else {
|
|
835
|
-
return false;
|
|
836
|
-
}
|
|
837
|
-
},
|
|
838
|
-
which,
|
|
839
|
-
{
|
|
840
|
-
polling: 1000,
|
|
841
|
-
timeout: 5000
|
|
842
|
-
}
|
|
843
|
-
);
|
|
844
|
-
const address = await addressJSHandle.jsonValue();
|
|
845
|
-
result.found = true;
|
|
846
|
-
result.address = address;
|
|
847
|
-
}
|
|
848
|
-
catch(error) {
|
|
849
|
-
actIndex = -2;
|
|
850
|
-
waitError(page, act, error, 'mailLink');
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
817
|
}
|
|
854
818
|
// Otherwise, if the act is a wait for a state:
|
|
855
819
|
else if (act.type === 'state') {
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
elements
|
|
3
|
+
This test reports data about specified elements.
|
|
4
|
+
*/
|
|
5
|
+
exports.reporter = async (page, detailLevel, tagName, onlyVisible, attribute) => {
|
|
6
|
+
// Determine a selector of the specified elements.
|
|
7
|
+
let selector = tagName || '*';
|
|
8
|
+
if (attribute) {
|
|
9
|
+
selector += `[${attribute}]`;
|
|
10
|
+
}
|
|
11
|
+
if (onlyVisible) {
|
|
12
|
+
selector += ':visible';
|
|
13
|
+
}
|
|
14
|
+
// Get the data on the elements.
|
|
15
|
+
const data = await page.$$eval(selector, (elements, detailLevel) => {
|
|
16
|
+
// FUNCTION DEFINITIONS START
|
|
17
|
+
// Compacts a string.
|
|
18
|
+
const compact = string => string.replace(/\s+/g, ' ').trim();
|
|
19
|
+
// Gets data on the sibling nodes of an element.
|
|
20
|
+
const getSibInfo = (node, nodeType, text) => {
|
|
21
|
+
const sibInfo = {
|
|
22
|
+
type: nodeType
|
|
23
|
+
};
|
|
24
|
+
if (nodeType === 1) {
|
|
25
|
+
sibInfo.tagName = node.tagName;
|
|
26
|
+
}
|
|
27
|
+
else if (nodeType === 3) {
|
|
28
|
+
sibInfo.text = compact(text);
|
|
29
|
+
}
|
|
30
|
+
return sibInfo;
|
|
31
|
+
};
|
|
32
|
+
// FUNCTION DEFINITIONS END
|
|
33
|
+
// Initialize the data with the count of the specified elements.
|
|
34
|
+
const data = {
|
|
35
|
+
total: elements.length
|
|
36
|
+
};
|
|
37
|
+
// If no itemization is required:
|
|
38
|
+
if (detailLevel === 0) {
|
|
39
|
+
// Return the element count.
|
|
40
|
+
return data;
|
|
41
|
+
}
|
|
42
|
+
// Otherwise, i.e. if itemization is required:
|
|
43
|
+
else {
|
|
44
|
+
// Initialize the item data.
|
|
45
|
+
data.items = [];
|
|
46
|
+
// For each specified element:
|
|
47
|
+
elements.forEach(element => {
|
|
48
|
+
// Initialize data on it.
|
|
49
|
+
const datum = {
|
|
50
|
+
tagName: element.tagName,
|
|
51
|
+
code: compact(element.outerHTML),
|
|
52
|
+
attributes: [],
|
|
53
|
+
textContent: compact(element.textContent)
|
|
54
|
+
};
|
|
55
|
+
// For each of its attributes:
|
|
56
|
+
for (const attribute of element.attributes) {
|
|
57
|
+
// Add data on the attribute to the element data.
|
|
58
|
+
const {name, value} = attribute;
|
|
59
|
+
datum.attributes.push({
|
|
60
|
+
name,
|
|
61
|
+
value
|
|
62
|
+
});
|
|
63
|
+
// If the element has reference labels:
|
|
64
|
+
if (name === 'aria-labelledby') {
|
|
65
|
+
// Add their texts to the element data.
|
|
66
|
+
const labelerIDs = value.split(/\s+/);
|
|
67
|
+
const labelers = [];
|
|
68
|
+
labelerIDs.forEach(id => {
|
|
69
|
+
const labeler = document.getElementById(id);
|
|
70
|
+
if (labeler) {
|
|
71
|
+
labelers.push(compact(labeler.textContent));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
if (labelers.length) {
|
|
75
|
+
datum.labelers = labelers;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// If the element has text content:
|
|
80
|
+
const {labels, textContent} = element;
|
|
81
|
+
const compactContent = compact(textContent);
|
|
82
|
+
if (compactContent) {
|
|
83
|
+
// Add it to the element data.
|
|
84
|
+
datum.textContent = compactContent;
|
|
85
|
+
}
|
|
86
|
+
// If the element has labels:
|
|
87
|
+
if (labels && labels.length) {
|
|
88
|
+
// Add their texts to the element data.
|
|
89
|
+
datum.labels = Array.from(labels).map(label => compact(label.textContent));
|
|
90
|
+
}
|
|
91
|
+
// If sibling itemization is required:
|
|
92
|
+
if (detailLevel === 2) {
|
|
93
|
+
// Add the sibling data to the element data.
|
|
94
|
+
datum.siblings = {
|
|
95
|
+
before: [],
|
|
96
|
+
after: []
|
|
97
|
+
};
|
|
98
|
+
let more = element;
|
|
99
|
+
while (more) {
|
|
100
|
+
more = more.previousSibling;
|
|
101
|
+
if (more) {
|
|
102
|
+
const {nodeType, nodeValue} = more;
|
|
103
|
+
if (! (nodeType === 3 && nodeValue === '')) {
|
|
104
|
+
const sibInfo = getSibInfo(more, nodeType, nodeValue);
|
|
105
|
+
datum.siblings.before.unshift(sibInfo);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
more = element;
|
|
110
|
+
while (more) {
|
|
111
|
+
more = more.nextSibling;
|
|
112
|
+
if (more) {
|
|
113
|
+
const {nodeType, textContent} = more;
|
|
114
|
+
if (! (nodeType === 3 && textContent === '')) {
|
|
115
|
+
const sibInfo = getSibInfo(more, nodeType, compact(textContent));
|
|
116
|
+
datum.siblings.after.push(sibInfo);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
data.items.push(datum);
|
|
122
|
+
});
|
|
123
|
+
return data;
|
|
124
|
+
}
|
|
125
|
+
}, detailLevel);
|
|
126
|
+
// Return the result.
|
|
127
|
+
return {result: data};
|
|
128
|
+
};
|