browsertime 15.4.0 → 16.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Browsertime changelog (we do [semantic versioning](https://semver.org))
2
2
 
3
+
4
+ ## 16.1.0 - 2022-04-20
5
+ ### Fixed
6
+ * Handle negative x/y offsets when cropping images in the new portable visual metrocs script, thank you [Gregory Mierzwinski](https://github.com/gmierz) for PR [#1770](https://github.com/sitespeedio/browsertime/pull/1770).
7
+ * Bumped Throttle dependency [#1769](https://github.com/sitespeedio/browsertime/pull/1769).
8
+ * Bumped chrome-har, chrome-remote-interface, dayjs and yargs dependencies [#1771](https://github.com/sitespeedio/browsertime/pull/1771).
9
+ ### Added
10
+ * Added blocking of Chrome and Edge phone home domains [#1763](https://github.com/sitespeedio/browsertime/pull/1763).
11
+
12
+ ## 16.0.1 - 2022-04-06
13
+ ### Fixed
14
+ * If visual metrics fails and you also use --visualElements, make sure that file is also stored so we can reporduce the issue [#1757](https://github.com/sitespeedio/browsertime/pull/1757).
15
+ ## 16.0.0 - 2022-04-05
16
+ ### Changed
17
+ * When I introduced flushing of the DNS per run I missed that it makes you need to run sudo to do it (Mac/Linux). That sucks so instead of being able to disable the flushing `--disableDNSFlush` you now enables it with `--flushDNS` [#1752](https://github.com/sitespeedio/browsertime/pull/1752).
18
+
19
+ ### Added
20
+ * Firefox 99 in the Docker container
21
+ * Edge and Edgedriver 100
22
+
23
+ ### Fixed
24
+ * Automatically save the original video if visual metrics fails [#1755](https://github.com/sitespeedio/browsertime/pull/1755).
25
+
3
26
  ## 15.4.0 - 2022-03-30
4
27
  ### Added
5
28
  * Updated to Chrome and Chromedriver 100 [#1743](https://github.com/sitespeedio/browsertime/pull/1743).
@@ -108,6 +108,11 @@ def crop_im(img, crop_x, crop_y, crop_x_offset, crop_y_offset, gravity=None):
108
108
  base_x += crop_x_offset
109
109
  base_y += crop_y_offset
110
110
 
111
+ # Take the maximum in case the offset was negative, and
112
+ # smaller than the base position
113
+ base_x = max(base_x, 0)
114
+ base_y = max(base_y, 0)
115
+
111
116
  return Image.fromarray(
112
117
  img[base_y : base_y + crop_y, base_x : base_x + crop_x, :]
113
118
  )
@@ -137,7 +142,7 @@ def resize(img, width, height):
137
142
  def scale(img, maxsize):
138
143
  """Scale an image to the given max size."""
139
144
  width, height = img.size
140
- ratio = min(maxsize / width, maxsize / height)
145
+ ratio = min(float(maxsize) / width, float(maxsize) / height)
141
146
  return resize(img, int(width * ratio), int(height * ratio))
142
147
 
143
148
 
@@ -2109,9 +2114,10 @@ def calculate_contentful_speed_index(progress, directory):
2109
2114
  content.append(value)
2110
2115
 
2111
2116
  for i, value in enumerate(content):
2112
- content[i] = (
2113
- maxContent == 0 and 0.0 or float(content[i]) / float(maxContent)
2114
- )
2117
+ if maxContent > 0:
2118
+ content[i] = float(content[i]) / float(maxContent)
2119
+ else:
2120
+ content[i] = 0.0
2115
2121
 
2116
2122
  # Assume 0 content for first frame
2117
2123
  cont_si = 1 * (progress[1]["time"] - progress[0]["time"])
@@ -2286,47 +2292,52 @@ def calculate_hero_time(progress, directory, hero, viewport):
2286
2292
  def check_config():
2287
2293
  ok = True
2288
2294
 
2289
- print("ffmpeg: ")
2295
+
2290
2296
  if get_decimate_filter() is not None:
2291
- print("OK")
2297
+ logging.debug('FFMPEG found')
2298
+ else:
2299
+ print("ffmpeg: FAIL")
2300
+ ok = False
2301
+
2302
+
2303
+ if sys.version_info >= (3, 6):
2304
+ logging.debug('Python 3.6+ found')
2292
2305
  else:
2293
- print("FAIL")
2306
+ print("Python 3.6+: FAIL")
2294
2307
  ok = False
2295
2308
 
2296
- print("Numpy: ")
2297
2309
  try:
2298
2310
  import numpy as np
2299
2311
 
2300
- print("OK")
2312
+ logging.debug('Numpy found')
2301
2313
  except BaseException:
2302
- print("FAIL")
2314
+ print("Numpy: FAIL")
2303
2315
  ok = False
2304
2316
 
2305
- print("OpenCV-Python: ")
2317
+
2306
2318
  try:
2307
2319
  import cv2
2308
-
2309
- print("OK")
2320
+
2321
+ logging.debug('OpenCV-Python found')
2310
2322
  except BaseException:
2311
- print("FAIL")
2323
+ print("OpenCV-Python: FAIL")
2312
2324
  ok = False
2313
2325
 
2314
- print("Pillow: ")
2326
+
2315
2327
  try:
2316
2328
  from PIL import Image, ImageCms, ImageDraw, ImageOps # noqa
2317
2329
 
2318
- print("OK")
2330
+ logging.debug('Pillow found')
2319
2331
  except BaseException:
2320
- print("FAIL")
2332
+ print("Pillow: FAIL")
2321
2333
  ok = False
2322
2334
 
2323
- print("SSIM: ")
2335
+
2324
2336
  try:
2325
2337
  from ssim import compute_ssim # noqa
2326
-
2327
- print("OK")
2338
+ logging.debug('SSIM found')
2328
2339
  except BaseException:
2329
- print("FAIL")
2340
+ print("SSIM: FAIL")
2330
2341
  ok = False
2331
2342
 
2332
2343
  return ok
@@ -2656,6 +2667,13 @@ def main():
2656
2667
  ok = False
2657
2668
  try:
2658
2669
  if not options.check:
2670
+ # Run a quick check to make sure all requirements exist,
2671
+ # otherwise failures might be silent due to how this code is
2672
+ # structured.
2673
+ ok = check_config()
2674
+ if not ok:
2675
+ raise Exception("Please install requirements before running.")
2676
+
2659
2677
  if options.video:
2660
2678
  orange_file = None
2661
2679
  if options.orange:
@@ -3,6 +3,8 @@ Firefox Examples
3
3
 
4
4
  This page shows a few of the options specific to Firefox.
5
5
 
6
- browsertime https://www.sitespeed.io --firefox.binaryPath '/Applications/Firefox.app/Contents/MacOS/firefox-bin'
6
+ ```
7
+ browsertime https://www.sitespeed.io -b firefox --firefox.binaryPath '/Applications/Firefox.app/Contents/MacOS/firefox-bin'
8
+ ```
7
9
 
8
10
  - Path to custom Firefox binary (e.g. Firefox Nightly). On OS X, the path should be to the binary inside the app bundle. (e.g. /Applications/Firefox.app/Contents/MacOS/firefox-bin)
@@ -5,6 +5,17 @@ const getViewPort = require('../../support/getViewPort');
5
5
  const util = require('../../support/util');
6
6
  const log = require('intel').getLogger('browsertime.chrome');
7
7
 
8
+ const CHROME_AMD_EDGE_INTERNAL_PHONE_HOME = [
9
+ '"MAP cache.pack.google.com 127.0.0.1"',
10
+ '"MAP clients1.google.com 127.0.0.1"',
11
+ '"MAP update.googleapis.com 127.0.0.1"',
12
+ '"MAP redirector.gvt1.com 127.0.0.1"',
13
+ '"MAP laptop-updates.brave.com 127.0.0.1"',
14
+ '"MAP offlinepages-pa.googleapis.com 127.0.0.1"',
15
+ '"MAP edge.microsoft.com 127.0.0.1"',
16
+ '"MAP optimizationguide-pa.googleapis.com 127.0.0.1"'
17
+ ];
18
+
8
19
  module.exports = function (seleniumOptions, browserOptions, options, baseDir) {
9
20
  // Fixing save password popup, only on Desktop
10
21
  if (!options.android) {
@@ -64,6 +75,17 @@ module.exports = function (seleniumOptions, browserOptions, options, baseDir) {
64
75
  excludes += 'MAP * 127.0.0.1, EXCLUDE ' + domain + ',';
65
76
  }
66
77
  seleniumOptions.addArguments('--host-resolver-rules=' + excludes);
78
+ } else {
79
+ // Make sure we only set this if we do not have any other host resolver rules
80
+ const chromeCommandLineArgs = util.toArray(browserOptions.args);
81
+ const argsWithHostResolverRules = chromeCommandLineArgs.filter(arg =>
82
+ arg.includes('host-resolver-rules')
83
+ );
84
+ if (argsWithHostResolverRules.length === 0) {
85
+ seleniumOptions.addArguments(
86
+ '--host-resolver-rules=' + CHROME_AMD_EDGE_INTERNAL_PHONE_HOME.join(',')
87
+ );
88
+ }
67
89
  }
68
90
 
69
91
  if (options.extension) {
@@ -102,7 +102,7 @@ class Iteration {
102
102
  const engineDelegate = this.engineDelegate;
103
103
 
104
104
  try {
105
- if (!options.disableDNSFlush === true) {
105
+ if (options.flushDNS) {
106
106
  await flushDNS(options);
107
107
  }
108
108
  if (options.connectivity && options.connectivity.variance) {
@@ -1117,6 +1117,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
1117
1117
  describe:
1118
1118
  'Start gnirehtet and reverse tethering the traffic from your Android phone.'
1119
1119
  })
1120
+ .option('flushDNS', {
1121
+ type: 'boolean',
1122
+ default: false,
1123
+ describe:
1124
+ 'Flush DNS between runs, works on Mac OS and Linux. Your user needs sudo rights to be able to flush the DNS.'
1125
+ })
1120
1126
  .option('extension', {
1121
1127
  describe:
1122
1128
  'Path to a WebExtension to be installed in the browser. Note that --extension can be passed multiple times.'
@@ -14,7 +14,7 @@ module.exports = async function (options) {
14
14
  }
15
15
 
16
16
  if (process.platform === 'darwin') {
17
- log.debug('Flush DNS cache on MacOS');
17
+ log.info('Flush DNS cache on MacOS');
18
18
  await execa('sudo', ['killall', '-HUP', 'mDNSResponder'], {
19
19
  reject: false
20
20
  });
@@ -25,7 +25,7 @@ module.exports = async function (options) {
25
25
  reject: false
26
26
  });
27
27
  } else if (process.platform === 'linux') {
28
- log.debug('Flush DNS cache on Linux');
28
+ log.info('Flush DNS cache on Linux');
29
29
  await execa('sudo', ['systemd-resolve', '--flush-caches'], {
30
30
  reject: false
31
31
  });
@@ -6,6 +6,7 @@ const readdir = promisify(fs.readdir);
6
6
  const lstat = promisify(fs.lstat);
7
7
  const unlink = promisify(fs.unlink);
8
8
  const rmdir = promisify(fs.rmdir);
9
+ const copyFile = promisify(fs.copyFile);
9
10
  const rename = promisify(fs.rename);
10
11
  const readFile = promisify(fs.readFile);
11
12
  const filters = require('./filters');
@@ -15,6 +16,9 @@ module.exports = {
15
16
  async rename(old, newName) {
16
17
  return rename(old, newName);
17
18
  },
19
+ async copyFile(source, destination) {
20
+ return copyFile(source, destination);
21
+ },
18
22
  async removeFile(fileName) {
19
23
  return unlink(fileName);
20
24
  },
@@ -9,6 +9,7 @@ const fs = require('fs');
9
9
  const get = require('lodash.get');
10
10
  const { promisify } = require('util');
11
11
  const rename = promisify(fs.rename);
12
+ const copyFile = promisify(fs.copyFile);
12
13
  const unlink = promisify(fs.unlink);
13
14
  const defaults = require('../../defaults');
14
15
 
@@ -23,6 +24,11 @@ module.exports = async function (
23
24
  const newStart = videoMetrics.videoRecordingStart / 1000;
24
25
  let tmpFile = path.join(videoDir, 'tmp.mp4');
25
26
 
27
+ if (get(options, 'videoParams.keepOriginalVideo', false)) {
28
+ const originalFile = path.join(videoDir, index + '-original.mp4');
29
+ await copyFile(videoPath, originalFile);
30
+ }
31
+
26
32
  // if there's no orange (too slow instance like travis?)
27
33
  // we don't wanna cut
28
34
  if (videoMetrics.videoRecordingStart > 0) {
@@ -45,11 +51,6 @@ module.exports = async function (
45
51
  tmpFile = videoPath;
46
52
  }
47
53
 
48
- if (get(options, 'videoParams.keepOriginalVideo', false)) {
49
- const originalFile = path.join(videoDir, index + '-original.mp4');
50
- await rename(videoPath, originalFile);
51
- }
52
-
53
54
  if (
54
55
  options.android &&
55
56
  get(options, 'videoParams.convert', defaults.convert)
@@ -4,7 +4,7 @@ const execa = require('execa');
4
4
  const log = require('intel').getLogger('browsertime.video');
5
5
  const get = require('lodash.get');
6
6
  const path = require('path');
7
- const { readFile, removeFile } = require('../../../support/fileUtil');
7
+ const { readFile, removeFile, copyFile } = require('../../../support/fileUtil');
8
8
 
9
9
  const SCRIPT_PATH = path.join(
10
10
  __dirname,
@@ -149,6 +149,12 @@ module.exports = {
149
149
  return JSON.parse(result.stdout);
150
150
  } catch (e) {
151
151
  log.error('VisualMetrics failed to run', e);
152
+ await copyFile(videoPath, videoPath + '.failed.mp4');
153
+
154
+ if (options.visualElements) {
155
+ await copyFile(elementsFile, elementsFile + '.failed.json');
156
+ }
157
+
152
158
  // If something goes wrong, dump the visual metrics log to our log
153
159
  const visualMetricLog = await readFile(visualMetricsLogFile);
154
160
  log.error('Log from VisualMetrics: %s', visualMetricLog);
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "description": "Browsertime",
3
- "version": "15.4.0",
3
+ "version": "16.1.0",
4
4
  "bin": "./bin/browsertime.js",
5
5
  "dependencies": {
6
6
  "@cypress/xvfb": "1.2.4",
7
7
  "@devicefarmer/adbkit": "2.11.3",
8
8
  "@sitespeed.io/chromedriver": "100.0.4896-20",
9
- "@sitespeed.io/edgedriver": "99.0.1150-25",
9
+ "@sitespeed.io/edgedriver": "100.0.1185-29",
10
10
  "@sitespeed.io/geckodriver": "0.30.0",
11
- "@sitespeed.io/throttle": "3.0.0",
11
+ "@sitespeed.io/throttle": "3.1.1",
12
12
  "@sitespeed.io/tracium": "0.3.3",
13
13
  "btoa": "1.2.1",
14
- "chrome-har": "0.12.0",
15
- "chrome-remote-interface": "0.31.0",
16
- "dayjs": "1.10.7",
14
+ "chrome-har": "0.13.0",
15
+ "chrome-remote-interface": "0.31.2",
16
+ "dayjs": "1.11.1",
17
17
  "execa": "5.1.1",
18
18
  "fast-stats": "0.0.6",
19
19
  "find-up": "5.0.0",
@@ -27,7 +27,7 @@
27
27
  "lodash.pick": "4.4.0",
28
28
  "lodash.set": "4.3.2",
29
29
  "selenium-webdriver": "4.1.1",
30
- "yargs": "17.2.1"
30
+ "yargs": "17.4.1"
31
31
  },
32
32
  "optionalDependencies": {
33
33
  "jimp": "0.16.1"
@@ -42,7 +42,7 @@
42
42
  "serve": "13.0.2"
43
43
  },
44
44
  "engines": {
45
- "node": ">=10.13.0"
45
+ "node": ">=14.19.1"
46
46
  },
47
47
  "files": [
48
48
  "CHANGELOG.md",