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/process-ctl.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const log = require('
|
|
4
|
-
const execa = require('execa');
|
|
5
|
-
const Bluebird = require('bluebird');
|
|
3
|
+
const log = require('./log');
|
|
4
|
+
const execa = require('execa').execa;
|
|
6
5
|
const util = require('util');
|
|
7
6
|
const EventEmitter = require('events').EventEmitter;
|
|
8
7
|
const spawnargs = require('spawn-args');
|
|
@@ -11,6 +10,8 @@ const _ = require('lodash');
|
|
|
11
10
|
const envWithLocalPath = require('./utils/env-with-local-path');
|
|
12
11
|
const fileutils = require('./utils/fileutils');
|
|
13
12
|
const Process = require('./utils/process');
|
|
13
|
+
const isWin = require('./utils/is-win')();
|
|
14
|
+
const { reduce } = require('./utils/promises');
|
|
14
15
|
|
|
15
16
|
const fileExists = fileutils.fileExists;
|
|
16
17
|
const executableExists = fileutils.executableExists;
|
|
@@ -37,16 +38,29 @@ module.exports = class ProcessCtl extends EventEmitter {
|
|
|
37
38
|
|
|
38
39
|
_spawn(exe, args, options) {
|
|
39
40
|
log.info('spawning: ' + exe + ' - ' + util.inspect(args));
|
|
40
|
-
|
|
41
|
+
|
|
42
|
+
// promise should always succeed, Process will uses .on('error') to handle errors
|
|
43
|
+
let process = execa(exe, args, Object.assign({ reject: false }, options));
|
|
44
|
+
|
|
45
|
+
process.then(result => {
|
|
46
|
+
if (result.failed && result.exitCode !== 0 &&
|
|
47
|
+
result.shortMessage.includes(isWin ? 'is not recognized' : 'ENOENT'))
|
|
48
|
+
{
|
|
49
|
+
this.emit('processError', new Error(result.shortMessage), result.stdout, result.stderr);
|
|
50
|
+
}
|
|
51
|
+
return Promise.resolve(result);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
let p = new Process(this.name, { killTimeout: this.killTimeout }, process);
|
|
41
55
|
this.emit('processStarted', p);
|
|
42
|
-
return
|
|
56
|
+
return Promise.resolve(p);
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
spawn(exe, args, options) {
|
|
46
60
|
let _options = this.prepareOptions(options);
|
|
47
61
|
|
|
48
62
|
if (Array.isArray(exe)) {
|
|
49
|
-
return
|
|
63
|
+
return reduce(exe, (found, exe) => {
|
|
50
64
|
if (found) {
|
|
51
65
|
return found;
|
|
52
66
|
}
|
|
@@ -10,7 +10,7 @@ The actual AppView. This encapsulates the entire UI.
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const StyledString = require('styled_string');
|
|
13
|
-
const log = require('
|
|
13
|
+
const log = require('../../log');
|
|
14
14
|
const Backbone = require('backbone');
|
|
15
15
|
|
|
16
16
|
const View = require('./view');
|
|
@@ -60,6 +60,7 @@ module.exports = View.extend({
|
|
|
60
60
|
if (atLeastOne && this.get('currentTab') < 0) {
|
|
61
61
|
this.set('currentTab', 0);
|
|
62
62
|
}
|
|
63
|
+
this.renderTop();
|
|
63
64
|
this.renderMiddle();
|
|
64
65
|
this.renderBottom();
|
|
65
66
|
});
|
|
@@ -213,7 +213,7 @@ module.exports = View.extend({
|
|
|
213
213
|
out += 'Top Level:\n' + indent(topLevelError) + '\n\n';
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
if (results && (tests = results.get('tests'))) {
|
|
216
|
+
if (results && (tests = results.get('tests')) && !topLevelError) {
|
|
217
217
|
var total = results.get('total');
|
|
218
218
|
var pending = results.get('pending');
|
|
219
219
|
var allDone = results.get('all');
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const log = require('
|
|
3
|
+
const log = require('../log');
|
|
4
4
|
const BrowserTapConsumer = require('../browser_tap_consumer');
|
|
5
|
-
const Bluebird = require('bluebird');
|
|
6
|
-
|
|
7
5
|
const LogEntry = require('../utils/log-entry');
|
|
6
|
+
const { asCallback } = require('../utils/promises');
|
|
8
7
|
const toResult = require('./to-result');
|
|
9
8
|
|
|
10
9
|
module.exports = class BrowserTestRunner {
|
|
@@ -33,7 +32,7 @@ module.exports = class BrowserTestRunner {
|
|
|
33
32
|
this.finished = false;
|
|
34
33
|
this.pending = true;
|
|
35
34
|
|
|
36
|
-
return new
|
|
35
|
+
return new Promise(resolve => {
|
|
37
36
|
this.onFinish = resolve;
|
|
38
37
|
|
|
39
38
|
if (this.socket) {
|
|
@@ -48,19 +47,19 @@ module.exports = class BrowserTestRunner {
|
|
|
48
47
|
this.onProcessError(err);
|
|
49
48
|
});
|
|
50
49
|
}
|
|
51
|
-
}).asCallback(onFinish);
|
|
50
|
+
}).then(...asCallback(onFinish));
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
stop(cb) {
|
|
55
54
|
if (this.socket) {
|
|
56
55
|
this.socket.emit('stop-run');
|
|
57
56
|
}
|
|
58
|
-
return
|
|
57
|
+
return Promise.resolve().then(...asCallback(cb));
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
exit() {
|
|
62
61
|
if (!this.process) {
|
|
63
|
-
return
|
|
62
|
+
return Promise.resolve();
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
// mark that somebody (generally app.js) has requested that the
|
|
@@ -119,6 +118,12 @@ module.exports = class BrowserTestRunner {
|
|
|
119
118
|
socket.on('test-metadata', this.onTestMetadata.bind(this));
|
|
120
119
|
socket.on('top-level-error', this.onGlobalError.bind(this));
|
|
121
120
|
|
|
121
|
+
socket.on('tap-debug', function(data) {
|
|
122
|
+
if (process.env.TESTEM_VERBOSE) {
|
|
123
|
+
log.verbose('tap-debug', data && data.msg);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
122
127
|
socket.on('browser-console', function(/* ...args */) {
|
|
123
128
|
let args = Array.prototype.slice.call(arguments);
|
|
124
129
|
let type = args.shift();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const log = require('
|
|
3
|
+
const { fromCallback, disposer } = require('../utils/promises');
|
|
4
|
+
const log = require('../log');
|
|
5
5
|
|
|
6
6
|
const template = require('../utils/strutils').template;
|
|
7
7
|
const ProcessCtl = require('../process-ctl');
|
|
@@ -11,13 +11,13 @@ module.exports = class HookRunner {
|
|
|
11
11
|
this.config = config;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
run(hook, data
|
|
14
|
+
run(hook, data) {
|
|
15
15
|
let hookCfg = this.config.get(hook);
|
|
16
16
|
if (!hookCfg) {
|
|
17
|
-
return
|
|
17
|
+
return Promise.resolve();
|
|
18
18
|
}
|
|
19
19
|
if (typeof hookCfg === 'function') {
|
|
20
|
-
return
|
|
20
|
+
return fromCallback(callback => {
|
|
21
21
|
hookCfg(this.config, data, callback);
|
|
22
22
|
});
|
|
23
23
|
}
|
|
@@ -57,7 +57,7 @@ module.exports = class HookRunner {
|
|
|
57
57
|
hookProcessPromise = this.processCtl.spawn(exe, args, options);
|
|
58
58
|
command = exe + ' ' + args.join(' ');
|
|
59
59
|
} else {
|
|
60
|
-
return
|
|
60
|
+
return Promise.reject(new Error('No command or exe/args specified for hook ' + hook));
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
waitForTextTimeout = waitForTextTimeout || 10000;
|
|
@@ -65,7 +65,7 @@ module.exports = class HookRunner {
|
|
|
65
65
|
|
|
66
66
|
let exited = false;
|
|
67
67
|
let finished;
|
|
68
|
-
let p = new
|
|
68
|
+
let p = new Promise((resolve, reject) => {
|
|
69
69
|
finished = (err, stdout, stderr) => {
|
|
70
70
|
if (exited) {
|
|
71
71
|
return;
|
|
@@ -109,7 +109,7 @@ module.exports = class HookRunner {
|
|
|
109
109
|
}
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
return p
|
|
112
|
+
return p;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
varsubParams() {
|
|
@@ -135,17 +135,19 @@ module.exports = class HookRunner {
|
|
|
135
135
|
return this.hookProcess.kill();
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
return
|
|
138
|
+
return Promise.resolve();
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
static with(config, hook, data) {
|
|
142
142
|
let hookRunner = new HookRunner(config);
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
let runPromise = hookRunner.run(hook, data).catch(err => {
|
|
145
145
|
log.error(hook + ' error', err);
|
|
146
146
|
|
|
147
147
|
throw err;
|
|
148
|
-
})
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return disposer(runPromise, () => hookRunner.stop());
|
|
149
151
|
}
|
|
150
152
|
};
|
|
151
153
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
var Bluebird = require('bluebird');
|
|
3
|
-
|
|
4
2
|
var toResult = require('./to-result');
|
|
3
|
+
const { asCallback } = require('../utils/promises');
|
|
5
4
|
|
|
6
5
|
class ProcessTestRunner {
|
|
7
6
|
constructor(launcher, reporter) {
|
|
@@ -15,19 +14,20 @@ class ProcessTestRunner {
|
|
|
15
14
|
this.onStart();
|
|
16
15
|
this.finished = false;
|
|
17
16
|
|
|
18
|
-
return new
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
19
18
|
this.onFinish = resolve;
|
|
20
19
|
this.launcher.start().then(testProcess => {
|
|
21
20
|
this.process = testProcess;
|
|
22
21
|
this.process.once('processExit', this.onProcessExit.bind(this));
|
|
23
22
|
this.process.once('processError', this.onProcessError.bind(this));
|
|
23
|
+
return Promise.resolve(testProcess);
|
|
24
24
|
}).catch(reject);
|
|
25
|
-
}).asCallback(onFinish);
|
|
25
|
+
}).then(...asCallback(onFinish));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
exit() {
|
|
29
29
|
if (!this.process) {
|
|
30
|
-
return
|
|
30
|
+
return Promise.resolve();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
return this.process.kill();
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
var TapConsumer = require('../tap_consumer');
|
|
4
|
-
var log = require('
|
|
5
|
-
var Bluebird = require('bluebird');
|
|
6
|
-
|
|
4
|
+
var log = require('../log');
|
|
7
5
|
var toResult = require('./to-result');
|
|
6
|
+
const { asCallback } = require('../utils/promises');
|
|
8
7
|
|
|
9
8
|
class TapProcessTestRunner {
|
|
10
9
|
constructor(launcher, reporter) {
|
|
@@ -23,19 +22,19 @@ class TapProcessTestRunner {
|
|
|
23
22
|
this.tapConsumer.on('test-result', this.onTestResult.bind(this));
|
|
24
23
|
this.tapConsumer.on('all-test-results', this.onAllTestResults.bind(this));
|
|
25
24
|
|
|
26
|
-
return new
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
27
26
|
this.onFinish = resolve;
|
|
28
27
|
this.launcher.start().then(tapProcess => {
|
|
29
28
|
this.process = tapProcess;
|
|
30
29
|
this.process.once('processError', this.onProcessError.bind(this));
|
|
31
30
|
this.process.process.stdout.pipe(this.tapConsumer.stream);
|
|
32
31
|
}).catch(reject);
|
|
33
|
-
}).asCallback(onFinish);
|
|
32
|
+
}).then(...asCallback(onFinish));
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
exit() {
|
|
37
36
|
if (!this.process) {
|
|
38
|
-
return
|
|
37
|
+
return Promise.resolve();
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
return this.process.kill();
|
package/lib/runners/to-result.js
CHANGED
package/lib/server/index.js
CHANGED
|
@@ -14,15 +14,13 @@ var socketIO = require('socket.io');
|
|
|
14
14
|
var compression = require('compression');
|
|
15
15
|
var fs = require('fs');
|
|
16
16
|
var path = require('path');
|
|
17
|
-
var log = require('
|
|
17
|
+
var log = require('../log');
|
|
18
18
|
var EventEmitter = require('events').EventEmitter;
|
|
19
19
|
var Mustache = require('consolidate').mustache;
|
|
20
20
|
var http = require('http');
|
|
21
21
|
var https = require('https');
|
|
22
22
|
var httpProxy = require('http-proxy');
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
var readFileAsync = Bluebird.promisify(fs.readFile);
|
|
23
|
+
const { fromCallback, each } = require('../utils/promises');
|
|
26
24
|
|
|
27
25
|
class Server extends EventEmitter {
|
|
28
26
|
constructor(config) {
|
|
@@ -37,7 +35,7 @@ class Server extends EventEmitter {
|
|
|
37
35
|
this.nextSocketId = 0;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
start(
|
|
38
|
+
start() {
|
|
41
39
|
this.createExpress();
|
|
42
40
|
|
|
43
41
|
// Start the server!
|
|
@@ -50,7 +48,7 @@ class Server extends EventEmitter {
|
|
|
50
48
|
});
|
|
51
49
|
});
|
|
52
50
|
|
|
53
|
-
return new
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
54
52
|
this.server.on('listening', () => {
|
|
55
53
|
this.config.set('port', this.server.address().port);
|
|
56
54
|
resolve();
|
|
@@ -63,23 +61,23 @@ class Server extends EventEmitter {
|
|
|
63
61
|
});
|
|
64
62
|
|
|
65
63
|
this.server.listen(this.config.get('port'));
|
|
66
|
-
})
|
|
64
|
+
});
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
stop(
|
|
67
|
+
stop() {
|
|
70
68
|
if (this.server && !this.stopped) {
|
|
71
69
|
this.stopped = true;
|
|
72
70
|
|
|
73
|
-
return
|
|
71
|
+
return fromCallback(closeCallback => {
|
|
74
72
|
this.server.close(closeCallback);
|
|
75
73
|
|
|
76
74
|
// Destroy all open sockets
|
|
77
75
|
for (var socketId in this.sockets) {
|
|
78
76
|
this.sockets[socketId].destroy();
|
|
79
77
|
}
|
|
80
|
-
})
|
|
78
|
+
});
|
|
81
79
|
} else {
|
|
82
|
-
return
|
|
80
|
+
return Promise.resolve();
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
83
|
|
|
@@ -281,11 +279,13 @@ class Server extends EventEmitter {
|
|
|
281
279
|
var url = base + test_page;
|
|
282
280
|
res.redirect(url);
|
|
283
281
|
} else {
|
|
284
|
-
config.getServeFiles(
|
|
285
|
-
|
|
286
|
-
this.renderRunnerPage(
|
|
282
|
+
Promise.all([config.getServeFiles(), config.getFooterScripts()])
|
|
283
|
+
.then(([files, footerScripts]) => {
|
|
284
|
+
this.renderRunnerPage(null, files, footerScripts, res);
|
|
285
|
+
})
|
|
286
|
+
.catch(err => {
|
|
287
|
+
this.renderRunnerPage(err, [], [], res);
|
|
287
288
|
});
|
|
288
|
-
});
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
|
|
@@ -314,11 +314,11 @@ class Server extends EventEmitter {
|
|
|
314
314
|
'mocha_adapter.js',
|
|
315
315
|
'testem_client.js'
|
|
316
316
|
];
|
|
317
|
-
|
|
317
|
+
each(files, file => {
|
|
318
318
|
if (file.indexOf(path.sep) === -1) {
|
|
319
319
|
file = `${__dirname}/../../public/testem/${file}`;
|
|
320
320
|
}
|
|
321
|
-
return
|
|
321
|
+
return fs.promises.readFile(file).then(data => {
|
|
322
322
|
res.write(`\n//============== ${path.basename(file)} ==================\n\n`);
|
|
323
323
|
res.write(data);
|
|
324
324
|
}).catch(err => {
|
|
@@ -376,20 +376,21 @@ class Server extends EventEmitter {
|
|
|
376
376
|
this.emit('file-requested', filePath);
|
|
377
377
|
});
|
|
378
378
|
} else {
|
|
379
|
-
fs.stat(filePath
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
});
|
|
389
|
-
} else {
|
|
379
|
+
fs.promises.stat(filePath)
|
|
380
|
+
.then(stat => {
|
|
381
|
+
this.emit('file-requested', filePath);
|
|
382
|
+
if (stat.isDirectory()) {
|
|
383
|
+
return fs.promises.readdir(filePath).then(files => {
|
|
384
|
+
var dirListingPage = `${__dirname}/../../views/directorylisting.mustache`;
|
|
385
|
+
res.render(dirListingPage, { files: files });
|
|
386
|
+
});
|
|
387
|
+
}
|
|
390
388
|
res.sendFile(filePath);
|
|
391
|
-
}
|
|
392
|
-
|
|
389
|
+
})
|
|
390
|
+
.catch(() => {
|
|
391
|
+
this.emit('file-requested', filePath);
|
|
392
|
+
res.sendFile(filePath);
|
|
393
|
+
});
|
|
393
394
|
}
|
|
394
395
|
}
|
|
395
396
|
|
package/lib/tap_consumer.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
const yaml = require('js-yaml');
|
|
4
|
-
const extend =
|
|
4
|
+
const extend = Object.assign;
|
|
5
5
|
const EventEmitter = require('events').EventEmitter;
|
|
6
6
|
const TapParser = require('tap-parser');
|
|
7
|
-
const log = require('
|
|
7
|
+
const log = require('./log');
|
|
8
8
|
|
|
9
9
|
module.exports = class TapConsumer extends EventEmitter {
|
|
10
10
|
constructor() {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared esbuild config for bundling Node.js-dependent test code to run in a
|
|
3
|
+
* browser via testem.
|
|
4
|
+
*
|
|
5
|
+
* esbuild's `@esbuild-plugins/node-modules-polyfill` stores the `process`
|
|
6
|
+
* polyfill as a scoped variable inside the IIFE it emits, but CJS module
|
|
7
|
+
* factories (wrapped in `__commonJS`) reference `process`, `__dirname`, and
|
|
8
|
+
* `setImmediate` as free globals — causing ReferenceErrors at runtime.
|
|
9
|
+
*
|
|
10
|
+
* These two options fix that:
|
|
11
|
+
* - `banner.js`: sets `globalThis.process`, `globalThis.setImmediate`, and
|
|
12
|
+
* `globalThis.Buffer` before the bundle executes, so CJS factories find
|
|
13
|
+
* them as globals.
|
|
14
|
+
* - `define`: replaces `__dirname` / `__filename` literals, which esbuild
|
|
15
|
+
* does not inject when targeting the browser platform.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
var banner = '(function(){' +
|
|
19
|
+
'if(typeof process==="undefined"){' +
|
|
20
|
+
'var p={env:{},browser:true,platform:"browser",' +
|
|
21
|
+
'nextTick:function(fn){Promise.resolve().then(fn);},' +
|
|
22
|
+
'on:function(){},once:function(){},off:function(){},' +
|
|
23
|
+
'emit:function(){},removeListener:function(){},' +
|
|
24
|
+
'removeAllListeners:function(){},addListener:function(){},' +
|
|
25
|
+
'binding:function(){throw new Error("process.binding not supported");},' +
|
|
26
|
+
'cwd:function(){return "/";},' +
|
|
27
|
+
'exit:function(){}' +
|
|
28
|
+
'};' +
|
|
29
|
+
'if(typeof globalThis!=="undefined")globalThis.process=p;' +
|
|
30
|
+
'else if(typeof window!=="undefined")window.process=p;' +
|
|
31
|
+
'}' +
|
|
32
|
+
'if(typeof setImmediate==="undefined"){' +
|
|
33
|
+
'var si=function(fn){Promise.resolve().then(fn);};' +
|
|
34
|
+
'if(typeof globalThis!=="undefined")globalThis.setImmediate=si;' +
|
|
35
|
+
'else if(typeof window!=="undefined")window.setImmediate=si;' +
|
|
36
|
+
'}' +
|
|
37
|
+
'})();';
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
banner: { js: banner },
|
|
41
|
+
bufferInject: require.resolve('./esbuild-buffer-inject.js'),
|
|
42
|
+
define: {
|
|
43
|
+
__dirname: '""',
|
|
44
|
+
__filename: '""'
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// esbuild inject shim: exposes Buffer as a global for browser bundles.
|
|
2
|
+
// The @esbuild-plugins/node-modules-polyfill plugin resolves `require('buffer')`
|
|
3
|
+
// to a browser polyfill, but does not assign it to globalThis automatically.
|
|
4
|
+
import { Buffer } from 'buffer';
|
|
5
|
+
if (typeof globalThis !== 'undefined') { globalThis.Buffer = Buffer; }
|
|
6
|
+
else if (typeof window !== 'undefined') { window.Buffer = Buffer; }
|
package/lib/utils/fileutils.js
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const execa = require('execa');
|
|
5
|
-
const
|
|
6
|
-
const log = require('
|
|
4
|
+
const execa = require('execa').execa;
|
|
5
|
+
const { promisify } = require('util');
|
|
6
|
+
const log = require('../log');
|
|
7
7
|
|
|
8
|
-
const fsStatAsync =
|
|
8
|
+
const fsStatAsync = promisify(fs.stat);
|
|
9
9
|
|
|
10
10
|
const isWin = require('./is-win')();
|
|
11
11
|
|
|
12
12
|
exports.fileExists = function fileExists(path) {
|
|
13
|
-
return fsStatAsync(path).then(stat => stat.isFile()).
|
|
13
|
+
return fsStatAsync(path).then(stat => stat.isFile()).catch(() => false);
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
exports.executableExists = function executableExists(exe, options) {
|
|
17
17
|
let cmd = isWin ? 'where' : 'which';
|
|
18
|
-
let test = execa(cmd, [exe], options);
|
|
19
|
-
|
|
20
|
-
test.
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
let test = execa(cmd, [exe], Object.assign({ reject: false }, options));
|
|
19
|
+
|
|
20
|
+
return test.then(result => {
|
|
21
|
+
if (result.exitCode === 0) {
|
|
22
|
+
return true;
|
|
23
|
+
} else if (!result.exitCode) {
|
|
24
|
+
log.error('Error spawning "' + cmd + ' ' + exe + '"', result);
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
});
|
|
23
28
|
};
|
package/lib/utils/is-win.js
CHANGED
|
@@ -84,6 +84,7 @@ function firefoxPaths() {
|
|
|
84
84
|
return [
|
|
85
85
|
'C:\\Program Files\\Mozilla Firefox\\firefox.exe',
|
|
86
86
|
'C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe',
|
|
87
|
+
'C:\\Users\\' + process.env.USERNAME + '\\AppData\\Local\\Mozilla Firefox\\firefox.exe',
|
|
87
88
|
process.env.HOME + '/Applications/Firefox.app/Contents/MacOS/firefox',
|
|
88
89
|
'/Applications/Firefox.app/Contents/MacOS/firefox'
|
|
89
90
|
];
|
|
@@ -94,24 +95,25 @@ function firefoxSetup(browserTmpDir, config, done) {
|
|
|
94
95
|
let perfJS = path.join(browserTmpDir, 'user.js');
|
|
95
96
|
|
|
96
97
|
if (config.get('firefox_user_js')) {
|
|
97
|
-
return fs.readFile(config.get('firefox_user_js')
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
fs.writeFile(perfJS, content, done);
|
|
103
|
-
});
|
|
98
|
+
return fs.promises.readFile(config.get('firefox_user_js'))
|
|
99
|
+
.then(content => fs.promises.writeFile(perfJS, content))
|
|
100
|
+
.then(() => done(null), done);
|
|
104
101
|
}
|
|
105
102
|
|
|
106
|
-
// using user.js to suppress the check default browser popup
|
|
107
|
-
//
|
|
103
|
+
// using user.js to suppress the check default browser popup,
|
|
104
|
+
// the welcome start page, and first-run helper installation prompts
|
|
108
105
|
let prefs = [
|
|
109
106
|
'user_pref("browser.shell.checkDefaultBrowser", false);',
|
|
110
107
|
'user_pref("browser.cache.disk.smart_size.first_run", false);',
|
|
111
108
|
'user_pref("datareporting.policy.dataSubmissionEnabled", false);',
|
|
112
|
-
'user_pref("datareporting.policy.dataSubmissionPolicyNotifiedTime", "1481830156314");'
|
|
109
|
+
'user_pref("datareporting.policy.dataSubmissionPolicyNotifiedTime", "1481830156314");',
|
|
110
|
+
'user_pref("app.update.auto", false);',
|
|
111
|
+
'user_pref("app.update.enabled", false);',
|
|
112
|
+
'user_pref("browser.EULA.override", true);',
|
|
113
|
+
'user_pref("toolkit.telemetry.reportingpolicy.firstRun", false);'
|
|
113
114
|
];
|
|
114
|
-
fs.writeFile(perfJS, prefs.join(os.EOL)
|
|
115
|
+
fs.promises.writeFile(perfJS, prefs.join(os.EOL))
|
|
116
|
+
.then(() => done(null), done);
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
// Return the catalogue of the browsers that Testem supports for the platform. Each 'browser object'
|
|
@@ -144,7 +146,7 @@ module.exports = function knownBrowsers(platform, config) {
|
|
|
144
146
|
possibleExe: 'firefox',
|
|
145
147
|
|
|
146
148
|
args(config, url) {
|
|
147
|
-
return ['-profile', '
|
|
149
|
+
return ['-profile', '-headless', this.browserTmpDir(), url];
|
|
148
150
|
},
|
|
149
151
|
setup(config, done) {
|
|
150
152
|
firefoxSetup(this.browserTmpDir(), config, done);
|