From 2b578e4a096aa94d792cc2da2da41fee061a77b8 Mon Sep 17 00:00:00 2001 From: Thiago Perrotta Date: Sun, 15 Oct 2023 10:11:44 -0400 Subject: [PATCH] feat: merge user-provided --{disable,enable}-features in args (#11152) Bug: #11072 --- .../src/node/ChromeLauncher.test.ts | 47 +++++++++++++++++++ .../puppeteer-core/src/node/ChromeLauncher.ts | 33 ++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 packages/puppeteer-core/src/node/ChromeLauncher.test.ts diff --git a/packages/puppeteer-core/src/node/ChromeLauncher.test.ts b/packages/puppeteer-core/src/node/ChromeLauncher.test.ts new file mode 100644 index 0000000000000..9b1a57a2c3db8 --- /dev/null +++ b/packages/puppeteer-core/src/node/ChromeLauncher.test.ts @@ -0,0 +1,47 @@ +/** + * Copyright 2023 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {describe, it} from 'node:test'; + +import expect from 'expect'; + +import {getFeatures} from './ChromeLauncher.js'; + +describe('getFeatures', () => { + it('returns an empty array when no options are provided', () => { + const result = getFeatures('--foo'); + expect(result).toEqual([]); + }); + + it('returns an empty array when no options match the flag', () => { + const result = getFeatures('--foo', ['--bar', '--baz']); + expect(result).toEqual([]); + }); + + it('returns an array of values when options match the flag', () => { + const result = getFeatures('--foo', ['--foo=bar', '--foo=baz']); + expect(result).toEqual(['bar', 'baz']); + }); + + it('does not handle whitespace', () => { + const result = getFeatures('--foo', ['--foo bar', '--foo baz ']); + expect(result).toEqual([]); + }); + + it('handles equals sign around the flag and value', () => { + const result = getFeatures('--foo', ['--foo=bar', '--foo=baz ']); + expect(result).toEqual(['bar', 'baz']); + }); +}); diff --git a/packages/puppeteer-core/src/node/ChromeLauncher.ts b/packages/puppeteer-core/src/node/ChromeLauncher.ts index af8b59ab641e7..d6488bd07b547 100644 --- a/packages/puppeteer-core/src/node/ChromeLauncher.ts +++ b/packages/puppeteer-core/src/node/ChromeLauncher.ts @@ -166,6 +166,7 @@ export class ChromeLauncher extends ProductLauncher { override defaultArgs(options: BrowserLaunchArgumentOptions = {}): string[] { // See https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md + // Merge default disabled features with user-provided ones, if any. const disabledFeatures = [ 'Translate', // AcceptCHFrame disabled because of crbug.com/1348106. @@ -174,9 +175,14 @@ export class ChromeLauncher extends ProductLauncher { 'OptimizationHints', // https://crbug.com/1492053 'ProcessPerSiteUpToMainFrameThreshold', + ...getFeatures('--disable-features', options.args), ]; - const enabledFeatures = ['NetworkServiceInProcess2']; + // Merge default enabled features with user-provided ones, if any. + const enabledFeatures = [ + 'NetworkServiceInProcess2', + ...getFeatures('--enable-features', options.args), + ]; const chromeArguments = [ '--allow-pre-commit-input', @@ -266,3 +272,28 @@ function convertPuppeteerChannelToBrowsersChannel( return BrowsersChromeReleaseChannel.CANARY; } } + +/** + * Extracts all features from the given command-line flag + * (e.g. `--enable-features`, `--enable-features=`). + * + * Example input: + * ["--enable-features=NetworkService,NetworkServiceInProcess", "--enable-features=Foo"] + * + * Example output: + * ["NetworkService", "NetworkServiceInProcess", "Foo"] + * + * @internal + */ +export function getFeatures(flag: string, options: string[] = []): string[] { + return options + .filter(s => { + return s.startsWith(flag.endsWith('=') ? flag : `${flag}=`); + }) + .map(s => { + return s.split(new RegExp(`${flag}` + '=\\s*'))[1]?.trim(); + }) + .filter(s => { + return s; + }) as string[]; +}