testem 3.18.0 → 3.19.1
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/lib/api.js +1 -1
- package/lib/app.js +42 -49
- package/lib/browser_launcher.js +5 -6
- package/lib/config.js +66 -50
- package/lib/launcher.js +7 -11
- package/lib/log.js +92 -0
- package/lib/process-ctl.js +20 -6
- package/lib/reporters/dev/index.js +2 -1
- package/lib/reporters/dev/split_log_panel.js +1 -1
- package/lib/runners/browser_test_runner.js +12 -7
- package/lib/runners/hook_runner.js +13 -11
- package/lib/runners/process_test_runner.js +5 -5
- package/lib/runners/tap_process_test_runner.js +5 -6
- package/lib/runners/to-result.js +1 -1
- package/lib/server/index.js +31 -30
- package/lib/tap_consumer.js +2 -2
- package/lib/utils/browser-args.js +1 -1
- package/lib/utils/esbuild-browser-polyfills.js +46 -0
- package/lib/utils/esbuild-buffer-inject.js +6 -0
- package/lib/utils/fileutils.js +15 -10
- package/lib/utils/is-win.js +0 -2
- package/lib/utils/known-browsers.js +14 -12
- package/lib/utils/posix.js +13 -0
- package/lib/utils/process.js +21 -11
- package/lib/utils/promises.js +130 -0
- package/lib/utils/report-file.js +1 -3
- package/lib/utils/reporter.js +3 -3
- package/lib/utils/run-timeout.js +4 -4
- package/lib/utils/signal-listeners.js +9 -7
- package/package.json +14 -15
package/lib/utils/process.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const execa = require('execa');
|
|
4
|
-
const log = require('npmlog');
|
|
5
|
-
const Bluebird = require('bluebird');
|
|
1
|
+
const execa = require('execa').execa;
|
|
2
|
+
const log = require('../log');
|
|
6
3
|
const EventEmitter = require('events').EventEmitter;
|
|
7
4
|
|
|
8
5
|
const isWin = require('./is-win')();
|
|
@@ -29,6 +26,15 @@ module.exports = class Process extends EventEmitter {
|
|
|
29
26
|
|
|
30
27
|
this.process.on('close', this.onClose.bind(this));
|
|
31
28
|
this.process.on('error', this.onError.bind(this));
|
|
29
|
+
|
|
30
|
+
this.process.then(result => {
|
|
31
|
+
if (result.failed && result.exitCode !== 0 &&
|
|
32
|
+
result.shortMessage.includes(isWin ? 'is not recognized' : 'ENOENT'))
|
|
33
|
+
{
|
|
34
|
+
this.onError(new Error(result.shortMessage), this.stdout, this.stderr);
|
|
35
|
+
}
|
|
36
|
+
return Promise.resolve(result);
|
|
37
|
+
});
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
onKillTimeout() {
|
|
@@ -48,7 +54,7 @@ module.exports = class Process extends EventEmitter {
|
|
|
48
54
|
|
|
49
55
|
onError(error) {
|
|
50
56
|
log.warn(this.name + ' errored', error);
|
|
51
|
-
this.process = null;
|
|
57
|
+
// this.process = null;
|
|
52
58
|
this.exitCode = 1;
|
|
53
59
|
this.emit('processError', error, this.stdout, this.stderr);
|
|
54
60
|
}
|
|
@@ -88,14 +94,14 @@ module.exports = class Process extends EventEmitter {
|
|
|
88
94
|
if (!this.process) {
|
|
89
95
|
log.info('Process ' + this.name + ' already killed.');
|
|
90
96
|
|
|
91
|
-
return
|
|
97
|
+
return Promise.resolve(this.exitCode);
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
sig = sig || 'SIGTERM';
|
|
95
101
|
|
|
96
102
|
let self = this;
|
|
97
103
|
|
|
98
|
-
return new
|
|
104
|
+
return new Promise(resolve => {
|
|
99
105
|
self.process.once('close', (code, sig) => {
|
|
100
106
|
self.process = null;
|
|
101
107
|
if (self._killTimer) {
|
|
@@ -132,14 +138,18 @@ function kill(p, sig) {
|
|
|
132
138
|
args.push('/f');
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
execa(command, args
|
|
141
|
+
const killProcess = execa(command, args, { reject: false });
|
|
142
|
+
|
|
143
|
+
killProcess.on('error', err => {
|
|
144
|
+
log.error(err);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
killProcess.then(result => {
|
|
136
148
|
// Processes without windows can't be killed without /F, detect and force
|
|
137
149
|
// kill them directly
|
|
138
150
|
if (result.stderr.indexOf('can only be terminated forcefully') !== -1) {
|
|
139
151
|
kill(p, 'SIGKILL');
|
|
140
152
|
}
|
|
141
|
-
}).catch(err => {
|
|
142
|
-
log.error(err);
|
|
143
153
|
});
|
|
144
154
|
} else {
|
|
145
155
|
p.kill(sig);
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
function fromCallback(fn) {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
fn((err, result) => {
|
|
4
|
+
if (err) {
|
|
5
|
+
reject(err);
|
|
6
|
+
} else {
|
|
7
|
+
resolve(result);
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function filter(arr, predicate) {
|
|
14
|
+
const results = await Promise.all(arr.map(item => predicate(item)));
|
|
15
|
+
return arr.filter((_, i) => results[i]);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function reduce(arr, reducer, initialValue) {
|
|
19
|
+
return arr.reduce(
|
|
20
|
+
(acc, item) => acc.then(a => reducer(a, item)),
|
|
21
|
+
Promise.resolve(initialValue)
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function each(arr, fn) {
|
|
26
|
+
return arr.reduce(
|
|
27
|
+
(p, item) => p.then(() => fn(item)),
|
|
28
|
+
Promise.resolve()
|
|
29
|
+
).then(() => arr);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class Disposer {
|
|
33
|
+
constructor(promise, cleanup) {
|
|
34
|
+
this.promise = Promise.resolve(promise);
|
|
35
|
+
this.cleanup = cleanup;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function disposer(promise, cleanup) {
|
|
40
|
+
return new Disposer(promise, cleanup);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function using(resource, fn) {
|
|
44
|
+
const isDisposer = resource instanceof Disposer;
|
|
45
|
+
const value = await (isDisposer ? resource.promise : resource);
|
|
46
|
+
|
|
47
|
+
let result, rejected = false, error;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
result = await fn(value);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
rejected = true;
|
|
53
|
+
error = err;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (isDisposer) {
|
|
57
|
+
const inspection = {
|
|
58
|
+
isRejected: () => rejected,
|
|
59
|
+
reason: () => error,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
await resource.cleanup(value, inspection);
|
|
64
|
+
} catch (cleanupErr) {
|
|
65
|
+
if (!rejected) {
|
|
66
|
+
// Callback succeeded but cleanup failed — surface cleanup error
|
|
67
|
+
throw cleanupErr;
|
|
68
|
+
}
|
|
69
|
+
// Both callback and cleanup failed — suppress cleanup error, re-throw original below
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (rejected) {
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function mapLimit(arr, concurrency, fn) {
|
|
80
|
+
if (!isFinite(concurrency) || concurrency >= arr.length) {
|
|
81
|
+
return Promise.all(arr.map(fn));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let index = 0;
|
|
85
|
+
let results = new Array(arr.length);
|
|
86
|
+
|
|
87
|
+
function next() {
|
|
88
|
+
let i = index++;
|
|
89
|
+
if (i >= arr.length) {
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return Promise.resolve(fn(arr[i])).then(result => {
|
|
94
|
+
results[i] = result;
|
|
95
|
+
return next();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let workers = [];
|
|
100
|
+
for (let w = 0; w < Math.min(concurrency, arr.length); w++) {
|
|
101
|
+
workers.push(next());
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return Promise.all(workers).then(() => results);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function retry(fn, { max_tries = 3 } = {}) {
|
|
108
|
+
let lastErr;
|
|
109
|
+
for (let i = 0; i < max_tries; i++) {
|
|
110
|
+
try {
|
|
111
|
+
return await fn();
|
|
112
|
+
} catch (e) {
|
|
113
|
+
lastErr = e;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
throw lastErr;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function delay(ms) {
|
|
120
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function asCallback(cb) {
|
|
124
|
+
return [
|
|
125
|
+
result => { if (cb) { cb(null, result); } return result; },
|
|
126
|
+
err => { if (cb) { cb(err); } throw err; }
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = { fromCallback, filter, reduce, each, mapLimit, retry, delay, asCallback, Disposer, disposer, using };
|
package/lib/utils/report-file.js
CHANGED
|
@@ -4,8 +4,6 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const mkdirp = require('mkdirp');
|
|
6
6
|
const PassThrough = require('stream').PassThrough;
|
|
7
|
-
const Bluebird = require('bluebird');
|
|
8
|
-
|
|
9
7
|
module.exports = class ReportFile {
|
|
10
8
|
constructor(reportFile) {
|
|
11
9
|
this.file = reportFile;
|
|
@@ -27,7 +25,7 @@ module.exports = class ReportFile {
|
|
|
27
25
|
this.outputStream.on('end', finish);
|
|
28
26
|
this.outputStream.on('error', finish);
|
|
29
27
|
|
|
30
|
-
this.closePromise = new
|
|
28
|
+
this.closePromise = new Promise((resolve, reject) => {
|
|
31
29
|
this.outputStream.on('finish', resolve);
|
|
32
30
|
this.outputStream.on('error', reject);
|
|
33
31
|
});
|
package/lib/utils/reporter.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const log = require('
|
|
3
|
+
const { disposer } = require('./promises');
|
|
4
|
+
const log = require('../log');
|
|
5
5
|
|
|
6
6
|
const reporters = require('../reporters');
|
|
7
7
|
const isa = require('./isa');
|
|
@@ -107,7 +107,7 @@ class Reporter {
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
Reporter.with = (app, stdout, path) =>
|
|
110
|
+
Reporter.with = (app, stdout, path) => disposer(Promise.resolve(new Reporter(app, stdout, path)), (reporter, promise) => {
|
|
111
111
|
if (promise.isRejected()) {
|
|
112
112
|
let err = promise.reason();
|
|
113
113
|
|
package/lib/utils/run-timeout.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { disposer } = require('./promises');
|
|
4
4
|
const EventEmitter = require('events').EventEmitter;
|
|
5
5
|
|
|
6
6
|
class RunTimeout {
|
|
@@ -11,7 +11,7 @@ class RunTimeout {
|
|
|
11
11
|
static with(timeout) {
|
|
12
12
|
let runTimeout = new RunTimeout(timeout);
|
|
13
13
|
|
|
14
|
-
return runTimeout.start()
|
|
14
|
+
return disposer(runTimeout.start(), () => runTimeout.stop());
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
start() {
|
|
@@ -23,7 +23,7 @@ class RunTimeout {
|
|
|
23
23
|
}, this.timeout * 1000);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
return
|
|
26
|
+
return Promise.resolve(this);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
setTimedOut() {
|
|
@@ -39,7 +39,7 @@ class RunTimeout {
|
|
|
39
39
|
|
|
40
40
|
try(fn) {
|
|
41
41
|
if (this.timedOut) {
|
|
42
|
-
return
|
|
42
|
+
return Promise.reject(new Error('Run timed out.'));
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
return fn();
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { disposer } = require('./promises');
|
|
4
4
|
const EventEmitter = require('events').EventEmitter;
|
|
5
5
|
|
|
6
6
|
class SignalListeners extends EventEmitter {
|
|
7
7
|
static with() {
|
|
8
8
|
let signalListeners = new this();
|
|
9
9
|
|
|
10
|
-
return signalListeners.add()
|
|
10
|
+
return disposer(signalListeners.add(), () => signalListeners.remove());
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
SignalListeners.prototype.add =
|
|
14
|
+
SignalListeners.prototype.add = function() {
|
|
15
15
|
this._boundSigInterrupt = () => {
|
|
16
16
|
this.emit('signal', new Error('Received SIGINT signal'));
|
|
17
17
|
};
|
|
@@ -23,16 +23,18 @@ SignalListeners.prototype.add = Bluebird.method(function() {
|
|
|
23
23
|
};
|
|
24
24
|
process.on('SIGTERM', this._boundSigTerminate);
|
|
25
25
|
|
|
26
|
-
return this;
|
|
27
|
-
}
|
|
26
|
+
return Promise.resolve(this);
|
|
27
|
+
};
|
|
28
28
|
|
|
29
|
-
SignalListeners.prototype.remove =
|
|
29
|
+
SignalListeners.prototype.remove = function() {
|
|
30
30
|
if (this._boundSigInterrupt) {
|
|
31
31
|
process.removeListener('SIGINT', this._boundSigInterrupt);
|
|
32
32
|
}
|
|
33
33
|
if (this._boundSigTerminate) {
|
|
34
34
|
process.removeListener('SIGTERM', this._boundSigTerminate);
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
|
|
37
|
+
return Promise.resolve();
|
|
38
|
+
};
|
|
37
39
|
|
|
38
40
|
module.exports = SignalListeners;
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"unittest",
|
|
8
8
|
"browser"
|
|
9
9
|
],
|
|
10
|
-
"version": "3.
|
|
10
|
+
"version": "3.19.1",
|
|
11
11
|
"author": "Toby Ho <airportyh@gmail.com>",
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
@@ -23,24 +23,23 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@xmldom/xmldom": "^0.8.0",
|
|
25
25
|
"backbone": "^1.1.2",
|
|
26
|
-
"bluebird": "^3.4.6",
|
|
27
26
|
"charm": "^1.0.0",
|
|
28
27
|
"commander": "^2.6.0",
|
|
29
28
|
"compression": "^1.7.4",
|
|
30
|
-
"consolidate": "^0.
|
|
31
|
-
"execa": "^
|
|
29
|
+
"consolidate": "^1.0.4",
|
|
30
|
+
"execa": "^9.6.1",
|
|
32
31
|
"express": "^4.10.7",
|
|
33
32
|
"fireworm": "^0.7.2",
|
|
34
|
-
"glob": "^
|
|
33
|
+
"glob": "^13.0.6",
|
|
35
34
|
"http-proxy": "^1.13.1",
|
|
36
35
|
"js-yaml": "^3.2.5",
|
|
37
36
|
"lodash": "^4.17.21",
|
|
38
37
|
"mkdirp": "^3.0.1",
|
|
39
38
|
"mustache": "^4.2.0",
|
|
40
39
|
"node-notifier": "^10.0.0",
|
|
41
|
-
"npmlog": "^6.0.0",
|
|
42
40
|
"printf": "^0.6.1",
|
|
43
|
-
"
|
|
41
|
+
"proc-log": "^5.0.0",
|
|
42
|
+
"rimraf": "^6.1.3",
|
|
44
43
|
"socket.io": "^4.5.4",
|
|
45
44
|
"spawn-args": "^0.2.0",
|
|
46
45
|
"styled_string": "0.0.1",
|
|
@@ -59,30 +58,30 @@
|
|
|
59
58
|
"scripts": {
|
|
60
59
|
"install:all": "npm install && npm install phantomjs-prebuilt",
|
|
61
60
|
"test": "mocha tests/*_tests.js tests/**/*_tests.js",
|
|
61
|
+
"test:verbose": "TESTEM_VERBOSE=1 mocha tests/*_tests.js tests/**/*_tests.js",
|
|
62
62
|
"cover": "cover run ./node_modules/.bin/_mocha tests/*_tests.js tests/**/*_tests.js; cover report html; open cover_html/index.html",
|
|
63
63
|
"integration": "node ./bin/run-integration.js",
|
|
64
64
|
"browser-tests": "cd examples/saucelabs/ && ../../testem.js ci -d",
|
|
65
65
|
"lint": "eslint ."
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"
|
|
69
|
-
"
|
|
68
|
+
"@cypress/request": "^3.0.10",
|
|
69
|
+
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
|
70
70
|
"chai": "^6.2.2",
|
|
71
71
|
"chai-files": "^1.2.0",
|
|
72
72
|
"chai-shallow-deep-equal": "^1.4.4",
|
|
73
73
|
"cheerio": "1.0.0-rc.12",
|
|
74
74
|
"dirty-chai": "^3.0.0",
|
|
75
|
+
"esbuild": "^0.25.1",
|
|
75
76
|
"eslint": "^9.39.4",
|
|
76
77
|
"eslint-plugin-chai-expect": "^3.1.0",
|
|
77
78
|
"eslint-plugin-mocha": "^11.2.0",
|
|
79
|
+
"fresh-tape": "^5.5.3",
|
|
78
80
|
"mocha": "^11.7.5",
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"shelljs": "^0.8.2",
|
|
82
|
-
"sinon": "10.0.0",
|
|
81
|
+
"saucie": "^4.0.1",
|
|
82
|
+
"sinon": "^21.0.3",
|
|
83
83
|
"sinon-chai": "^4.0.1",
|
|
84
|
-
"socket.io-client": "^4.1.2"
|
|
85
|
-
"tape": "^5.2.2"
|
|
84
|
+
"socket.io-client": "^4.1.2"
|
|
86
85
|
},
|
|
87
86
|
"bin": {
|
|
88
87
|
"testem": "./testem.js"
|