testaro 76.2.2 → 77.0.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/README.md +33 -1
- package/package.json +1 -1
- package/procs/doActs.js +30 -1
- package/run.js +25 -0
package/README.md
CHANGED
|
@@ -209,18 +209,50 @@ The act types and their options are documented in the `etc` property of the [act
|
|
|
209
209
|
|
|
210
210
|
### Job as an object
|
|
211
211
|
|
|
212
|
+
#### Simple execution
|
|
213
|
+
|
|
212
214
|
An application can execute a job with:
|
|
213
215
|
|
|
214
216
|
```javascript
|
|
215
217
|
const {doJob} = require('testaro/run');
|
|
218
|
+
// Perform the job, which adds content to the job, making it a report.
|
|
216
219
|
doJob(job)
|
|
217
220
|
.then(report => {
|
|
218
|
-
//
|
|
221
|
+
// Optionally, modify the report.
|
|
219
222
|
…
|
|
220
223
|
return report;
|
|
221
224
|
});
|
|
222
225
|
```
|
|
223
226
|
|
|
227
|
+
#### Execution with observability
|
|
228
|
+
|
|
229
|
+
If the application is capable of listening for events while a job is being executed, it is possible to do that by passing a second argument to `doJob`:
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
const {doJob} = require('testaro/run');
|
|
233
|
+
// Perform the job, which adds content to the job, making it a report.
|
|
234
|
+
doJob(job, {
|
|
235
|
+
onProgress: event => {
|
|
236
|
+
// Handle the event. For example:
|
|
237
|
+
console.log(event);
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
.then(report => {
|
|
241
|
+
// Optionally, modify the report.
|
|
242
|
+
…
|
|
243
|
+
return report;
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Testaro emits events during job execution that allow an application to monitor progress. The events are:
|
|
248
|
+
|
|
249
|
+
- `jobStart` - Emitted when a job starts.
|
|
250
|
+
- `catalogStart` - Emitted when catalog compilation starts.
|
|
251
|
+
- `catalogEnd` - Emitted when catalog compilation ends.
|
|
252
|
+
- `actStart` - Emitted when an act starts.
|
|
253
|
+
- `actEnd` - Emitted when an act ends.
|
|
254
|
+
- `jobEnd` - Emitted when a job ends.
|
|
255
|
+
|
|
224
256
|
### Job as a file
|
|
225
257
|
|
|
226
258
|
Jobs can be stored as JSON files in the `todo` subdirectory of a directory identified by the `JOBDIR` environment variable. After Testaro performs such a job, Testaro moves the job file to the `done` subdirectory of the same directory and saves the report in the `raw` subdirectory of the directory identified by the `REPORTDIR` environment variable.
|
package/package.json
CHANGED
package/procs/doActs.js
CHANGED
|
@@ -227,7 +227,20 @@ const waitError = (page, act, error, what) => {
|
|
|
227
227
|
return false;
|
|
228
228
|
};
|
|
229
229
|
// Performs the acts in a report and adds the results to the report.
|
|
230
|
-
exports.doActs = async report => {
|
|
230
|
+
exports.doActs = async (report, opts = {}) => {
|
|
231
|
+
// Fire-and-forget progress emitter (see #44), mirroring run.js: a handler
|
|
232
|
+
// exception is logged, never propagated, so a faulty consumer can never abort
|
|
233
|
+
// the job.
|
|
234
|
+
const emitProgress = event => {
|
|
235
|
+
if (opts && typeof opts.onProgress === 'function') {
|
|
236
|
+
try {
|
|
237
|
+
opts.onProgress(event);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
console.log(`ERROR in onProgress callback: ${error.message}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
231
244
|
// Make a temporary copy of the report. Precondition: report is valid.
|
|
232
245
|
let tempReport = JSON.parse(JSON.stringify(report));
|
|
233
246
|
let page = null;
|
|
@@ -247,6 +260,9 @@ exports.doActs = async report => {
|
|
|
247
260
|
if (tempReport?.jobData && ! tempReport.jobData.aborted) {
|
|
248
261
|
let act = acts[actIndex];
|
|
249
262
|
const {type, which} = act;
|
|
263
|
+
// #44: signal act start so a consumer can heartbeat and advance a live
|
|
264
|
+
// per-act (per-tool, for test acts) view while the act runs.
|
|
265
|
+
emitProgress({event: 'actStart', index: Number(actIndex), type, which});
|
|
250
266
|
const actSuffix = type === 'test' ? ` ${which}` : '';
|
|
251
267
|
const message = `>>>> ${type}${actSuffix}`;
|
|
252
268
|
// Log the act.
|
|
@@ -477,6 +493,19 @@ exports.doActs = async report => {
|
|
|
477
493
|
act.expectationFailures = failureCount;
|
|
478
494
|
}
|
|
479
495
|
}
|
|
496
|
+
// #44: signal test-act completion with its outcome — timedOut is the
|
|
497
|
+
// most useful, since doActs already SIGKILLs a timed-out child — and its
|
|
498
|
+
// elapsed time, so consumers need not re-derive them from the report.
|
|
499
|
+
emitProgress({
|
|
500
|
+
event: 'actEnd',
|
|
501
|
+
index: Number(actIndex),
|
|
502
|
+
type,
|
|
503
|
+
which,
|
|
504
|
+
outcome: timedOut
|
|
505
|
+
? 'timedOut'
|
|
506
|
+
: act.data && act.data.prevented ? 'prevented' : 'success',
|
|
507
|
+
elapsedMs: Date.now() - startTime
|
|
508
|
+
});
|
|
480
509
|
}
|
|
481
510
|
// Otherwise, if a current page exists:
|
|
482
511
|
else if (page) {
|
package/run.js
CHANGED
|
@@ -76,6 +76,20 @@ const getTmpDirPath = async jobName => {
|
|
|
76
76
|
};
|
|
77
77
|
// Runs a job and returns a report.
|
|
78
78
|
exports.doJob = async (job, opts = {}) => {
|
|
79
|
+
// Fire-and-forget progress emitter (see #44). A handler exception is logged,
|
|
80
|
+
// never propagated, so a faulty consumer can never abort the job. Payloads
|
|
81
|
+
// carry identifiers and timing only — no report content — and are delivered
|
|
82
|
+
// via the existing opts param, so doJob's signature is unchanged.
|
|
83
|
+
const emitProgress = event => {
|
|
84
|
+
if (opts && typeof opts.onProgress === 'function') {
|
|
85
|
+
try {
|
|
86
|
+
opts.onProgress(event);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.log(`ERROR in onProgress callback: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
79
93
|
// Initialize a report as a copy of the job.
|
|
80
94
|
let report = JSON.parse(JSON.stringify(job));
|
|
81
95
|
report.jobData ??= {};
|
|
@@ -94,6 +108,7 @@ exports.doJob = async (job, opts = {}) => {
|
|
|
94
108
|
else {
|
|
95
109
|
// Report this.
|
|
96
110
|
console.log(`Starting job ${job.id} (${job.target.what})`);
|
|
111
|
+
emitProgress({event: 'jobStart', id: job.id});
|
|
97
112
|
const tmpDir = await getTmpDirPath(job.id);
|
|
98
113
|
// Add initialized job data to the report.
|
|
99
114
|
const startTime = new Date();
|
|
@@ -128,8 +143,15 @@ exports.doJob = async (job, opts = {}) => {
|
|
|
128
143
|
if (job.browserID && job.target && job.standard !== 'no') {
|
|
129
144
|
// Initialize a catalog so it precedes any page images in the report.
|
|
130
145
|
report.catalog = {};
|
|
146
|
+
// getCatalog() navigates to the target (procs/catalog.js) — which, on a
|
|
147
|
+
// slow, blocked, or dead target, can retry across browser types — before
|
|
148
|
+
// any act runs. Bracket it with events so a consumer can heartbeat through
|
|
149
|
+
// this phase instead of seeing the job fall silent until the first act.
|
|
150
|
+
emitProgress({event: 'catalogStart'});
|
|
151
|
+
const catalogStartMs = Date.now();
|
|
131
152
|
// Add a catalog of the target, and a page image if required, to the report.
|
|
132
153
|
report.catalog = await getCatalog(report);
|
|
154
|
+
emitProgress({event: 'catalogEnd', elapsedMs: Date.now() - catalogStartMs});
|
|
133
155
|
}
|
|
134
156
|
// Perform the acts and revise the report.
|
|
135
157
|
report = await doActs(report, opts);
|
|
@@ -152,6 +174,9 @@ exports.doJob = async (job, opts = {}) => {
|
|
|
152
174
|
report.jobData.toolTimes[item[0]] = item[1];
|
|
153
175
|
});
|
|
154
176
|
}
|
|
177
|
+
// Signal job completion (also fires for an invalid job, after its abort data
|
|
178
|
+
// is set) so a consumer can finalize regardless of outcome.
|
|
179
|
+
emitProgress({event: 'jobEnd', id: job.id, aborted: !! report.jobData.aborted});
|
|
155
180
|
// Return the report.
|
|
156
181
|
return report;
|
|
157
182
|
};
|