testaro 5.5.7 → 5.5.8
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/create.js +13 -4
- package/package.json +1 -1
- package/run.js +16 -7
- package/tests/radioSet.js +25 -15
- package/tests/tabNav.js +61 -53
- package/tests/tenon.js +7 -4
package/create.js
CHANGED
|
@@ -59,19 +59,27 @@ const runHosts = async (timeStamp, specs) => {
|
|
|
59
59
|
stdio: [0, 1, 'ignore', 'ipc']
|
|
60
60
|
}
|
|
61
61
|
);
|
|
62
|
+
let runMoreTimer = null;
|
|
62
63
|
// If the child process times out:
|
|
63
64
|
const timer = setTimeout(async () => {
|
|
64
65
|
clearTimeout(timer);
|
|
65
66
|
// Record the host as timed out.
|
|
66
67
|
timeoutHosts.push(id);
|
|
67
68
|
// Kill the child process.
|
|
68
|
-
subprocess.kill();
|
|
69
|
+
subprocess.kill('SIGKILL');
|
|
69
70
|
console.log(`Script for host ${id} exceeded ${timeLimit}-second time limit, so was killed`);
|
|
70
|
-
// Run the remaining host scripts.
|
|
71
|
-
|
|
71
|
+
// Run the remaining host scripts after a 10-second wait.
|
|
72
|
+
runMoreTimer = setTimeout(async () => {
|
|
73
|
+
clearTimeout(runMoreTimer);
|
|
74
|
+
if (! (successHosts.includes(id) || crashHosts.includes(id))) {
|
|
75
|
+
console.log('Continuing with the remaining host scripts');
|
|
76
|
+
await runHosts(timeStamp, specs);
|
|
77
|
+
}
|
|
78
|
+
}, 10000);
|
|
72
79
|
}, 1000 * (script.timeLimit || timeLimit));
|
|
73
80
|
// If the child process succeeds:
|
|
74
81
|
subprocess.on('message', async message => {
|
|
82
|
+
clearTimeout(runMoreTimer);
|
|
75
83
|
clearTimeout(timer);
|
|
76
84
|
// Save its report as a file.
|
|
77
85
|
await fs.writeFile(`${reportDir}/${id}.json`, message);
|
|
@@ -83,8 +91,9 @@ const runHosts = async (timeStamp, specs) => {
|
|
|
83
91
|
});
|
|
84
92
|
// If the child process ends:
|
|
85
93
|
subprocess.on('exit', async () => {
|
|
86
|
-
// If
|
|
94
|
+
// If its end was not due to success or a timeout:
|
|
87
95
|
if (! (successHosts.includes(id) || timeoutHosts.includes(id))) {
|
|
96
|
+
clearTimeout(runMoreTimer);
|
|
88
97
|
clearTimeout(timer);
|
|
89
98
|
crashHosts.push(id);
|
|
90
99
|
console.log(`Script for host ${id} crashed`);
|
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -634,6 +634,15 @@ const wait = ms => {
|
|
|
634
634
|
}, ms);
|
|
635
635
|
});
|
|
636
636
|
};
|
|
637
|
+
// Adds an error result to an act.
|
|
638
|
+
const addError = (act, error) => {
|
|
639
|
+
act.result = {
|
|
640
|
+
error
|
|
641
|
+
};
|
|
642
|
+
if (act.type === 'test') {
|
|
643
|
+
act.result.prevented = true;
|
|
644
|
+
}
|
|
645
|
+
};
|
|
637
646
|
// Recursively performs the acts in a report.
|
|
638
647
|
const doActs = async (report, actIndex, page) => {
|
|
639
648
|
process.on('message', message => {
|
|
@@ -761,11 +770,11 @@ const doActs = async (report, actIndex, page) => {
|
|
|
761
770
|
)
|
|
762
771
|
.catch(error => {
|
|
763
772
|
console.log(`ERROR waiting for page to be ${act.which} (${error.message})`);
|
|
764
|
-
act
|
|
773
|
+
addError(act, `ERROR waiting for page to be ${act.which}`);
|
|
765
774
|
actIndex = -2;
|
|
766
775
|
});
|
|
767
776
|
if (actIndex > -2) {
|
|
768
|
-
|
|
777
|
+
addError(`Page became ${act.which}`);
|
|
769
778
|
}
|
|
770
779
|
}
|
|
771
780
|
// Otherwise, if the act is a page switch:
|
|
@@ -977,7 +986,7 @@ const doActs = async (report, actIndex, page) => {
|
|
|
977
986
|
await matchingElement.waitForElementState('stable', {timeout: 2000})
|
|
978
987
|
.catch(error => {
|
|
979
988
|
console.log(`ERROR waiting for stable ${act.type} (${error.message})`);
|
|
980
|
-
act
|
|
989
|
+
addError(act, `ERROR waiting for stable ${act.type}`);
|
|
981
990
|
});
|
|
982
991
|
if (! act.result) {
|
|
983
992
|
const isEnabled = await matchingElement.isEnabled();
|
|
@@ -988,7 +997,7 @@ const doActs = async (report, actIndex, page) => {
|
|
|
988
997
|
})
|
|
989
998
|
.catch(error => {
|
|
990
999
|
console.log(`ERROR checking ${act.type} (${error.message})`);
|
|
991
|
-
act
|
|
1000
|
+
addError(act, `ERROR checking ${act.type}`);
|
|
992
1001
|
});
|
|
993
1002
|
if (! act.result) {
|
|
994
1003
|
act.result = 'checked';
|
|
@@ -1250,19 +1259,19 @@ const doActs = async (report, actIndex, page) => {
|
|
|
1250
1259
|
// Otherwise, i.e. if redirection is prohibited but occurred:
|
|
1251
1260
|
else {
|
|
1252
1261
|
// Add the error result to the act.
|
|
1253
|
-
act
|
|
1262
|
+
addError(act, `ERROR: Page URL wrong (${url})`);
|
|
1254
1263
|
}
|
|
1255
1264
|
}
|
|
1256
1265
|
// Otherwise, i.e. if the required page URL does not exist:
|
|
1257
1266
|
else {
|
|
1258
1267
|
// Add an error result to the act.
|
|
1259
|
-
act
|
|
1268
|
+
addError(act, 'ERROR: Page has no URL');
|
|
1260
1269
|
}
|
|
1261
1270
|
}
|
|
1262
1271
|
// Otherwise, i.e. if no page exists:
|
|
1263
1272
|
else {
|
|
1264
1273
|
// Add an error result to the act.
|
|
1265
|
-
act
|
|
1274
|
+
addError(act, 'ERROR: No page identified');
|
|
1266
1275
|
}
|
|
1267
1276
|
}
|
|
1268
1277
|
// Otherwise, i.e. if the command is invalid:
|
package/tests/radioSet.js
CHANGED
|
@@ -66,22 +66,32 @@ exports.reporter = async (page, withItems) => {
|
|
|
66
66
|
}
|
|
67
67
|
return radios;
|
|
68
68
|
}, []);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
if (setRadios) {
|
|
70
|
+
// Get an array of all radio buttons.
|
|
71
|
+
const allRadios = Array.from(document.body.querySelectorAll('input[type=radio'));
|
|
72
|
+
// Tabulate the results.
|
|
73
|
+
const totals = data.totals;
|
|
74
|
+
totals.total = allRadios.length;
|
|
75
|
+
totals.inSet = setRadios.length;
|
|
76
|
+
totals.percent = totals.total ? Math.floor(100 * totals.inSet / totals.total) : 'N.A.';
|
|
77
|
+
// If itemization is required:
|
|
78
|
+
if (withItems) {
|
|
79
|
+
// Add it to the results.
|
|
80
|
+
const nonSetRadios = allRadios.filter(radio => ! setRadios.includes(radio));
|
|
81
|
+
const items = data.items;
|
|
82
|
+
items.inSet = setRadios.map(radio => textOf(radio));
|
|
83
|
+
items.notInSet = nonSetRadios.map(radio => textOf(radio));
|
|
84
|
+
}
|
|
85
|
+
return {result: data};
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
return {
|
|
89
|
+
result: {
|
|
90
|
+
prevented: true,
|
|
91
|
+
error: 'ERROR identifying homogeneous field sets'
|
|
92
|
+
}
|
|
93
|
+
};
|
|
83
94
|
}
|
|
84
|
-
return {result: data};
|
|
85
95
|
}, args);
|
|
86
96
|
return await dataJSHandle.jsonValue();
|
|
87
97
|
};
|
package/tests/tabNav.js
CHANGED
|
@@ -92,84 +92,92 @@ exports.reporter = async (page, withItems) => {
|
|
|
92
92
|
const testKey = async (
|
|
93
93
|
tabs, tabElement, keyName, keyProp, goodIndex, elementIsCorrect, itemData
|
|
94
94
|
) => {
|
|
95
|
-
let pressed = true;
|
|
96
|
-
// Click the tab element, to make the focus on it effective.
|
|
97
|
-
await tabElement.click({
|
|
98
|
-
timeout: 500
|
|
99
|
-
})
|
|
100
|
-
.catch(async error => {
|
|
101
|
-
await tabElement.click({
|
|
102
|
-
force: true
|
|
103
|
-
});
|
|
104
|
-
})
|
|
105
|
-
.catch(error => {
|
|
106
|
-
console.log(
|
|
107
|
-
`ERROR clicking tab element ${itemData.text} (${error.message.replace(/\n.+/s, '')})`
|
|
108
|
-
);
|
|
109
|
-
pressed = false;
|
|
110
|
-
});
|
|
111
|
-
// Increment the counts of navigations and key navigations.
|
|
112
|
-
data.totals.navigations.all.total++;
|
|
113
|
-
data.totals.navigations.specific[keyProp].total++;
|
|
114
95
|
const {navigationErrors} = itemData;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
//
|
|
118
|
-
await tabElement.
|
|
119
|
-
timeout:
|
|
96
|
+
if (navigationErrors) {
|
|
97
|
+
let pressed = true;
|
|
98
|
+
// Click the tab element, to make the focus on it effective.
|
|
99
|
+
await tabElement.click({
|
|
100
|
+
timeout: 500
|
|
101
|
+
})
|
|
102
|
+
.catch(async error => {
|
|
103
|
+
console.log(
|
|
104
|
+
`ERROR clicking tab element ${itemData.text} (${error.message.replace(/\n.+/s, '')})`
|
|
105
|
+
);
|
|
106
|
+
await tabElement.click({
|
|
107
|
+
force: true
|
|
108
|
+
});
|
|
120
109
|
})
|
|
121
110
|
.catch(error => {
|
|
122
|
-
console.log(
|
|
111
|
+
console.log(
|
|
112
|
+
`ERROR force-clicking tab element ${itemData.text} (${error.message.replace(/\n.+/s, '')})`
|
|
113
|
+
);
|
|
123
114
|
pressed = false;
|
|
124
115
|
});
|
|
125
|
-
//
|
|
116
|
+
// Increment the counts of navigations and key navigations.
|
|
117
|
+
data.totals.navigations.all.total++;
|
|
118
|
+
data.totals.navigations.specific[keyProp].total++;
|
|
119
|
+
// If the click succeeded:
|
|
126
120
|
if (pressed) {
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
121
|
+
// Refocus the tab element and press the specified key (page.keyboard.press may fail).
|
|
122
|
+
await tabElement.press(keyName, {
|
|
123
|
+
timeout: 1000
|
|
124
|
+
})
|
|
125
|
+
.catch(error => {
|
|
126
|
+
console.log(`ERROR: could not press ${keyName} (${error.message})`);
|
|
127
|
+
pressed = false;
|
|
128
|
+
});
|
|
129
|
+
// If the refocus and keypress succeeded:
|
|
130
|
+
if (pressed) {
|
|
131
|
+
// Identify which tab element is now focused, if any.
|
|
132
|
+
const focusIndex = await focusedTab(tabs);
|
|
133
|
+
// If the focus is correct:
|
|
134
|
+
if (focusIndex === goodIndex) {
|
|
135
|
+
// Increment the counts of correct navigations and correct key navigations.
|
|
136
|
+
data.totals.navigations.all.correct++;
|
|
137
|
+
data.totals.navigations.specific[keyProp].correct++;
|
|
138
|
+
}
|
|
139
|
+
// Otherwise, i.e. if the focus is incorrect:
|
|
140
|
+
else {
|
|
141
|
+
// Increment the counts of incorrect navigations and incorrect key navigations.
|
|
142
|
+
data.totals.navigations.all.incorrect++;
|
|
143
|
+
data.totals.navigations.specific[keyProp].incorrect++;
|
|
144
|
+
// Update the element status to incorrect.
|
|
145
|
+
elementIsCorrect = false;
|
|
146
|
+
// If itemization is required:
|
|
147
|
+
if (withItems) {
|
|
148
|
+
// Update the element report.
|
|
149
|
+
navigationErrors.push(keyName);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return elementIsCorrect;
|
|
134
153
|
}
|
|
135
|
-
// Otherwise, i.e. if the
|
|
154
|
+
// Otherwise, i.e. if the refocus or keypress failed:
|
|
136
155
|
else {
|
|
137
156
|
// Increment the counts of incorrect navigations and incorrect key navigations.
|
|
138
157
|
data.totals.navigations.all.incorrect++;
|
|
139
158
|
data.totals.navigations.specific[keyProp].incorrect++;
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
// If itemization is required:
|
|
143
|
-
if (withItems) {
|
|
159
|
+
// If itemization is required and a focus failure has not yet been reported:
|
|
160
|
+
if (withItems && ! navigationErrors.includes('focus')) {
|
|
144
161
|
// Update the element report.
|
|
145
|
-
navigationErrors.push(
|
|
162
|
+
navigationErrors.push('focus');
|
|
146
163
|
}
|
|
164
|
+
return false;
|
|
147
165
|
}
|
|
148
|
-
return elementIsCorrect;
|
|
149
166
|
}
|
|
150
|
-
// Otherwise, i.e. if the
|
|
167
|
+
// Otherwise, i.e. if the click failed:
|
|
151
168
|
else {
|
|
152
169
|
// Increment the counts of incorrect navigations and incorrect key navigations.
|
|
153
170
|
data.totals.navigations.all.incorrect++;
|
|
154
171
|
data.totals.navigations.specific[keyProp].incorrect++;
|
|
155
|
-
// If itemization is required and a
|
|
156
|
-
if (withItems && ! navigationErrors.includes('
|
|
172
|
+
// If itemization is required and a click failure has not yet been reported:
|
|
173
|
+
if (withItems && ! navigationErrors.includes('click')) {
|
|
157
174
|
// Update the element report.
|
|
158
|
-
navigationErrors.push('
|
|
175
|
+
navigationErrors.push('click');
|
|
159
176
|
}
|
|
160
177
|
return false;
|
|
161
178
|
}
|
|
162
179
|
}
|
|
163
|
-
// Otherwise, i.e. if the click failed:
|
|
164
180
|
else {
|
|
165
|
-
// Increment the counts of incorrect navigations and incorrect key navigations.
|
|
166
|
-
data.totals.navigations.all.incorrect++;
|
|
167
|
-
data.totals.navigations.specific[keyProp].incorrect++;
|
|
168
|
-
// If itemization is required and a click failure has not yet been reported:
|
|
169
|
-
if (withItems && ! navigationErrors.includes('click')) {
|
|
170
|
-
// Update the element report.
|
|
171
|
-
navigationErrors.push('click');
|
|
172
|
-
}
|
|
173
181
|
return false;
|
|
174
182
|
}
|
|
175
183
|
};
|
package/tests/tenon.js
CHANGED
|
@@ -98,10 +98,13 @@ exports.reporter = async (tenonData, id) => {
|
|
|
98
98
|
}
|
|
99
99
|
// Otherwise, i.e. if the test is still running or failed:
|
|
100
100
|
else {
|
|
101
|
-
return {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
return {
|
|
102
|
+
result: {
|
|
103
|
+
prevented: true,
|
|
104
|
+
error: 'ERROR: Tenon test stalled or crashed',
|
|
105
|
+
status
|
|
106
|
+
}
|
|
107
|
+
};
|
|
105
108
|
}
|
|
106
109
|
}
|
|
107
110
|
// Otherwise, if the test is still running after a wait for its status:
|