browsertime 17.0.0-beta.2 → 17.0.0-beta.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/CHANGELOG.md +29 -3
- package/bin/browsertime.js +2 -5
- package/lib/core/engine/index.js +21 -3
- package/lib/core/engine/iteration.js +8 -15
- package/lib/support/cli.js +6 -0
- package/lib/support/engineUtils.js +66 -60
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,10 +3,36 @@
|
|
|
3
3
|
## 17.0.0 - UNRELEASED
|
|
4
4
|
|
|
5
5
|
### Breaking changes
|
|
6
|
-
* We moved the project to be a [pure ESM package](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) [#1859](https://github.com/sitespeedio/browsertime/pull/1859). That helps us keep up to date with dependencies that already did the move.
|
|
6
|
+
* We moved the project to be a [pure ESM package](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) [#1859](https://github.com/sitespeedio/browsertime/pull/1859). That helps us keep up to date with dependencies that already did the move and make sure we can always use the latest version of our dependencies.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
#### CLI users
|
|
9
|
+
If you are a command line user and use scripting, you will need to do a change to your scripts or add a extra configuration.
|
|
10
|
+
The new browsertime version treat all JavaScript files that ends with *.js* as ESM modules, that means your old script files will not work out of the box. There's a couple of fixes for that:
|
|
11
|
+
|
|
12
|
+
**The best fix**:
|
|
13
|
+
Change your code so your scripts also follows ESM package. If you have simple scripts you probably just need to change your exports. The old way looked like this:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
module.exports = async function(context, commands) {
|
|
17
|
+
...
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
change that to:
|
|
22
|
+
```
|
|
23
|
+
export default async function (context, commands) {
|
|
24
|
+
...
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If you have more complicated scripts, follow the [ESM package guide](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
|
|
29
|
+
|
|
30
|
+
**The quick fix**: Rename your *.js* to *.cjs* that way NodeJS will treat your file as a common JS file and everthing will just work. For example if you have a file names `login.js` you can rename that to `login.cjs` and make sure you load that new file.
|
|
31
|
+
|
|
32
|
+
**Another quick fix alternative**: Add `--cjs` as a parameter to your test. That way the scripting file will be treated as a commonjs file. This is a hack, so to make sure it works, the user that runs Browsertime need to have write privileges to the folder where you have your scripting files.
|
|
33
|
+
|
|
34
|
+
#### Non cli users
|
|
35
|
+
If you import Browsertime in NodeJS we changed how you do your import.
|
|
10
36
|
|
|
11
37
|
If you use ES modules you can import Browsertime like this:
|
|
12
38
|
```JavaScript
|
package/bin/browsertime.js
CHANGED
|
@@ -154,6 +154,7 @@ async function run(urls, options) {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
let cliResult = parseCommandLine();
|
|
157
|
+
logging(cliResult.options);
|
|
157
158
|
|
|
158
159
|
/*
|
|
159
160
|
Each url can be:
|
|
@@ -169,8 +170,7 @@ const tests = [];
|
|
|
169
170
|
for (const url of cliResult.urls) {
|
|
170
171
|
// for each url, we try to load it as a script, that may contain
|
|
171
172
|
// export a single function or an object containing setUp/test/tearDown functions.
|
|
172
|
-
let testScript = await loadScript(url);
|
|
173
|
-
|
|
173
|
+
let testScript = await loadScript(url, cliResult.options);
|
|
174
174
|
// if the value is an url or a not a single function, we can return the original value
|
|
175
175
|
if (typeof testScript == 'string' || testScript instanceof AsyncFunction) {
|
|
176
176
|
tests.push(url);
|
|
@@ -192,7 +192,4 @@ for (const url of cliResult.urls) {
|
|
|
192
192
|
// here, url is the filename containing the script, and test the callable.
|
|
193
193
|
tests.push([url, testScript.test]);
|
|
194
194
|
}
|
|
195
|
-
|
|
196
|
-
logging(cliResult.options);
|
|
197
|
-
|
|
198
195
|
await run(tests, cliResult.options);
|
package/lib/core/engine/index.js
CHANGED
|
@@ -25,8 +25,8 @@ import Collector from './collector.js';
|
|
|
25
25
|
import { Android, isAndroidConfigured } from '../../android/index.js';
|
|
26
26
|
import RootedDevice from '../../android/root.js';
|
|
27
27
|
import run from './run.js';
|
|
28
|
-
import { loadScript } from '../../support/engineUtils.js';
|
|
29
28
|
import IOSRecorder from '../../video/screenRecording/ios/iosRecorder.js';
|
|
29
|
+
import { loadPrePostScripts, loadScript } from '../../support/engineUtils.js';
|
|
30
30
|
const log = intel.getLogger('browsertime');
|
|
31
31
|
const defaults = {
|
|
32
32
|
scripts: [],
|
|
@@ -252,11 +252,30 @@ export default class Engine {
|
|
|
252
252
|
engineDelegate = new Safari(storageManager, options);
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
|
+
|
|
256
|
+
let preScripts, postScripts, postURLScripts, pageCompleteCheck;
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
preScripts = await loadPrePostScripts(options.preScript, options);
|
|
260
|
+
postScripts = await loadPrePostScripts(options.postScript, options);
|
|
261
|
+
postURLScripts = await loadPrePostScripts(options.postURLScript, options);
|
|
262
|
+
pageCompleteCheck = options.pageCompleteCheck
|
|
263
|
+
? await loadScript(options.pageCompleteCheck, options)
|
|
264
|
+
: undefined;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
log.error(error.message);
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
|
|
255
270
|
const iteration = new Iteration(
|
|
256
271
|
storageManager,
|
|
257
272
|
engineDelegate,
|
|
258
273
|
scriptsByCategory,
|
|
259
274
|
asyncScriptsByCategory,
|
|
275
|
+
preScripts,
|
|
276
|
+
postScripts,
|
|
277
|
+
postURLScripts,
|
|
278
|
+
pageCompleteCheck,
|
|
260
279
|
options
|
|
261
280
|
);
|
|
262
281
|
|
|
@@ -425,8 +444,7 @@ export default class Engine {
|
|
|
425
444
|
if (Array.isArray(urlOrFile)) {
|
|
426
445
|
script = urlOrFile[1];
|
|
427
446
|
}
|
|
428
|
-
|
|
429
|
-
script = await loadScript(script, true);
|
|
447
|
+
script = await loadScript(script, options, true);
|
|
430
448
|
|
|
431
449
|
if (script.setUp) {
|
|
432
450
|
if (!options.preScript) {
|
|
@@ -7,10 +7,6 @@ import preURL from '../../support/preURL.js';
|
|
|
7
7
|
import setResourceTimingBufferSize from '../../support/setResourceTimingBufferSize.js';
|
|
8
8
|
import ScreenshotManager from '../../screenshot/index.js';
|
|
9
9
|
import ExtensionServer from '../../extensionserver/index.js';
|
|
10
|
-
import {
|
|
11
|
-
loadPrePostScriptsSync,
|
|
12
|
-
loadScriptSync
|
|
13
|
-
} from '../../support/engineUtils.js';
|
|
14
10
|
import Video from '../../video/video.js';
|
|
15
11
|
import stop from '../../support/stop.js';
|
|
16
12
|
import AddText from './command/addText.js';
|
|
@@ -61,19 +57,16 @@ export default class Iteration {
|
|
|
61
57
|
engineDelegate,
|
|
62
58
|
scriptsByCategory,
|
|
63
59
|
asyncScriptsByCategory,
|
|
60
|
+
preScripts,
|
|
61
|
+
postScripts,
|
|
62
|
+
postURLScripts,
|
|
63
|
+
pageCompleteCheck,
|
|
64
64
|
options
|
|
65
65
|
) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.pageCompleteCheck = options.pageCompleteCheck
|
|
71
|
-
? loadScriptSync(options.pageCompleteCheck)
|
|
72
|
-
: undefined;
|
|
73
|
-
} catch (error) {
|
|
74
|
-
log.error(error.message);
|
|
75
|
-
throw error;
|
|
76
|
-
}
|
|
66
|
+
this.preScripts = preScripts;
|
|
67
|
+
this.postScripts = postScripts;
|
|
68
|
+
this.postURLScripts = postURLScripts;
|
|
69
|
+
this.pageCompleteCheck = pageCompleteCheck;
|
|
77
70
|
this.options = options;
|
|
78
71
|
this.storageManager = storageManager;
|
|
79
72
|
this.engineDelegate = engineDelegate;
|
package/lib/support/cli.js
CHANGED
|
@@ -1194,6 +1194,12 @@ export function parseCommandLine() {
|
|
|
1194
1194
|
type: 'boolean',
|
|
1195
1195
|
default: false
|
|
1196
1196
|
})
|
|
1197
|
+
.option('cjs', {
|
|
1198
|
+
describe:
|
|
1199
|
+
'Load scripting files that ends with .js as common js. Default (false) loads files as esmodules.',
|
|
1200
|
+
type: 'boolean',
|
|
1201
|
+
default: false
|
|
1202
|
+
})
|
|
1197
1203
|
.option('browserRestartTries', {
|
|
1198
1204
|
type: 'number',
|
|
1199
1205
|
default: 3,
|
|
@@ -1,79 +1,70 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import {
|
|
1
|
+
import { resolve, dirname, join } from 'node:path';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { writeFile as _writeFile, access, unlink as _unlink } from 'node:fs';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
3
5
|
import dayjs from 'dayjs';
|
|
4
6
|
import intel from 'intel';
|
|
5
7
|
import { toArray } from '../support/util.js';
|
|
6
|
-
import {
|
|
7
|
-
removeFile,
|
|
8
|
-
copyFile,
|
|
9
|
-
removeFileSync,
|
|
10
|
-
copyFileSync
|
|
11
|
-
} from './fileUtil.js';
|
|
12
|
-
const require = createRequire(import.meta.url);
|
|
13
8
|
const log = intel.getLogger('browsertime');
|
|
9
|
+
const writeFile = promisify(_writeFile);
|
|
10
|
+
const unlink = promisify(_unlink);
|
|
14
11
|
|
|
15
12
|
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (script.endsWith('.js')) {
|
|
25
|
-
const name = script + '.cjs';
|
|
26
|
-
copyFileSync(script, name);
|
|
27
|
-
const data = require(resolve(name));
|
|
28
|
-
removeFileSync(name);
|
|
29
|
-
return data;
|
|
30
|
-
} else {
|
|
31
|
-
return require(resolve(script));
|
|
32
|
-
}
|
|
33
|
-
} catch (error) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
"Couldn't run pre/post script file: " + resolve(script) + ' ' + error
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
14
|
+
async function exists(path) {
|
|
15
|
+
try {
|
|
16
|
+
await access(path);
|
|
17
|
+
return true;
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
39
21
|
}
|
|
40
22
|
|
|
41
|
-
|
|
23
|
+
async function loadFile(script, options, throwError) {
|
|
24
|
+
// if the script is an AsyncFunction, return it.
|
|
42
25
|
if (script instanceof AsyncFunction) {
|
|
43
26
|
return script;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (script.endsWith('.js')) {
|
|
47
|
-
const name = script + '.cjs';
|
|
48
|
-
copyFileSync(script, name);
|
|
49
|
-
const data = require(resolve(name));
|
|
50
|
-
removeFileSync(name);
|
|
51
|
-
return data;
|
|
52
|
-
} else {
|
|
53
|
-
return require(resolve(script));
|
|
54
|
-
}
|
|
55
|
-
} catch {
|
|
56
|
-
// assume the script is a valid inline script by default
|
|
27
|
+
} else if (!script.endsWith('js')) {
|
|
28
|
+
// This is an inline script
|
|
57
29
|
return script;
|
|
58
30
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
31
|
+
// If we follow correct naming for modules (.mjs) or commonjs (.cjs)
|
|
32
|
+
// we just loads it. .js files is loaded as commonjs if you set
|
|
33
|
+
// --cjs true
|
|
34
|
+
if (
|
|
35
|
+
options.cjs === false ||
|
|
36
|
+
script.endsWith('.mjs') ||
|
|
37
|
+
script.endsWith('.cjs')
|
|
38
|
+
) {
|
|
39
|
+
let myFunction = await import(pathToFileURL(resolve(script)));
|
|
40
|
+
return myFunction.default ?? myFunction;
|
|
41
|
+
} else {
|
|
42
|
+
// Hack a way! Try to add a package.json file in the same folder as the
|
|
43
|
+
// script file. That way, the .js file will be treated as commonjs =
|
|
44
|
+
// working as before we moved Browsertime to module
|
|
45
|
+
let createdPackageJson = false;
|
|
67
46
|
try {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
await
|
|
71
|
-
|
|
72
|
-
await removeFile(name);
|
|
73
|
-
return data;
|
|
47
|
+
const packageJson = join(dirname(resolve(script)), 'package.json');
|
|
48
|
+
if (!(await exists(packageJson))) {
|
|
49
|
+
await writeFile(packageJson, '{}');
|
|
50
|
+
createdPackageJson = true;
|
|
74
51
|
} else {
|
|
75
|
-
|
|
52
|
+
log.error(
|
|
53
|
+
'Could not create package.json file, the %S file will be treated as a esmodule',
|
|
54
|
+
script
|
|
55
|
+
);
|
|
76
56
|
}
|
|
57
|
+
const myFunction = await import(resolve(script));
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
if (createdPackageJson) {
|
|
61
|
+
await unlink(packageJson);
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
log.error(error);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return myFunction.default ?? myFunction;
|
|
77
68
|
} catch (error) {
|
|
78
69
|
// assume the script is a valid inline script by default
|
|
79
70
|
if (throwError) {
|
|
@@ -86,6 +77,21 @@ export async function loadScript(script, throwError) {
|
|
|
86
77
|
}
|
|
87
78
|
}
|
|
88
79
|
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function loadPrePostScripts(scripts, options) {
|
|
83
|
+
const readScripts = [];
|
|
84
|
+
for (let script of toArray(scripts)) {
|
|
85
|
+
const loadedScript = await loadFile(script, options, true);
|
|
86
|
+
readScripts.push(loadedScript);
|
|
87
|
+
}
|
|
88
|
+
return readScripts;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function loadScript(script, options, throwError) {
|
|
92
|
+
if (script) {
|
|
93
|
+
return loadFile(script, options, throwError);
|
|
94
|
+
}
|
|
89
95
|
return script;
|
|
90
96
|
}
|
|
91
97
|
export function timestamp() {
|