From dcc1d538839a037f877917f12d61999bdd3b4a21 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 20 Jul 2024 20:53:37 +0200 Subject: [PATCH 01/14] feat: Implement expand-prefs with tests --- src/extension-runners/chromium.js | 44 ++++++++++----- src/util/expand-prefs.js | 32 +++++++++++ tests/unit/test-util/test.expand-prefs.js | 68 +++++++++++++++++++++++ 3 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 src/util/expand-prefs.js create mode 100644 tests/unit/test-util/test.expand-prefs.js diff --git a/src/extension-runners/chromium.js b/src/extension-runners/chromium.js index a2f91d813c..be90dbb65b 100644 --- a/src/extension-runners/chromium.js +++ b/src/extension-runners/chromium.js @@ -7,14 +7,15 @@ import fs from 'fs/promises'; import path from 'path'; import { - Launcher as ChromeLauncher, launch as defaultChromiumLaunch, + Launcher as ChromeLauncher, } from 'chrome-launcher'; import { createLogger } from '../util/logger.js'; import { TempDir } from '../util/temp-dir.js'; import isDirectory from '../util/is-directory.js'; import fileExists from '../util/file-exists.js'; +import expandPrefs from '../util/expand-prefs.js'; const log = createLogger(import.meta.url); @@ -28,6 +29,10 @@ export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter( (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag), ); +const DEFAULT_PREFS = { + 'extensions.ui.developer_mode': true, +}; + // This is a client for the Chrome Devtools protocol. The methods and results // are documented at https://chromedevtools.github.io/devtools-protocol/tot/ class ChromeDevtoolsProtocolClient { @@ -167,19 +172,6 @@ export class ChromiumExtensionRunner { // Method exported from the IExtensionRunner interface. - /** - * Returns the runner name. - */ - getName() { - return 'Chromium'; - } - - async run() { - // Run should never be called more than once. - this._promiseSetupDone = this.setupInstance(); - await this._promiseSetupDone; - } - static async isUserDataDir(dirPath) { const localStatePath = path.join(dirPath, 'Local State'); const defaultPath = path.join(dirPath, 'Default'); @@ -222,6 +214,19 @@ export class ChromiumExtensionRunner { }; } + /** + * Returns the runner name. + */ + getName() { + return 'Chromium'; + } + + async run() { + // Run should never be called more than once. + this._promiseSetupDone = this.setupInstance(); + await this._promiseSetupDone; + } + /** * Setup the Chromium Profile and run a Chromium instance. */ @@ -598,4 +603,15 @@ export class ChromiumExtensionRunner { } } } + + /** + * Returns a deep preferences object based on a set of flat preferences, like + * "extensions.ui.developer_mode". + */ + getPrefs() { + return expandPrefs({ + ...DEFAULT_PREFS, + ...this.params.customPrefs, + }); + } } diff --git a/src/util/expand-prefs.js b/src/util/expand-prefs.js new file mode 100644 index 0000000000..70fe95dd48 --- /dev/null +++ b/src/util/expand-prefs.js @@ -0,0 +1,32 @@ +/** + * Given an object where the keys are the flattened path to a + * preference, and the value is the value to set at that path, return + * an object where the paths are fully expanded. + */ +export default function expandPrefs(prefs) { + const prefsMap = new Map(); + for (const [key, value] of Object.entries(prefs)) { + let submap = prefsMap; + const props = key.split('.'); + const lastProp = props.pop(); + for (const prop of props) { + if (!submap.has(prop)) { + submap.set(prop, new Map()); + } + submap = submap.get(prop); + if (!(submap instanceof Map)) { + throw new Error( + `Cannot set ${key} because a value already exists at ${prop}`, + ); + } + } + submap.set(lastProp, value); + } + return mapToObject(prefsMap); +} + +function mapToObject(map) { + return Object.fromEntries( + Array.from(map, ([k, v]) => [k, v instanceof Map ? mapToObject(v) : v]), + ); +} diff --git a/tests/unit/test-util/test.expand-prefs.js b/tests/unit/test-util/test.expand-prefs.js new file mode 100644 index 0000000000..7e74d8da8c --- /dev/null +++ b/tests/unit/test-util/test.expand-prefs.js @@ -0,0 +1,68 @@ +import { assert, expect } from 'chai'; +import { describe, it } from 'mocha'; + +import expandPrefs from '../../../src/util/expand-prefs.js'; + +describe('utils/expand-prefs', () => { + it('expands dot-deliminated preferences into a deep object', () => { + const input = { + a: 'a', + 'b.c': 'c', + 'd.e.f': 'f', + }; + const expected = { + a: 'a', + b: { + c: 'c', + }, + d: { + e: { + f: 'f', + }, + }, + }; + const actual = expandPrefs(input); + + assert.deepEqual(actual, expected); + }); + + it("doesn't pollute the object prototype", () => { + const call = 'overriden'; + const input = { + 'hasOwnProperty.call': call, + }; + const expected = { + hasOwnProperty: { + call, + }, + }; + const actual = expandPrefs(input); + + assert.notEqual(Object.prototype.hasOwnProperty.call, call); + assert.deepEqual(actual, expected); + }); + + it('throws an error when setting the child property of an already set parent', () => { + const input = { + a: 'a', + 'a.b': 'b', + }; + + expect(() => expandPrefs(input)).to.throw( + 'Cannot set a.b because a value already exists at a', + ); + }); + + it('allows overriding a parent even if a child has already been set', () => { + const input = { + 'a.b': 'b', + a: 'a', + }; + const expected = { + a: 'a', + }; + const actual = expandPrefs(input); + + assert.deepEqual(actual, expected); + }); +}); From 0942b7b798e916cc4b65ebabf4f8e382031cf93c Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Fri, 20 Mar 2026 11:56:26 +0100 Subject: [PATCH 02/14] Implement chromiumPref with tests --- src/cmd/run.js | 7 +++ src/extension-runners/chromium.js | 11 ++-- src/program.js | 17 +++++- src/util/chromium-preferences.js | 30 +++++++++++ src/util/expand-prefs.js | 5 +- tests/unit/test-cmd/test.run.js | 18 ++++++- .../test-extension-runners/test.chromium.js | 34 ++++++++++-- .../test-util/test.chromium-preferences.js | 54 +++++++++++++++++++ tests/unit/test-util/test.expand-prefs.js | 30 +++++------ tests/unit/test.program.js | 21 ++++++++ 10 files changed, 195 insertions(+), 32 deletions(-) create mode 100644 src/util/chromium-preferences.js create mode 100644 tests/unit/test-util/test.chromium-preferences.js diff --git a/src/cmd/run.js b/src/cmd/run.js index d07d8df6dd..b619ca724a 100644 --- a/src/cmd/run.js +++ b/src/cmd/run.js @@ -51,6 +51,7 @@ export default async function run( firefoxApkComponent, // Chromium CLI options. chromiumBinary, + chromiumPref = new Map(), chromiumProfile, }, { @@ -84,6 +85,11 @@ export default async function run( // Create an alias for --pref since it has been transformed into an // object containing one or more preferences. const customPrefs = pref; + + // Create an alias for --chromium-pref since it has been transformed into an + // object containing one or more preferences. + const customChromiumPrefs = chromiumPref; + const manifestData = await getValidatedManifest(sourceDir); const profileDir = firefoxProfile || chromiumProfile; @@ -191,6 +197,7 @@ export default async function run( ...commonRunnerParams, verbose, chromiumBinary, + customChromiumPrefs, chromiumProfile, }; diff --git a/src/extension-runners/chromium.js b/src/extension-runners/chromium.js index be90dbb65b..987f66be19 100644 --- a/src/extension-runners/chromium.js +++ b/src/extension-runners/chromium.js @@ -29,9 +29,7 @@ export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter( (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag), ); -const DEFAULT_PREFS = { - 'extensions.ui.developer_mode': true, -}; +const DEFAULT_PREFS = new Map([['extensions.ui.developer_mode', true]]); // This is a client for the Chrome Devtools protocol. The methods and results // are documented at https://chromedevtools.github.io/devtools-protocol/tot/ @@ -609,9 +607,8 @@ export class ChromiumExtensionRunner { * "extensions.ui.developer_mode". */ getPrefs() { - return expandPrefs({ - ...DEFAULT_PREFS, - ...this.params.customPrefs, - }); + return expandPrefs( + new Map([...DEFAULT_PREFS, ...this.params.customChromiumPrefs]), + ); } } diff --git a/src/program.js b/src/program.js index 5daca429ba..4e1322f07c 100644 --- a/src/program.js +++ b/src/program.js @@ -10,15 +10,16 @@ import { Parser as yargsParser } from 'yargs/helpers'; import defaultCommands from './cmd/index.js'; import { UsageError } from './errors.js'; import { - createLogger, consoleStream as defaultLogStream, + createLogger, } from './util/logger.js'; import { coerceCLICustomPreference } from './firefox/preferences.js'; +import { coerceCLICustomChromiumPreference } from './util/chromium-preferences.js'; import { checkForUpdates as defaultUpdateChecker } from './util/updates.js'; import { + applyConfigToArgv as defaultApplyConfigToArgv, discoverConfigFiles as defaultConfigDiscovery, loadJSConfigFile as defaultLoadJSConfigFile, - applyConfigToArgv as defaultApplyConfigToArgv, } from './config.js'; const log = createLogger(import.meta.url); @@ -619,6 +620,18 @@ Example: $0 --help run. demandOption: false, type: 'string', }, + 'chromium-pref': { + describe: + 'Launch chromium with a custom preference ' + + '(example: --chromium-pref=browser.theme.follows_system_colors=false). ' + + 'You can repeat this option to set more than one ' + + 'preference.', + demandOption: false, + requiresArg: true, + type: 'array', + coerce: (arg) => + arg != null ? coerceCLICustomChromiumPreference(arg) : undefined, + }, 'chromium-profile': { describe: 'Path to a custom Chromium profile', demandOption: false, diff --git a/src/util/chromium-preferences.js b/src/util/chromium-preferences.js new file mode 100644 index 0000000000..80a81373e3 --- /dev/null +++ b/src/util/chromium-preferences.js @@ -0,0 +1,30 @@ +import { UsageError } from '../errors.js'; + +export function coerceCLICustomChromiumPreference(cliPrefs) { + const chromiumPrefs = new Map(); + + for (const pref of cliPrefs) { + const prefsAry = pref.split('='); + + if (prefsAry.length < 2) { + throw new UsageError( + `Incomplete custom preference: "${pref}". ` + + 'Syntax expected: "prefname=prefvalue".', + ); + } + + const key = prefsAry[0]; + let value = prefsAry.slice(1).join('='); + + + if (value === `${parseInt(value)}`) { + value = parseInt(value, 10); + } else if (value === 'true' || value === 'false') { + value = value === 'true'; + } + + chromiumPrefs.set(key, value); + } + + return chromiumPrefs; +} diff --git a/src/util/expand-prefs.js b/src/util/expand-prefs.js index 70fe95dd48..b5b2f23fcc 100644 --- a/src/util/expand-prefs.js +++ b/src/util/expand-prefs.js @@ -1,11 +1,12 @@ /** - * Given an object where the keys are the flattened path to a + * Given a Map where the keys are the flattened path to a * preference, and the value is the value to set at that path, return * an object where the paths are fully expanded. */ export default function expandPrefs(prefs) { const prefsMap = new Map(); - for (const [key, value] of Object.entries(prefs)) { + + for (const [key, value] of prefs) { let submap = prefsMap; const props = key.split('.'); const lastProp = props.pop(); diff --git a/tests/unit/test-cmd/test.run.js b/tests/unit/test-cmd/test.run.js index 19f5f88e4c..b248e5687b 100644 --- a/tests/unit/test-cmd/test.run.js +++ b/tests/unit/test-cmd/test.run.js @@ -7,8 +7,8 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; import { - fixturePath, FakeExtensionRunner, + fixturePath, getFakeFirefox, getFakeRemoteFirefox, mockModule, @@ -341,6 +341,22 @@ describe('run', () => { ); }); + it('provides chromium custom preferences to the Chromium runner params', async () => { + const fakeChromiumPref = new Map([['extensions.ui.developer_mode', false]]); + const cmd = await prepareRun(); + await cmd.run({ + target: ['chromium'], + chromiumPref: fakeChromiumPref, + }); + + sinon.assert.calledWithMatch(chromiumRunnerStub, { + customChromiumPrefs: sinon.match.instanceOf(Map), + }); + + const { customChromiumPrefs } = chromiumRunnerStub.firstCall.args[0]; + assert.strictEqual(customChromiumPrefs, fakeChromiumPref); + }); + it('creates multiple extension runners', async () => { const cmd = await prepareRun(); await cmd.run({ target: ['firefox-android', 'firefox-desktop'] }); diff --git a/tests/unit/test-extension-runners/test.chromium.js b/tests/unit/test-extension-runners/test.chromium.js index c3a22a116f..d31e9a89f4 100644 --- a/tests/unit/test-extension-runners/test.chromium.js +++ b/tests/unit/test-extension-runners/test.chromium.js @@ -2,7 +2,7 @@ import path from 'path'; import EventEmitter from 'events'; import { assert } from 'chai'; -import { describe, it, beforeEach } from 'mocha'; +import { beforeEach, describe, it } from 'mocha'; import deepcopy from 'deepcopy'; import fs from 'fs-extra'; import * as sinon from 'sinon'; @@ -12,9 +12,7 @@ import { ChromiumExtensionRunner, DEFAULT_CHROME_FLAGS, } from '../../../src/extension-runners/chromium.js'; -import { - consoleStream, // instance is imported to inspect logged messages -} from '../../../src/util/logger.js'; +import { consoleStream } from '../../../src/util/logger.js'; import { TempDir, withTempDir } from '../../../src/util/temp-dir.js'; import fileExists from '../../../src/util/file-exists.js'; import isDirectory from '../../../src/util/is-directory.js'; @@ -602,6 +600,34 @@ describe('util/extension-runners/chromium', async () => { sinon.assert.calledOnce(fakeChromeInstance.kill); }); + describe('getPrefs', () => { + it('merges default and custom preferences from a Map', () => { + const { params } = prepareExtensionRunnerParams({ + params: { + customChromiumPrefs: new Map([ + ['extensions.ui.developer_mode', false], + ['browser.theme.color', 'dark'], + ]), + }, + }); + + const runnerInstance = new ChromiumExtensionRunner(params); + + assert.deepEqual(runnerInstance.getPrefs(), { + extensions: { + ui: { + developer_mode: false, + }, + }, + browser: { + theme: { + color: 'dark', + }, + }, + }); + }); + }); + describe('reloadAllExtensions', () => { let runnerInstance; diff --git a/tests/unit/test-util/test.chromium-preferences.js b/tests/unit/test-util/test.chromium-preferences.js new file mode 100644 index 0000000000..1bdce2e724 --- /dev/null +++ b/tests/unit/test-util/test.chromium-preferences.js @@ -0,0 +1,54 @@ +import { describe, it } from 'mocha'; +import { assert } from 'chai'; + +import { UsageError } from '../../../src/errors.js'; +import { coerceCLICustomChromiumPreference } from '../../../src/util/chromium-preferences.js'; + +describe('util/chromium-preferences', () => { + describe('coerceCLICustomChromiumPreference', () => { + it('converts cli preferences into a Map', () => { + const prefs = coerceCLICustomChromiumPreference([ + 'extensions.ui.developer_mode=false', + 'browser.theme.color=dark', + ]); + + assert.instanceOf(prefs, Map); + assert.strictEqual(prefs.get('extensions.ui.developer_mode'), false); + assert.strictEqual(prefs.get('browser.theme.color'), 'dark'); + }); + + it('converts integer values', () => { + const prefs = coerceCLICustomChromiumPreference(['some.int.pref=455']); + + assert.strictEqual(prefs.get('some.int.pref'), 455); + }); + + it('supports string values containing equals signs', () => { + const prefs = coerceCLICustomChromiumPreference([ + 'some.string.pref=value=with=equals', + ]); + + assert.strictEqual(prefs.get('some.string.pref'), 'value=with=equals'); + }); + + it('throws on incomplete preferences', () => { + assert.throws( + () => coerceCLICustomChromiumPreference(['invalid.preference']), + UsageError, + 'Incomplete custom preference: "invalid.preference". ' + + 'Syntax expected: "prefname=prefvalue".', + ); + }); + + it('accepts permissive Chromium preference keys', () => { + const prefs = coerceCLICustomChromiumPreference([ + 'net.http.server_properties:https://example.com=true', + ]); + + assert.strictEqual( + prefs.get('net.http.server_properties:https://example.com'), + true, + ); + }); + }); +}); diff --git a/tests/unit/test-util/test.expand-prefs.js b/tests/unit/test-util/test.expand-prefs.js index 7e74d8da8c..1e4a082735 100644 --- a/tests/unit/test-util/test.expand-prefs.js +++ b/tests/unit/test-util/test.expand-prefs.js @@ -5,11 +5,11 @@ import expandPrefs from '../../../src/util/expand-prefs.js'; describe('utils/expand-prefs', () => { it('expands dot-deliminated preferences into a deep object', () => { - const input = { - a: 'a', - 'b.c': 'c', - 'd.e.f': 'f', - }; + const input = new Map([ + ['a', 'a'], + ['b.c', 'c'], + ['d.e.f', 'f'], + ]); const expected = { a: 'a', b: { @@ -28,9 +28,7 @@ describe('utils/expand-prefs', () => { it("doesn't pollute the object prototype", () => { const call = 'overriden'; - const input = { - 'hasOwnProperty.call': call, - }; + const input = new Map([['hasOwnProperty.call', call]]); const expected = { hasOwnProperty: { call, @@ -43,10 +41,10 @@ describe('utils/expand-prefs', () => { }); it('throws an error when setting the child property of an already set parent', () => { - const input = { - a: 'a', - 'a.b': 'b', - }; + const input = new Map([ + ['a', 'a'], + ['a.b', 'b'], + ]); expect(() => expandPrefs(input)).to.throw( 'Cannot set a.b because a value already exists at a', @@ -54,10 +52,10 @@ describe('utils/expand-prefs', () => { }); it('allows overriding a parent even if a child has already been set', () => { - const input = { - 'a.b': 'b', - a: 'a', - }; + const input = new Map([ + ['a.b', 'b'], + ['a', 'a'], + ]); const expected = { a: 'a', }; diff --git a/tests/unit/test.program.js b/tests/unit/test.program.js index 7eebe2f2e3..889a5b72a9 100644 --- a/tests/unit/test.program.js +++ b/tests/unit/test.program.js @@ -614,6 +614,27 @@ describe('program.main', () => { }); }); + it('converts chromium custom preferences into a Map', () => { + const fakeCommands = fake(commands, { + run: () => Promise.resolve(), + }); + return execProgram( + [ + 'run', + '--chromium-pref', + 'extensions.ui.developer_mode=false', + '--chromium-pref', + 'browser.theme.color=dark', + ], + { commands: fakeCommands }, + ).then(() => { + const { chromiumPref } = fakeCommands.run.firstCall.args[0]; + assert.instanceOf(chromiumPref, Map); + assert.strictEqual(chromiumPref.get('extensions.ui.developer_mode'), false); + assert.strictEqual(chromiumPref.get('browser.theme.color'), 'dark'); + }); + }); + it('passes shouldExitProgram option to commands', () => { const fakeCommands = fake(commands, { lint: () => Promise.resolve(), From a937f4158d3301a18129b85b4e62e6cd0464b44e Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Mon, 23 Mar 2026 09:21:47 +0100 Subject: [PATCH 03/14] Remove coerceCLICustomChromiumPreference and revert unnecessary changes(Map refactor and so on) --- src/cmd/run.js | 2 +- src/extension-runners/chromium.js | 35 ++++++------ src/program.js | 3 +- src/util/chromium-preferences.js | 30 ----------- src/util/expand-prefs.js | 5 +- tests/unit/test-cmd/test.run.js | 2 +- .../test-extension-runners/test.chromium.js | 16 +++--- .../test-util/test.chromium-preferences.js | 54 ------------------- tests/unit/test-util/test.expand-prefs.js | 30 ++++++----- tests/unit/test.program.js | 8 +-- 10 files changed, 52 insertions(+), 133 deletions(-) delete mode 100644 src/util/chromium-preferences.js delete mode 100644 tests/unit/test-util/test.chromium-preferences.js diff --git a/src/cmd/run.js b/src/cmd/run.js index b619ca724a..56e8f72815 100644 --- a/src/cmd/run.js +++ b/src/cmd/run.js @@ -51,7 +51,7 @@ export default async function run( firefoxApkComponent, // Chromium CLI options. chromiumBinary, - chromiumPref = new Map(), + chromiumPref = {}, chromiumProfile, }, { diff --git a/src/extension-runners/chromium.js b/src/extension-runners/chromium.js index 987f66be19..244491aa0f 100644 --- a/src/extension-runners/chromium.js +++ b/src/extension-runners/chromium.js @@ -29,7 +29,7 @@ export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter( (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag), ); -const DEFAULT_PREFS = new Map([['extensions.ui.developer_mode', true]]); +const DEFAULT_PREFS = { 'extensions.ui.developer_mode': true }; // This is a client for the Chrome Devtools protocol. The methods and results // are documented at https://chromedevtools.github.io/devtools-protocol/tot/ @@ -170,6 +170,19 @@ export class ChromiumExtensionRunner { // Method exported from the IExtensionRunner interface. + /** + * Returns the runner name. + */ + getName() { + return 'Chromium'; + } + + async run() { + // Run should never be called more than once. + this._promiseSetupDone = this.setupInstance(); + await this._promiseSetupDone; + } + static async isUserDataDir(dirPath) { const localStatePath = path.join(dirPath, 'Local State'); const defaultPath = path.join(dirPath, 'Default'); @@ -212,19 +225,6 @@ export class ChromiumExtensionRunner { }; } - /** - * Returns the runner name. - */ - getName() { - return 'Chromium'; - } - - async run() { - // Run should never be called more than once. - this._promiseSetupDone = this.setupInstance(); - await this._promiseSetupDone; - } - /** * Setup the Chromium Profile and run a Chromium instance. */ @@ -607,8 +607,9 @@ export class ChromiumExtensionRunner { * "extensions.ui.developer_mode". */ getPrefs() { - return expandPrefs( - new Map([...DEFAULT_PREFS, ...this.params.customChromiumPrefs]), - ); + return expandPrefs({ + ...DEFAULT_PREFS, + ...this.params.customChromiumPrefs, + }); } } diff --git a/src/program.js b/src/program.js index 4e1322f07c..711bdc9345 100644 --- a/src/program.js +++ b/src/program.js @@ -14,7 +14,6 @@ import { createLogger, } from './util/logger.js'; import { coerceCLICustomPreference } from './firefox/preferences.js'; -import { coerceCLICustomChromiumPreference } from './util/chromium-preferences.js'; import { checkForUpdates as defaultUpdateChecker } from './util/updates.js'; import { applyConfigToArgv as defaultApplyConfigToArgv, @@ -630,7 +629,7 @@ Example: $0 --help run. requiresArg: true, type: 'array', coerce: (arg) => - arg != null ? coerceCLICustomChromiumPreference(arg) : undefined, + arg != null ? coerceCLICustomPreference(arg) : undefined, }, 'chromium-profile': { describe: 'Path to a custom Chromium profile', diff --git a/src/util/chromium-preferences.js b/src/util/chromium-preferences.js deleted file mode 100644 index 80a81373e3..0000000000 --- a/src/util/chromium-preferences.js +++ /dev/null @@ -1,30 +0,0 @@ -import { UsageError } from '../errors.js'; - -export function coerceCLICustomChromiumPreference(cliPrefs) { - const chromiumPrefs = new Map(); - - for (const pref of cliPrefs) { - const prefsAry = pref.split('='); - - if (prefsAry.length < 2) { - throw new UsageError( - `Incomplete custom preference: "${pref}". ` + - 'Syntax expected: "prefname=prefvalue".', - ); - } - - const key = prefsAry[0]; - let value = prefsAry.slice(1).join('='); - - - if (value === `${parseInt(value)}`) { - value = parseInt(value, 10); - } else if (value === 'true' || value === 'false') { - value = value === 'true'; - } - - chromiumPrefs.set(key, value); - } - - return chromiumPrefs; -} diff --git a/src/util/expand-prefs.js b/src/util/expand-prefs.js index b5b2f23fcc..70fe95dd48 100644 --- a/src/util/expand-prefs.js +++ b/src/util/expand-prefs.js @@ -1,12 +1,11 @@ /** - * Given a Map where the keys are the flattened path to a + * Given an object where the keys are the flattened path to a * preference, and the value is the value to set at that path, return * an object where the paths are fully expanded. */ export default function expandPrefs(prefs) { const prefsMap = new Map(); - - for (const [key, value] of prefs) { + for (const [key, value] of Object.entries(prefs)) { let submap = prefsMap; const props = key.split('.'); const lastProp = props.pop(); diff --git a/tests/unit/test-cmd/test.run.js b/tests/unit/test-cmd/test.run.js index b248e5687b..6467adae1a 100644 --- a/tests/unit/test-cmd/test.run.js +++ b/tests/unit/test-cmd/test.run.js @@ -7,8 +7,8 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; import { - FakeExtensionRunner, fixturePath, + FakeExtensionRunner, getFakeFirefox, getFakeRemoteFirefox, mockModule, diff --git a/tests/unit/test-extension-runners/test.chromium.js b/tests/unit/test-extension-runners/test.chromium.js index d31e9a89f4..012cbbb9f5 100644 --- a/tests/unit/test-extension-runners/test.chromium.js +++ b/tests/unit/test-extension-runners/test.chromium.js @@ -2,7 +2,7 @@ import path from 'path'; import EventEmitter from 'events'; import { assert } from 'chai'; -import { beforeEach, describe, it } from 'mocha'; +import { describe, it, beforeEach } from 'mocha'; import deepcopy from 'deepcopy'; import fs from 'fs-extra'; import * as sinon from 'sinon'; @@ -12,7 +12,9 @@ import { ChromiumExtensionRunner, DEFAULT_CHROME_FLAGS, } from '../../../src/extension-runners/chromium.js'; -import { consoleStream } from '../../../src/util/logger.js'; +import { + consoleStream, // instance is imported to inspect logged messages +} from '../../../src/util/logger.js'; import { TempDir, withTempDir } from '../../../src/util/temp-dir.js'; import fileExists from '../../../src/util/file-exists.js'; import isDirectory from '../../../src/util/is-directory.js'; @@ -601,13 +603,13 @@ describe('util/extension-runners/chromium', async () => { }); describe('getPrefs', () => { - it('merges default and custom preferences from a Map', () => { + it('merges default and custom preferences from an object', () => { const { params } = prepareExtensionRunnerParams({ params: { - customChromiumPrefs: new Map([ - ['extensions.ui.developer_mode', false], - ['browser.theme.color', 'dark'], - ]), + customChromiumPrefs: { + 'extensions.ui.developer_mode': false, + 'browser.theme.color': 'dark', + }, }, }); diff --git a/tests/unit/test-util/test.chromium-preferences.js b/tests/unit/test-util/test.chromium-preferences.js deleted file mode 100644 index 1bdce2e724..0000000000 --- a/tests/unit/test-util/test.chromium-preferences.js +++ /dev/null @@ -1,54 +0,0 @@ -import { describe, it } from 'mocha'; -import { assert } from 'chai'; - -import { UsageError } from '../../../src/errors.js'; -import { coerceCLICustomChromiumPreference } from '../../../src/util/chromium-preferences.js'; - -describe('util/chromium-preferences', () => { - describe('coerceCLICustomChromiumPreference', () => { - it('converts cli preferences into a Map', () => { - const prefs = coerceCLICustomChromiumPreference([ - 'extensions.ui.developer_mode=false', - 'browser.theme.color=dark', - ]); - - assert.instanceOf(prefs, Map); - assert.strictEqual(prefs.get('extensions.ui.developer_mode'), false); - assert.strictEqual(prefs.get('browser.theme.color'), 'dark'); - }); - - it('converts integer values', () => { - const prefs = coerceCLICustomChromiumPreference(['some.int.pref=455']); - - assert.strictEqual(prefs.get('some.int.pref'), 455); - }); - - it('supports string values containing equals signs', () => { - const prefs = coerceCLICustomChromiumPreference([ - 'some.string.pref=value=with=equals', - ]); - - assert.strictEqual(prefs.get('some.string.pref'), 'value=with=equals'); - }); - - it('throws on incomplete preferences', () => { - assert.throws( - () => coerceCLICustomChromiumPreference(['invalid.preference']), - UsageError, - 'Incomplete custom preference: "invalid.preference". ' + - 'Syntax expected: "prefname=prefvalue".', - ); - }); - - it('accepts permissive Chromium preference keys', () => { - const prefs = coerceCLICustomChromiumPreference([ - 'net.http.server_properties:https://example.com=true', - ]); - - assert.strictEqual( - prefs.get('net.http.server_properties:https://example.com'), - true, - ); - }); - }); -}); diff --git a/tests/unit/test-util/test.expand-prefs.js b/tests/unit/test-util/test.expand-prefs.js index 1e4a082735..7e74d8da8c 100644 --- a/tests/unit/test-util/test.expand-prefs.js +++ b/tests/unit/test-util/test.expand-prefs.js @@ -5,11 +5,11 @@ import expandPrefs from '../../../src/util/expand-prefs.js'; describe('utils/expand-prefs', () => { it('expands dot-deliminated preferences into a deep object', () => { - const input = new Map([ - ['a', 'a'], - ['b.c', 'c'], - ['d.e.f', 'f'], - ]); + const input = { + a: 'a', + 'b.c': 'c', + 'd.e.f': 'f', + }; const expected = { a: 'a', b: { @@ -28,7 +28,9 @@ describe('utils/expand-prefs', () => { it("doesn't pollute the object prototype", () => { const call = 'overriden'; - const input = new Map([['hasOwnProperty.call', call]]); + const input = { + 'hasOwnProperty.call': call, + }; const expected = { hasOwnProperty: { call, @@ -41,10 +43,10 @@ describe('utils/expand-prefs', () => { }); it('throws an error when setting the child property of an already set parent', () => { - const input = new Map([ - ['a', 'a'], - ['a.b', 'b'], - ]); + const input = { + a: 'a', + 'a.b': 'b', + }; expect(() => expandPrefs(input)).to.throw( 'Cannot set a.b because a value already exists at a', @@ -52,10 +54,10 @@ describe('utils/expand-prefs', () => { }); it('allows overriding a parent even if a child has already been set', () => { - const input = new Map([ - ['a.b', 'b'], - ['a', 'a'], - ]); + const input = { + 'a.b': 'b', + a: 'a', + }; const expected = { a: 'a', }; diff --git a/tests/unit/test.program.js b/tests/unit/test.program.js index 889a5b72a9..e159aec3e8 100644 --- a/tests/unit/test.program.js +++ b/tests/unit/test.program.js @@ -614,7 +614,7 @@ describe('program.main', () => { }); }); - it('converts chromium custom preferences into a Map', () => { + it('converts chromium custom preferences into an object', () => { const fakeCommands = fake(commands, { run: () => Promise.resolve(), }); @@ -629,9 +629,9 @@ describe('program.main', () => { { commands: fakeCommands }, ).then(() => { const { chromiumPref } = fakeCommands.run.firstCall.args[0]; - assert.instanceOf(chromiumPref, Map); - assert.strictEqual(chromiumPref.get('extensions.ui.developer_mode'), false); - assert.strictEqual(chromiumPref.get('browser.theme.color'), 'dark'); + assert.isObject(chromiumPref); + assert.strictEqual(chromiumPref['extensions.ui.developer_mode'], false); + assert.strictEqual(chromiumPref['browser.theme.color'], 'dark'); }); }); From 956a22c12caa844a7d23c7ff4cd717a69537161e Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Mon, 23 Mar 2026 09:23:21 +0100 Subject: [PATCH 04/14] Rename DEFAULT_PREFS to DEFAULT_CHROMIUM_PREFS --- src/extension-runners/chromium.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/extension-runners/chromium.js b/src/extension-runners/chromium.js index 244491aa0f..dbb960fb3b 100644 --- a/src/extension-runners/chromium.js +++ b/src/extension-runners/chromium.js @@ -7,8 +7,8 @@ import fs from 'fs/promises'; import path from 'path'; import { - launch as defaultChromiumLaunch, Launcher as ChromeLauncher, + launch as defaultChromiumLaunch, } from 'chrome-launcher'; import { createLogger } from '../util/logger.js'; @@ -29,7 +29,7 @@ export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter( (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag), ); -const DEFAULT_PREFS = { 'extensions.ui.developer_mode': true }; +const DEFAULT_CHROMIUM_PREFS = { 'extensions.ui.developer_mode': true }; // This is a client for the Chrome Devtools protocol. The methods and results // are documented at https://chromedevtools.github.io/devtools-protocol/tot/ @@ -608,7 +608,7 @@ export class ChromiumExtensionRunner { */ getPrefs() { return expandPrefs({ - ...DEFAULT_PREFS, + ...DEFAULT_CHROMIUM_PREFS, ...this.params.customChromiumPrefs, }); } From 90e743dedd7d133d5e727f5aa4d8ccd140d5b8ce Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Mon, 23 Mar 2026 09:25:51 +0100 Subject: [PATCH 05/14] Use object instead of Map for "provides chromium custom..." test of test.run.js --- tests/unit/test-cmd/test.run.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test-cmd/test.run.js b/tests/unit/test-cmd/test.run.js index 6467adae1a..05595877bc 100644 --- a/tests/unit/test-cmd/test.run.js +++ b/tests/unit/test-cmd/test.run.js @@ -342,7 +342,7 @@ describe('run', () => { }); it('provides chromium custom preferences to the Chromium runner params', async () => { - const fakeChromiumPref = new Map([['extensions.ui.developer_mode', false]]); + const fakeChromiumPref = { 'extensions.ui.developer_mode': false }; const cmd = await prepareRun(); await cmd.run({ target: ['chromium'], @@ -350,7 +350,7 @@ describe('run', () => { }); sinon.assert.calledWithMatch(chromiumRunnerStub, { - customChromiumPrefs: sinon.match.instanceOf(Map), + customChromiumPrefs: sinon.match.object, }); const { customChromiumPrefs } = chromiumRunnerStub.firstCall.args[0]; From a53d06ddb5409d548beb1c1b20acb7151e7e3650 Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Mon, 23 Mar 2026 09:28:00 +0100 Subject: [PATCH 06/14] Rename back DEFAULT_CHROMIUM_PREFS TO DEFAULT_PREFS --- src/extension-runners/chromium.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extension-runners/chromium.js b/src/extension-runners/chromium.js index dbb960fb3b..552e5b422b 100644 --- a/src/extension-runners/chromium.js +++ b/src/extension-runners/chromium.js @@ -29,7 +29,7 @@ export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter( (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag), ); -const DEFAULT_CHROMIUM_PREFS = { 'extensions.ui.developer_mode': true }; +const DEFAULT_PREFS = { 'extensions.ui.developer_mode': true }; // This is a client for the Chrome Devtools protocol. The methods and results // are documented at https://chromedevtools.github.io/devtools-protocol/tot/ @@ -608,7 +608,7 @@ export class ChromiumExtensionRunner { */ getPrefs() { return expandPrefs({ - ...DEFAULT_CHROMIUM_PREFS, + ...DEFAULT_PREFS, ...this.params.customChromiumPrefs, }); } From 1135d21c0739ab33df50e9db5da4afd65bafef62 Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Mon, 23 Mar 2026 09:30:11 +0100 Subject: [PATCH 07/14] chore: Make expand-prefs.js more readable --- src/util/expand-prefs.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/expand-prefs.js b/src/util/expand-prefs.js index 70fe95dd48..58018e4bfe 100644 --- a/src/util/expand-prefs.js +++ b/src/util/expand-prefs.js @@ -5,15 +5,19 @@ */ export default function expandPrefs(prefs) { const prefsMap = new Map(); + for (const [key, value] of Object.entries(prefs)) { let submap = prefsMap; const props = key.split('.'); const lastProp = props.pop(); + for (const prop of props) { if (!submap.has(prop)) { submap.set(prop, new Map()); } + submap = submap.get(prop); + if (!(submap instanceof Map)) { throw new Error( `Cannot set ${key} because a value already exists at ${prop}`, From d261160da7b6b0ef39b388c126d33ef52e5834b8 Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Mon, 23 Mar 2026 09:33:59 +0100 Subject: [PATCH 08/14] revert: Imports order of program.js --- src/program.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/program.js b/src/program.js index 711bdc9345..d7c1414c3e 100644 --- a/src/program.js +++ b/src/program.js @@ -10,15 +10,15 @@ import { Parser as yargsParser } from 'yargs/helpers'; import defaultCommands from './cmd/index.js'; import { UsageError } from './errors.js'; import { - consoleStream as defaultLogStream, createLogger, + consoleStream as defaultLogStream, } from './util/logger.js'; import { coerceCLICustomPreference } from './firefox/preferences.js'; import { checkForUpdates as defaultUpdateChecker } from './util/updates.js'; import { - applyConfigToArgv as defaultApplyConfigToArgv, discoverConfigFiles as defaultConfigDiscovery, loadJSConfigFile as defaultLoadJSConfigFile, + applyConfigToArgv as defaultApplyConfigToArgv, } from './config.js'; const log = createLogger(import.meta.url); From 2cb6ec7595161e9ff9847694e4d0ffe0e09296b7 Mon Sep 17 00:00:00 2001 From: Patryk Kuniczak Date: Thu, 23 Apr 2026 14:41:02 +0200 Subject: [PATCH 09/14] Update src/extension-runners/chromium.js Co-authored-by: Rob Wu --- src/extension-runners/chromium.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extension-runners/chromium.js b/src/extension-runners/chromium.js index 552e5b422b..f04faff69a 100644 --- a/src/extension-runners/chromium.js +++ b/src/extension-runners/chromium.js @@ -334,6 +334,7 @@ export class ChromiumExtensionRunner { logLevel: this.params.verbose ? 'verbose' : 'silent', // Ignore default flags to keep the extension enabled. ignoreDefaultFlags: true, + prefs: this.getPrefs(), }); this.cdp = new ChromeDevtoolsProtocolClient(this.chromiumInstance); From 05c58933a4e667d6f552c7ac67c46f224b879e46 Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Thu, 23 Apr 2026 15:22:32 +0200 Subject: [PATCH 10/14] Add tests for enabling and overriding developer_mode in Chromium prefs --- .../test-extension-runners/test.chromium.js | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/tests/unit/test-extension-runners/test.chromium.js b/tests/unit/test-extension-runners/test.chromium.js index 012cbbb9f5..e19a2e62c1 100644 --- a/tests/unit/test-extension-runners/test.chromium.js +++ b/tests/unit/test-extension-runners/test.chromium.js @@ -70,6 +70,28 @@ function prepareExtensionRunnerParams( } describe('util/extension-runners/chromium', async () => { + describe('developer_mode pref', () => { + it('defaults extensions.ui.developer_mode to true', async () => { + const { params } = prepareExtensionRunnerParams(); + const runnerInstance = new ChromiumExtensionRunner(params); + const prefs = runnerInstance.getPrefs(); + assert.propertyVal(prefs.extensions.ui, 'developer_mode', true); + }); + + it('allows overriding extensions.ui.developer_mode to false', async () => { + const { params } = prepareExtensionRunnerParams({ + params: { + customChromiumPrefs: { + 'extensions.ui.developer_mode': false, + }, + }, + }); + const runnerInstance = new ChromiumExtensionRunner(params); + const prefs = runnerInstance.getPrefs(); + assert.propertyVal(prefs.extensions.ui, 'developer_mode', false); + }); + }); + it('uses the expected chrome flags', () => { // Flags from chrome-launcher v0.14.0 const expectedFlags = [ @@ -120,6 +142,13 @@ describe('util/extension-runners/chromium', async () => { '--disable-blink-features=AutomationControlled', ], startingUrl: undefined, + prefs: { + extensions: { + ui: { + developer_mode: true, + }, + }, + }, }); await runnerInstance.exit(); @@ -603,7 +632,7 @@ describe('util/extension-runners/chromium', async () => { }); describe('getPrefs', () => { - it('merges default and custom preferences from an object', () => { + it('merges default and custom preferences from an object and passes them to the launcher', async () => { const { params } = prepareExtensionRunnerParams({ params: { customChromiumPrefs: { @@ -615,7 +644,7 @@ describe('util/extension-runners/chromium', async () => { const runnerInstance = new ChromiumExtensionRunner(params); - assert.deepEqual(runnerInstance.getPrefs(), { + const expectedPrefs = { extensions: { ui: { developer_mode: false, @@ -626,6 +655,13 @@ describe('util/extension-runners/chromium', async () => { color: 'dark', }, }, + }; + + assert.deepEqual(runnerInstance.getPrefs(), expectedPrefs); + + await runnerInstance.run(); + sinon.assert.calledWithMatch(params.chromiumLaunch, { + prefs: expectedPrefs, }); }); }); From da15bcac870c364908574cf03cd29777c56fe833 Mon Sep 17 00:00:00 2001 From: Patryk Kuniczak Date: Thu, 23 Apr 2026 20:34:36 +0200 Subject: [PATCH 11/14] Update tests/unit/test-extension-runners/test.chromium.js Co-authored-by: Rob Wu --- tests/unit/test-extension-runners/test.chromium.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/unit/test-extension-runners/test.chromium.js b/tests/unit/test-extension-runners/test.chromium.js index e19a2e62c1..723fd2e783 100644 --- a/tests/unit/test-extension-runners/test.chromium.js +++ b/tests/unit/test-extension-runners/test.chromium.js @@ -74,8 +74,15 @@ describe('util/extension-runners/chromium', async () => { it('defaults extensions.ui.developer_mode to true', async () => { const { params } = prepareExtensionRunnerParams(); const runnerInstance = new ChromiumExtensionRunner(params); - const prefs = runnerInstance.getPrefs(); - assert.propertyVal(prefs.extensions.ui, 'developer_mode', true); + await runnerInstance.run(); + sinon.assert.calledWithMatch(params.chromiumLaunch, { + prefs: { + ui: { + developer_mode: true, + }, + }, + }); + await runnerInstance.exit(); }); it('allows overriding extensions.ui.developer_mode to false', async () => { From 649c5e3afed558c28bf55e5d3de408f55c407811 Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Thu, 23 Apr 2026 20:39:23 +0200 Subject: [PATCH 12/14] remove unnecessary test and move `default extensions.ui ...` test into `getPrefs` describe --- .../test-extension-runners/test.chromium.js | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/tests/unit/test-extension-runners/test.chromium.js b/tests/unit/test-extension-runners/test.chromium.js index 723fd2e783..70bc7fb061 100644 --- a/tests/unit/test-extension-runners/test.chromium.js +++ b/tests/unit/test-extension-runners/test.chromium.js @@ -70,35 +70,6 @@ function prepareExtensionRunnerParams( } describe('util/extension-runners/chromium', async () => { - describe('developer_mode pref', () => { - it('defaults extensions.ui.developer_mode to true', async () => { - const { params } = prepareExtensionRunnerParams(); - const runnerInstance = new ChromiumExtensionRunner(params); - await runnerInstance.run(); - sinon.assert.calledWithMatch(params.chromiumLaunch, { - prefs: { - ui: { - developer_mode: true, - }, - }, - }); - await runnerInstance.exit(); - }); - - it('allows overriding extensions.ui.developer_mode to false', async () => { - const { params } = prepareExtensionRunnerParams({ - params: { - customChromiumPrefs: { - 'extensions.ui.developer_mode': false, - }, - }, - }); - const runnerInstance = new ChromiumExtensionRunner(params); - const prefs = runnerInstance.getPrefs(); - assert.propertyVal(prefs.extensions.ui, 'developer_mode', false); - }); - }); - it('uses the expected chrome flags', () => { // Flags from chrome-launcher v0.14.0 const expectedFlags = [ @@ -639,6 +610,20 @@ describe('util/extension-runners/chromium', async () => { }); describe('getPrefs', () => { + it('check if default extensions.ui.developer_mode is true', async () => { + const { params } = prepareExtensionRunnerParams(); + const runnerInstance = new ChromiumExtensionRunner(params); + await runnerInstance.run(); + sinon.assert.calledWithMatch(params.chromiumLaunch, { + prefs: { + ui: { + developer_mode: true, + }, + }, + }); + await runnerInstance.exit(); + }); + it('merges default and custom preferences from an object and passes them to the launcher', async () => { const { params } = prepareExtensionRunnerParams({ params: { From 48151b2ffbba3464337d84c572af8707e713b521 Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Thu, 23 Apr 2026 20:41:15 +0200 Subject: [PATCH 13/14] reorder `check if default extensions.ui ...` test --- .../test-extension-runners/test.chromium.js | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/unit/test-extension-runners/test.chromium.js b/tests/unit/test-extension-runners/test.chromium.js index 70bc7fb061..4a10977474 100644 --- a/tests/unit/test-extension-runners/test.chromium.js +++ b/tests/unit/test-extension-runners/test.chromium.js @@ -102,6 +102,20 @@ describe('util/extension-runners/chromium', async () => { assert.notInclude(DEFAULT_CHROME_FLAGS, '--disable-extensions'); }); + it('check if default extensions.ui.developer_mode is true', async () => { + const { params } = prepareExtensionRunnerParams(); + const runnerInstance = new ChromiumExtensionRunner(params); + await runnerInstance.run(); + sinon.assert.calledWithMatch(params.chromiumLaunch, { + prefs: { + ui: { + developer_mode: true, + }, + }, + }); + await runnerInstance.exit(); + }); + it('installs and runs the extension', async () => { const { params, fakeChromeInstance } = prepareExtensionRunnerParams(); const runnerInstance = new ChromiumExtensionRunner(params); @@ -610,20 +624,6 @@ describe('util/extension-runners/chromium', async () => { }); describe('getPrefs', () => { - it('check if default extensions.ui.developer_mode is true', async () => { - const { params } = prepareExtensionRunnerParams(); - const runnerInstance = new ChromiumExtensionRunner(params); - await runnerInstance.run(); - sinon.assert.calledWithMatch(params.chromiumLaunch, { - prefs: { - ui: { - developer_mode: true, - }, - }, - }); - await runnerInstance.exit(); - }); - it('merges default and custom preferences from an object and passes them to the launcher', async () => { const { params } = prepareExtensionRunnerParams({ params: { From 6ea8fcea58ca73742a549db1ea63d46fda243188 Mon Sep 17 00:00:00 2001 From: PatrykKuniczak Date: Thu, 23 Apr 2026 20:44:45 +0200 Subject: [PATCH 14/14] fix: `check if default extensions.ui ...` test expected params --- tests/unit/test-extension-runners/test.chromium.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/test-extension-runners/test.chromium.js b/tests/unit/test-extension-runners/test.chromium.js index 4a10977474..cfa5b3a81c 100644 --- a/tests/unit/test-extension-runners/test.chromium.js +++ b/tests/unit/test-extension-runners/test.chromium.js @@ -108,8 +108,10 @@ describe('util/extension-runners/chromium', async () => { await runnerInstance.run(); sinon.assert.calledWithMatch(params.chromiumLaunch, { prefs: { - ui: { - developer_mode: true, + extensions: { + ui: { + developer_mode: true, + }, }, }, });