From 724dbd54815e37b3f07f7d31154e6ed33d7d23ca Mon Sep 17 00:00:00 2001 From: Alexander Marks Date: Mon, 27 Sep 2021 14:41:55 -0700 Subject: [PATCH] Add `browser.profile` setting and fix Firefox `addArguments` bug (#226) This PR adds a new browser.profile JSON config setting which can be used like this: { "benchmarks": [ { "url": "mybench.html", "browser": { "name": "firefox", "profile": "/Users//Library/Application Support/Firefox/Profiles/" } } ] } It also fixes a bug where addArguments was not being applied to Firefox, even though it was documented that it was supported. For Chrome, it was previously supported and documented to use "addArguments": ["user-data-dir="] to achieve this same effect, but I found that the equivalent for Firefox ("-profile=") caused Selenium to timeout trying to connect to the process. I wasn't able to figure out exactly why this was happening, but I did notice a dedicated setProfile method just for Firefox, which does work. So by adding the browser.profile setting, we now have a way to call this special API, plus the user doesn't need to remember the user-data-dir flag in Chrome. Fixes #222 Also threw in a fix to tests relating to chromedriver having updated to Chrome 94 while GitHub Actions is still on Chrome 93. --- .github/workflows/tests.yaml | 4 +++ CHANGELOG.md | 6 ++++ README.md | 67 ++++++++++++++++++++++++++++-------- config.schema.json | 8 +++++ src/browser.ts | 16 +++++++++ src/configfile.ts | 15 ++++++++ 6 files changed, 102 insertions(+), 14 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index ee48f6d..78e7afa 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -28,6 +28,10 @@ jobs: cache: npm - run: npm ci + # TODO(aomarks) The latest chromedriver has updated to 94, but GitHub + # Actions hasn't updated yet. Pin to the earlier verison of chromedriver + # until GitHub Actions updated. + - run: npm install chromedriver@^93.0.0 - run: npm run build - run: npm test diff --git a/CHANGELOG.md b/CHANGELOG.md index 036d157..f7fe3b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ project adheres to [Semantic Versioning](http://semver.org/). - Fix bug where log files would be created with '\' backslash names instead of nested directories. +- Fix bug where `browser.addArguments` JSON config setting did not work for + Firefox. + +- Add `browser.profile` JSON config setting that sets the browser profile + directory. Currently supported in Chrome and Firefox. + - Upgrade dependencies. ## [0.5.9] 2021-04-22 diff --git a/README.md b/README.md index cb08fd5..20b74f0 100644 --- a/README.md +++ b/README.md @@ -538,26 +538,65 @@ However, in some cases it may be useful to use an existing browser profile, for example if the webpage you are benchmarking requires being signed into an account. -In Chrome, you can use the `user-data-dir` flag to launch the browser using an -existing profile directory. You may also need to remove the `use-mock-keychain` -default argument if you encounter authentication problems. You can find out the -current binary path, profile location, and arguments of a running Chrome session -by visiting the `chrome://version` URL. +In Chrome and Firefox, use the `profile` JSON config option to specify an +existing profile to use. Other browsers do not yet support this option. -NOTE: If there is an existing Chrome process using the profile, you must -first terminate it. You also need to close all open tabs, or disable the -"Continue where you left off" startup setting, because tachometer does not -expect to find any existing tabs. +#### Chrome + +To find your current profile location in Chrome, visit `chrome://version` and +look for "Profile Path". + +If there is an existing Chrome process using this profile, you must first +terminate it. You also need to close all open tabs, or disable the "Continue +where you left off" startup setting, because tachometer does not expect to find +any existing tabs. + +You may also need to remove the `use-mock-keychain` default argument if you +encounter authentication problems. For example, using the standard location of the default user profile on macOS: ```json { - "name": "chrome", - "addArguments": [ - "user-data-dir=/Users//Library/Application Support/Google/Chrome" - ], - "removeArguments": ["use-mock-keychain"] + "benchmarks": [ + { + "url": "mybench.html", + "browser": { + "name": "chrome", + "profile": "/Users//Library/Application Support/Google/Chrome", + "removeArguments": ["use-mock-keychain"] + } + } + ] +} +``` + +#### Firefox + +To find your current profile location in Firefox, visit `about:support` and look +for "Profile Folder" or "Profile Directory". + +Note when using the `profile` option in Firefox, the profile directory is copied +to a temporary location. + + + +You may encounter a `no such file or directory, stat '.../lock'` error, due to a +bug in `selenium-webdriver`. Deleting this `lock` file should resolve the error. + +For example, using the standard location of user profiles on macOS: + +```json +{ + "benchmarks": [ + { + "url": "mybench.html", + "browser": { + "name": "firefox", + "profile": "/Users//Library/Application Support/Firefox/Profiles/" + } + } + ] } ``` diff --git a/config.schema.json b/config.schema.json index b0817c9..41a6619 100644 --- a/config.schema.json +++ b/config.schema.json @@ -50,6 +50,10 @@ ], "type": "string" }, + "profile": { + "description": "Path to a profile directory to use instead of the default temporary fresh\none.", + "type": "string" + }, "remoteUrl": { "description": "A remote WebDriver server HTTP address to launch the browser from.", "type": "string" @@ -291,6 +295,10 @@ "description": "Advanced preferences that are usually set from the about:config page\nin Firefox (see\nhttps://support.mozilla.org/en-US/kb/about-config-editor-firefox).", "type": "object" }, + "profile": { + "description": "Path to a profile directory to use instead of the default temporary fresh\none.", + "type": "string" + }, "remoteUrl": { "description": "A remote WebDriver server HTTP address to launch the browser from.", "type": "string" diff --git a/src/browser.ts b/src/browser.ts index 747816a..584e8eb 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -68,6 +68,8 @@ export interface BrowserConfig { preferences?: {[name: string]: string | number | boolean}; /** Trace browser performance logs configuration */ trace?: TraceConfig; + /** Path to profile directory to use instead of the default fresh one. */ + profile?: string; } /** @@ -105,6 +107,7 @@ export function browserSignature(config: BrowserConfig): string { config.removeArguments ?? [], config.cpuThrottlingRate ?? 1, config.preferences ?? {}, + config.profile ?? '', ]); } @@ -243,6 +246,9 @@ function chromeOpts(config: BrowserConfig): chrome.Options { } const {width, height} = config.windowSize; opts.addArguments(`--window-size=${width},${height}`); + if (config.profile) { + opts.addArguments(`user-data-dir=${config.profile}`); + } return opts; } @@ -262,6 +268,16 @@ function firefoxOpts(config: BrowserConfig): firefox.Options { const {width, height} = config.windowSize; opts.addArguments(`-width=${width}`); opts.addArguments(`-height=${height}`); + if (config.addArguments) { + opts.addArguments(...config.addArguments); + } + if (config.profile) { + // Note there is also a `-profile` flag for Firefox that could be set with + // `addArguments`, but using that causes Selenium to timeout trying to + // connect to the browser process. This `setProfile` method creates a + // temporary copy of the profile. + opts.setProfile(config.profile); + } return opts; } diff --git a/src/configfile.ts b/src/configfile.ts index cfb5810..e222166 100644 --- a/src/configfile.ts +++ b/src/configfile.ts @@ -241,6 +241,12 @@ interface ChromeConfig extends BrowserConfigBase { * Optional config to turn on performance tracing. */ trace?: TraceConfig | true; + + /** + * Path to a profile directory to use instead of the default temporary fresh + * one. + */ + profile?: string; } /** @@ -285,6 +291,12 @@ interface FirefoxConfig extends BrowserConfigBase { * https://support.mozilla.org/en-US/kb/about-config-editor-firefox). */ preferences?: {[name: string]: string | number | boolean}; + + /** + * Path to a profile directory to use instead of the default temporary fresh + * one. + */ + profile?: string; } interface SafariConfig extends BrowserConfigBase { @@ -526,6 +538,9 @@ function parseBrowserObject(config: BrowserConfigs): BrowserConfig { }; } } + if ('profile' in config && config.profile !== undefined) { + parsed.profile = config.profile; + } return parsed; }