testaro 5.14.2 → 5.14.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.
- package/README.md +3 -1
- package/package.json +1 -1
- package/run.js +28 -11
- package/samples/scripts/tp16.json +6 -0
- package/tests/nonTable.js +14 -2
- package/tests/textNodes.js +22 -24
- package/validation/executors/test.js +5 -21
- package/validation/tests/scripts/nonTable.json +28 -0
- package/validation/tests/scripts/textNodes.json +89 -0
- package/validation/tests/targets/elements/index.html +2 -2
- package/validation/tests/targets/nonTable/chime.m4a +0 -0
- package/validation/tests/targets/nonTable/gong.m4a +0 -0
- package/validation/tests/targets/nonTable/index.html +65 -0
- package/validation/tests/targets/textNodes/index.html +40 -0
package/README.md
CHANGED
|
@@ -103,7 +103,7 @@ A script is a JSON file with the properties:
|
|
|
103
103
|
}
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
The `timeLimit` property is optional. If it is omitted, a default of 300 seconds (5 minutes) is set.
|
|
106
|
+
The `timeLimit` property is optional. If it is omitted, a default of 300 seconds (5 minutes) is set.
|
|
107
107
|
|
|
108
108
|
### Example
|
|
109
109
|
|
|
@@ -444,6 +444,8 @@ That would state the expectation that the `result` property of the `acts` item f
|
|
|
444
444
|
|
|
445
445
|
The first item in each array is an identifier of a property within the `result` property. The item has the format of a string with `.` delimiters. Each `.`-delimited segment its the name of the next property in the hierarchy. If the current object is an array, the next segment must be a non-negative integer, representing the index of an element of the array. For example, `items.1.attributes.0` references the first element of the array that is the `attributes` property of the object that is the second element of the array that is the `items` property of `result`. (In JavaScript, this would be written `items[1].attributes[0]`, but in the `expect` property all property names are `.`-delimited.)
|
|
446
446
|
|
|
447
|
+
If there is only 1 item in an array, it states the expectation that the specified property does not exist. Otherwise, there are 3 items in the array.
|
|
448
|
+
|
|
447
449
|
The second item in each array, if there are 3 items in the array, is an operator, drawn from:
|
|
448
450
|
- `<`: less than
|
|
449
451
|
- `=`: equal to
|
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -65,7 +65,17 @@ const tests = {
|
|
|
65
65
|
};
|
|
66
66
|
// Tests that may change the DOM.
|
|
67
67
|
const domChangers = new Set([
|
|
68
|
-
'axe',
|
|
68
|
+
'axe',
|
|
69
|
+
'continuum',
|
|
70
|
+
'focAll',
|
|
71
|
+
'focInd',
|
|
72
|
+
'focOp',
|
|
73
|
+
'hover',
|
|
74
|
+
'htmlcs',
|
|
75
|
+
'ibm',
|
|
76
|
+
'menuNav',
|
|
77
|
+
'textNodes',
|
|
78
|
+
'wave'
|
|
69
79
|
]);
|
|
70
80
|
// Browser types available in PlayWright.
|
|
71
81
|
const browserTypeNames = {
|
|
@@ -557,23 +567,29 @@ const visit = async (act, page, isStrict) => {
|
|
|
557
567
|
};
|
|
558
568
|
// Returns a property value and whether it satisfies an expectation.
|
|
559
569
|
const isTrue = (object, specs) => {
|
|
560
|
-
let satisfied;
|
|
561
570
|
const property = specs[0];
|
|
562
571
|
const propertyTree = property.split('.');
|
|
563
|
-
const relation = specs[1];
|
|
564
|
-
const criterion = specs[2];
|
|
565
572
|
let actual = property.length ? object[propertyTree[0]] : object;
|
|
566
573
|
// Identify the actual value of the specified property.
|
|
567
574
|
while (propertyTree.length > 1 && actual !== undefined) {
|
|
568
575
|
propertyTree.shift();
|
|
569
576
|
actual = actual[propertyTree[0]];
|
|
570
577
|
}
|
|
571
|
-
|
|
572
|
-
|
|
578
|
+
// If the expectation is that the property does not exist:
|
|
579
|
+
if (specs.length === 1) {
|
|
580
|
+
// Return whether the expectation is satisfied.
|
|
581
|
+
return [actual, actual === undefined];
|
|
573
582
|
}
|
|
574
|
-
|
|
583
|
+
// Otherwise, i.e. if the expectation is of a property value:
|
|
584
|
+
else if (specs.length === 3) {
|
|
575
585
|
// Determine whether the expectation was fulfilled.
|
|
576
|
-
|
|
586
|
+
const relation = specs[1];
|
|
587
|
+
const criterion = specs[2];
|
|
588
|
+
let satisfied;
|
|
589
|
+
if (actual === undefined) {
|
|
590
|
+
return [null, false];
|
|
591
|
+
}
|
|
592
|
+
else if (relation === '=') {
|
|
577
593
|
satisfied = actual === criterion;
|
|
578
594
|
}
|
|
579
595
|
else if (relation === '<') {
|
|
@@ -591,11 +607,12 @@ const isTrue = (object, specs) => {
|
|
|
591
607
|
else if (relation === '!i') {
|
|
592
608
|
satisfied = ! actual.includes(criterion);
|
|
593
609
|
}
|
|
594
|
-
else if (! relation) {
|
|
595
|
-
satisfied = actual === undefined;
|
|
596
|
-
}
|
|
597
610
|
return [actual, satisfied];
|
|
598
611
|
}
|
|
612
|
+
// Otherwise, i.e. if the specifications are invalid:
|
|
613
|
+
else {
|
|
614
|
+
//
|
|
615
|
+
}
|
|
599
616
|
};
|
|
600
617
|
// Adds a wait error result to an act.
|
|
601
618
|
const waitError = (page, act, error, what) => {
|
|
@@ -113,6 +113,12 @@
|
|
|
113
113
|
"withItems": true,
|
|
114
114
|
"what": "keyboard navigation within true-focus menus"
|
|
115
115
|
},
|
|
116
|
+
{
|
|
117
|
+
"type": "test",
|
|
118
|
+
"which": "nonTable",
|
|
119
|
+
"withItems": true,
|
|
120
|
+
"what": "tables used for layout"
|
|
121
|
+
},
|
|
116
122
|
{
|
|
117
123
|
"type": "test",
|
|
118
124
|
"which": "radioSet",
|
package/tests/nonTable.js
CHANGED
|
@@ -4,17 +4,21 @@
|
|
|
4
4
|
This test reports tables used for layout.
|
|
5
5
|
*/
|
|
6
6
|
exports.reporter = async (page, withItems) => {
|
|
7
|
-
// Identify the
|
|
7
|
+
// Identify the tables used for layout.
|
|
8
8
|
const badTableTexts = await page.$$eval('table', tables => {
|
|
9
|
+
// Initialize an array of pseudotable texts.
|
|
9
10
|
const badTableTexts = [];
|
|
10
11
|
// FUNCTION DEFINITIONS START
|
|
11
12
|
// Returns a space-minimized copy of a string.
|
|
12
13
|
const compact = string => string.replace(/[\t\n]/g, '').replace(/\s{2,}/g, ' ').trim();
|
|
14
|
+
// Adds the first 100 characters of the code of a pseudotable to the array of pseudotable texts.
|
|
13
15
|
const addBad = table => {
|
|
14
16
|
badTableTexts.push(compact(table.outerHTML).slice(0, 100));
|
|
15
17
|
};
|
|
16
18
|
// FUNCTION DEFINITIONS END
|
|
19
|
+
// For each table on the page:
|
|
17
20
|
tables.forEach(table => {
|
|
21
|
+
// Ignore it if it has a grid or treegrid role, a caption, or a table-like element.
|
|
18
22
|
const role = table.getAttribute('role');
|
|
19
23
|
if (
|
|
20
24
|
table.caption
|
|
@@ -23,10 +27,13 @@ exports.reporter = async (page, withItems) => {
|
|
|
23
27
|
) {
|
|
24
28
|
return;
|
|
25
29
|
}
|
|
30
|
+
// Otherwise, if the table contains another table:
|
|
26
31
|
else if (table.querySelector('table')) {
|
|
32
|
+
// Treat it as a pseudotable.
|
|
27
33
|
addBad(table);
|
|
28
34
|
return;
|
|
29
35
|
}
|
|
36
|
+
// Otherwise, if the table has only 1 row or 1 column:
|
|
30
37
|
else if (
|
|
31
38
|
table.querySelectorAll('tr').length === 1
|
|
32
39
|
|| Math.max(
|
|
@@ -35,18 +42,23 @@ exports.reporter = async (page, withItems) => {
|
|
|
35
42
|
.map(row => Array.from(row.querySelectorAll('td')).length)
|
|
36
43
|
) === 1
|
|
37
44
|
) {
|
|
45
|
+
// Treat it as a pseudotable.
|
|
38
46
|
addBad(table);
|
|
39
47
|
return;
|
|
40
48
|
}
|
|
49
|
+
// Otherwise, if the table contains an object or player:
|
|
41
50
|
else if (table.querySelector('object, embed, applet, audio, video')) {
|
|
51
|
+
// Treat it as a pseudotable.
|
|
42
52
|
addBad(table);
|
|
43
53
|
return;
|
|
44
54
|
}
|
|
45
55
|
});
|
|
56
|
+
// Return the array of pseudotable text beginnings.
|
|
46
57
|
return badTableTexts;
|
|
47
58
|
});
|
|
59
|
+
// Return the result.
|
|
48
60
|
const data = {
|
|
49
|
-
|
|
61
|
+
total: badTableTexts.length
|
|
50
62
|
};
|
|
51
63
|
if (withItems) {
|
|
52
64
|
data.items = badTableTexts;
|
package/tests/textNodes.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
This test reports data about specified text nodes.
|
|
4
4
|
Meanings of detailLevel values:
|
|
5
5
|
0. Only total node count; no detail.
|
|
6
|
-
1
|
|
6
|
+
1-3. Count of ancestry levels to provide data on (1 = text node, 2 = also parent,
|
|
7
|
+
3 = also grandparent)
|
|
7
8
|
*/
|
|
8
|
-
exports.reporter = async (page, detailLevel, text) => {
|
|
9
|
+
exports.reporter = async (page, detailLevel, text = '') => {
|
|
9
10
|
let data = {};
|
|
10
11
|
// Get the data on the text nodes.
|
|
11
12
|
try {
|
|
@@ -13,14 +14,10 @@ exports.reporter = async (page, detailLevel, text) => {
|
|
|
13
14
|
const detailLevel = args[0];
|
|
14
15
|
const text = args[1];
|
|
15
16
|
const matchNodes = [];
|
|
16
|
-
//
|
|
17
|
+
// Collapse any adjacent text nodes.
|
|
17
18
|
document.body.normalize();
|
|
18
|
-
//
|
|
19
|
-
const
|
|
20
|
-
// Insert it into the document.
|
|
21
|
-
document.body.appendChild(tempBody);
|
|
22
|
-
// Remove the irrelevant text content from the copy.
|
|
23
|
-
const extraElements = Array.from(tempBody.querySelectorAll('style, script, svg'));
|
|
19
|
+
// Remove the irrelevant text content.
|
|
20
|
+
const extraElements = Array.from(document.body.querySelectorAll('style, script, svg'));
|
|
24
21
|
extraElements.forEach(element => {
|
|
25
22
|
element.textContent = '';
|
|
26
23
|
});
|
|
@@ -28,8 +25,11 @@ exports.reporter = async (page, detailLevel, text) => {
|
|
|
28
25
|
// Compacts a string.
|
|
29
26
|
const compact = string => string.replace(/\s+/g, ' ').trim();
|
|
30
27
|
// Compacts and lower-cases a string.
|
|
31
|
-
const
|
|
32
|
-
|
|
28
|
+
const standardize = string => compact(string).toLowerCase();
|
|
29
|
+
/*
|
|
30
|
+
Gets data (tagName, text if specified, attributes, refLabels, labels, and children)
|
|
31
|
+
on an element.
|
|
32
|
+
*/
|
|
33
33
|
const getElementData = (element, withText) => {
|
|
34
34
|
// Initialize the data.
|
|
35
35
|
const data = {
|
|
@@ -80,15 +80,16 @@ exports.reporter = async (page, detailLevel, text) => {
|
|
|
80
80
|
return data;
|
|
81
81
|
};
|
|
82
82
|
// FUNCTION DEFINITIONS END
|
|
83
|
-
const
|
|
83
|
+
const stdText = standardize(text);
|
|
84
84
|
// Create a collection of the text nodes.
|
|
85
|
-
const walker = document.createTreeWalker(
|
|
85
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
|
|
86
86
|
// Get their count.
|
|
87
87
|
const data = {nodeCount: 0};
|
|
88
88
|
let more = true;
|
|
89
89
|
while(more) {
|
|
90
90
|
if (walker.nextNode()) {
|
|
91
|
-
|
|
91
|
+
const stdCurrent = standardize(walker.currentNode.nodeValue);
|
|
92
|
+
if (stdCurrent.includes(stdText)) {
|
|
92
93
|
data.nodeCount++;
|
|
93
94
|
matchNodes.push(walker.currentNode);
|
|
94
95
|
}
|
|
@@ -97,27 +98,25 @@ exports.reporter = async (page, detailLevel, text) => {
|
|
|
97
98
|
more = false;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
// If
|
|
101
|
-
if (detailLevel
|
|
102
|
-
// Return the node count.
|
|
103
|
-
return data;
|
|
104
|
-
}
|
|
105
|
-
// Otherwise, i.e. if itemization is required:
|
|
106
|
-
else {
|
|
101
|
+
// If itemization is required:
|
|
102
|
+
if (detailLevel > 0) {
|
|
107
103
|
// Initialize the item data.
|
|
108
104
|
data.items = [];
|
|
109
|
-
// For each text node matching
|
|
105
|
+
// For each text node matching any specified text:
|
|
110
106
|
matchNodes.forEach(node => {
|
|
111
107
|
// Initialize the data on it.
|
|
112
108
|
const itemData = {text: compact(node.nodeValue)};
|
|
113
109
|
// If ancestral itemization is required:
|
|
114
110
|
if (detailLevel > 1) {
|
|
115
|
-
// Add the ancestral data to the item data.
|
|
111
|
+
// Add the ancestral data, starting with the parent, to the item data.
|
|
116
112
|
itemData.ancestors = [];
|
|
117
113
|
let base = node;
|
|
118
114
|
let currentLevel = 1;
|
|
115
|
+
// For each specified ancestral distance:
|
|
119
116
|
while(currentLevel++ < detailLevel) {
|
|
117
|
+
// Add data on it to the data on the text node.
|
|
120
118
|
const newBase = base.parentElement;
|
|
119
|
+
// Omit the text of the text node if the ancestor is its parent.
|
|
121
120
|
itemData.ancestors.push(getElementData(newBase, currentLevel > 2));
|
|
122
121
|
base = newBase;
|
|
123
122
|
}
|
|
@@ -126,7 +125,6 @@ exports.reporter = async (page, detailLevel, text) => {
|
|
|
126
125
|
data.items.push(itemData);
|
|
127
126
|
});
|
|
128
127
|
}
|
|
129
|
-
document.body.removeChild(tempBody);
|
|
130
128
|
return data;
|
|
131
129
|
}, [detailLevel, text]);
|
|
132
130
|
}
|
|
@@ -6,10 +6,6 @@ const fs = require('fs').promises;
|
|
|
6
6
|
const {handleRequest} = require(`${__dirname}/../../run`);
|
|
7
7
|
const test = process.argv[2];
|
|
8
8
|
const validateTests = async () => {
|
|
9
|
-
const totals = {
|
|
10
|
-
attempts: 0,
|
|
11
|
-
successes: 0
|
|
12
|
-
};
|
|
13
9
|
const scriptFileNames = await fs.readdir(`${__dirname}/../tests/scripts`);
|
|
14
10
|
for (const scriptFileName of scriptFileNames.filter(fileName => fileName === `${test}.json`)) {
|
|
15
11
|
const rawScriptJSON = await fs
|
|
@@ -29,37 +25,25 @@ const validateTests = async () => {
|
|
|
29
25
|
console.log('Failure: Log empty or invalid');
|
|
30
26
|
console.log(JSON.stringify(log, null, 2));
|
|
31
27
|
}
|
|
28
|
+
const testActs = acts.filter(act => act.type && act.type === 'test');
|
|
32
29
|
if (
|
|
33
|
-
|
|
34
|
-
&&
|
|
35
|
-
act => act.type && act.type === 'test'
|
|
36
|
-
? act.result && act.result.failureCount !== undefined
|
|
37
|
-
: true
|
|
38
|
-
)
|
|
30
|
+
testActs.length === script.commands.filter(cmd => cmd.type === 'test').length
|
|
31
|
+
&& testActs.every(testAct => testAct.result && testAct.result.failureCount !== undefined)
|
|
39
32
|
) {
|
|
40
|
-
totals.attempts++;
|
|
41
|
-
totals.successes++;
|
|
42
33
|
console.log('Success: Reports have been correctly populated');
|
|
43
|
-
if (
|
|
44
|
-
act => act.type === 'test' ? act.result.failureCount === 0 : true
|
|
45
|
-
)) {
|
|
46
|
-
totals.attempts++;
|
|
47
|
-
totals.successes++;
|
|
34
|
+
if (testActs.every(testAct => testAct.result.failureCount === 0)) {
|
|
48
35
|
console.log('Success: No failures');
|
|
49
36
|
}
|
|
50
37
|
else {
|
|
51
|
-
|
|
52
|
-
console.log('Failure: At least one test has at least one failure');
|
|
38
|
+
console.log('Failure: The test has at least one failure');
|
|
53
39
|
console.log(JSON.stringify(acts, null, 2));
|
|
54
40
|
}
|
|
55
41
|
}
|
|
56
42
|
else {
|
|
57
|
-
totals.attempts++;
|
|
58
43
|
console.log('Failure: Reports empty or invalid');
|
|
59
44
|
console.log(JSON.stringify(acts, null, 2));
|
|
60
45
|
}
|
|
61
46
|
}
|
|
62
|
-
console.log(`Grand totals: attempts ${totals.attempts}, successes ${totals.successes}`);
|
|
63
47
|
return Promise.resolve('');
|
|
64
48
|
};
|
|
65
49
|
validateTests()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"what": "validation of nonTable test",
|
|
3
|
+
"strict": true,
|
|
4
|
+
"commands": [
|
|
5
|
+
{
|
|
6
|
+
"type": "launch",
|
|
7
|
+
"which": "chromium",
|
|
8
|
+
"what": "usual browser"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"type": "url",
|
|
12
|
+
"which": "__targets__/nonTable/index.html",
|
|
13
|
+
"what": "page with a real table and 3 pseudotables"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "test",
|
|
17
|
+
"which": "nonTable",
|
|
18
|
+
"what": "tables used for layout",
|
|
19
|
+
"withItems": true,
|
|
20
|
+
"expect": [
|
|
21
|
+
["total", "=", 3],
|
|
22
|
+
["items.0", "i", "Unit"],
|
|
23
|
+
["items.1", "i", "Sales"],
|
|
24
|
+
["items.2", "i", "Chime"]
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"what": "validation of elements test",
|
|
3
|
+
"strict": true,
|
|
4
|
+
"commands": [
|
|
5
|
+
{
|
|
6
|
+
"type": "launch",
|
|
7
|
+
"which": "chromium",
|
|
8
|
+
"what": "usual browser"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"type": "url",
|
|
12
|
+
"which": "__targets__/textNodes/index.html",
|
|
13
|
+
"what": "page with a shadow root"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "test",
|
|
17
|
+
"which": "textNodes",
|
|
18
|
+
"what": "text nodes",
|
|
19
|
+
"detailLevel": 0,
|
|
20
|
+
"expect": [
|
|
21
|
+
["nodeCount", "=", 35]
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "test",
|
|
26
|
+
"which": "textNodes",
|
|
27
|
+
"what": "text nodes",
|
|
28
|
+
"detailLevel": 0,
|
|
29
|
+
"text": "alia",
|
|
30
|
+
"expect": [
|
|
31
|
+
["nodeCount", "=", 2]
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "test",
|
|
36
|
+
"which": "textNodes",
|
|
37
|
+
"what": "text nodes",
|
|
38
|
+
"detailLevel": 1,
|
|
39
|
+
"text": "alia",
|
|
40
|
+
"expect": [
|
|
41
|
+
["nodeCount", "=", 2],
|
|
42
|
+
["items.0.text", "=", "Io alia"]
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "test",
|
|
47
|
+
"which": "textNodes",
|
|
48
|
+
"what": "text nodes",
|
|
49
|
+
"detailLevel": 2,
|
|
50
|
+
"text": "This is the",
|
|
51
|
+
"expect": [
|
|
52
|
+
["nodeCount", "=", 2],
|
|
53
|
+
["items.0.text", "=", "This is the first button"],
|
|
54
|
+
["items.1.text", "=", "This is the second button"],
|
|
55
|
+
["items.0.ancestors.0.tagName", "=", "BUTTON"],
|
|
56
|
+
["items.1.ancestors.0.tagName", "=", "BUTTON"],
|
|
57
|
+
["items.0.ancestors.0.attributes.0.name", "=", "id"],
|
|
58
|
+
["items.0.ancestors.0.attributes.0.value", "=", "button0"],
|
|
59
|
+
["items.1.ancestors.0.attributes.1.name", "=", "aria-labelledby"],
|
|
60
|
+
["items.1.ancestors.0.attributes.1.value", "=", "button1Label"],
|
|
61
|
+
["items.0.ancestors.0.refLabels"],
|
|
62
|
+
["items.1.ancestors.0.refLabels.0", "=", "Click the second button."],
|
|
63
|
+
["items.0.ancestors.0.labels.0", "=", "Click the first button."],
|
|
64
|
+
["items.0.ancestors.0.labels.1", "=", "Did you click it?"],
|
|
65
|
+
["items.1.ancestors.0.labels"],
|
|
66
|
+
["items.0.ancestors.0.children"]
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"type": "test",
|
|
71
|
+
"which": "textNodes",
|
|
72
|
+
"what": "text nodes",
|
|
73
|
+
"detailLevel": 3,
|
|
74
|
+
"text": "tute alia",
|
|
75
|
+
"expect": [
|
|
76
|
+
["nodeCount", "=", 1],
|
|
77
|
+
["items.0.text", "=", "Io tute alia"],
|
|
78
|
+
["items.0.ancestors.0.tagName", "=", "LI"],
|
|
79
|
+
["items.0.ancestors.1.tagName", "=", "UL"],
|
|
80
|
+
["items.0.ancestors.0.attributes.0.name", "=", "class"],
|
|
81
|
+
["items.0.ancestors.0.attributes.0.value", "=", "last"],
|
|
82
|
+
["items.0.ancestors.1.attributes.0.name", "=", "lang"],
|
|
83
|
+
["items.0.ancestors.1.attributes.0.value", "=", "eo"],
|
|
84
|
+
["items.0.ancestors.1.children.1.tagName", "=", "LI"],
|
|
85
|
+
["items.0.ancestors.1.children.2.attributes.1.name", "=", "hidden"]
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
<html lang="en-US">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
|
-
<title>Page</title>
|
|
5
|
+
<title>Page for elements test validation</title>
|
|
6
6
|
<meta name="description" content="tester">
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<main>
|
|
11
|
-
<h1>Page</h1>
|
|
11
|
+
<h1>Page for elements test validation</h1>
|
|
12
12
|
<h2>Main part</h2>
|
|
13
13
|
<p class="first">This is a paragraph.</p>
|
|
14
14
|
<p>This is a list:</p>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en-US">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Page with a real table and pseudotables</title>
|
|
6
|
+
<meta name="description" content="tester">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
+
<style>
|
|
9
|
+
table {
|
|
10
|
+
border-collapse: collapse;
|
|
11
|
+
}
|
|
12
|
+
td, th {
|
|
13
|
+
padding: 0.3rem;
|
|
14
|
+
border: 0.2rem black solid;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<main>
|
|
20
|
+
<h1>Page with a real table and pseudotables</h1>
|
|
21
|
+
<h2>Real table</h2>
|
|
22
|
+
<table>
|
|
23
|
+
<caption>Personnel</caption>
|
|
24
|
+
<thead>
|
|
25
|
+
<tr><th>Name</th><th>Department</th></tr>
|
|
26
|
+
</thead>
|
|
27
|
+
<tbody>
|
|
28
|
+
<tr><th>Amy</th><td>Accessibility</td></tr>
|
|
29
|
+
<tr><th>Abe</th><td>Marketing</td></tr>
|
|
30
|
+
</tbody>
|
|
31
|
+
</table>
|
|
32
|
+
<h2>Pseudotables 0 and 1: personnel</h2>
|
|
33
|
+
<table>
|
|
34
|
+
<tr><td>Given name</td><td>Unit</td></tr>
|
|
35
|
+
<tr><td>Kim</td><td>Usability</td></tr>
|
|
36
|
+
<tr><td>Ken</td><td><table><tr><td>Advertising</td><td>Sales</td></tr></table></td></tr>
|
|
37
|
+
</table>
|
|
38
|
+
<h2>Pseudotable 2: ringtones</h2>
|
|
39
|
+
<table>
|
|
40
|
+
<tr>
|
|
41
|
+
<td>Chime</td>
|
|
42
|
+
<td>
|
|
43
|
+
<object
|
|
44
|
+
title="chime"
|
|
45
|
+
type="audio/mp4"
|
|
46
|
+
data="chime.m4a"
|
|
47
|
+
>
|
|
48
|
+
</object>
|
|
49
|
+
</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<tr>
|
|
52
|
+
<td>Gong</td>
|
|
53
|
+
<td>
|
|
54
|
+
<object
|
|
55
|
+
title="gong"
|
|
56
|
+
type="audio/mp4"
|
|
57
|
+
data="gong.m4a"
|
|
58
|
+
>
|
|
59
|
+
</object>
|
|
60
|
+
</td>
|
|
61
|
+
</tr>
|
|
62
|
+
</table>
|
|
63
|
+
</main>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en-US">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Page for textNodes test validation</title>
|
|
6
|
+
<meta name="description" content="tester">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<main>
|
|
11
|
+
<h1>Page for textNodes test validation</h1>
|
|
12
|
+
<h2>Main part</h2>
|
|
13
|
+
<p class="first">This is a paragraph.</p>
|
|
14
|
+
<p>This is a list:</p>
|
|
15
|
+
<ul lang="eo">
|
|
16
|
+
<li class="first">Io</li>
|
|
17
|
+
<li>Io alia</li>
|
|
18
|
+
<li class="last" hidden>Io tute alia</li>
|
|
19
|
+
</ul>
|
|
20
|
+
<h2>Auxiliary part</h2>
|
|
21
|
+
<p>This is a summary.</p>
|
|
22
|
+
<div id="host"></div>
|
|
23
|
+
<div id="guest">
|
|
24
|
+
<h3>Details</h3>
|
|
25
|
+
<p class="sole">Here are some details.</p>
|
|
26
|
+
</div>
|
|
27
|
+
<label for="button0">Click the first button.</label>
|
|
28
|
+
<button id="button0" type="button">This is the first button</button>
|
|
29
|
+
<label for="button0">Did you click it?</label>
|
|
30
|
+
<p id="button1Label">Click the second button.</p>
|
|
31
|
+
<button type="button" aria-labelledby="button1Label">This is the second button</button>
|
|
32
|
+
</main>
|
|
33
|
+
<script>
|
|
34
|
+
document
|
|
35
|
+
.getElementById('host')
|
|
36
|
+
.attachShadow({mode: 'open'})
|
|
37
|
+
.appendChild(document.getElementById('guest'));
|
|
38
|
+
</script>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|