From 6d6b1a384bb0f29a6c62a8382b36560da4226f4e Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Wed, 30 Apr 2025 08:41:19 -0700 Subject: [PATCH] chore: fix merge config (#311) --- src/config.ts | 27 ++++++++++++++++-------- src/program.ts | 1 + tests/fixtures.ts | 10 ++++----- tests/headed.spec.ts | 49 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 tests/headed.spec.ts diff --git a/src/config.ts b/src/config.ts index 4ad8697..0d4ad7a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -89,7 +89,7 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise return path.join(result, fileName); } +function pickDefined(obj: T | undefined): Partial { + return Object.fromEntries( + Object.entries(obj ?? {}).filter(([_, v]) => v !== undefined) + ) as Partial; +} + function mergeConfig(base: Config, overrides: Config): Config { const browser: Config['browser'] = { - ...base.browser, - ...overrides.browser, + ...pickDefined(base.browser), + ...pickDefined(overrides.browser), launchOptions: { - ...base.browser?.launchOptions, - ...overrides.browser?.launchOptions, + ...pickDefined(base.browser?.launchOptions), + ...pickDefined(overrides.browser?.launchOptions), ...{ assistantMode: true }, }, contextOptions: { - ...base.browser?.contextOptions, - ...overrides.browser?.contextOptions, + ...pickDefined(base.browser?.contextOptions), + ...pickDefined(overrides.browser?.contextOptions), }, }; + if (browser.browserName !== 'chromium') + delete browser.launchOptions.channel; + return { - ...base, - ...overrides, + ...pickDefined(base), + ...pickDefined(overrides), browser, }; } diff --git a/src/program.ts b/src/program.ts index 6a09ced..c97fcfe 100644 --- a/src/program.ts +++ b/src/program.ts @@ -41,6 +41,7 @@ program .option('--config ', 'Path to the configuration file.') .action(async options => { const config = await resolveConfig(options); + console.error(config); const serverList = new ServerList(() => createServer(config)); setupExitWatchdog(serverList); diff --git a/tests/fixtures.ts b/tests/fixtures.ts index 4027b2c..adfda76 100644 --- a/tests/fixtures.ts +++ b/tests/fixtures.ts @@ -34,11 +34,11 @@ type TestFixtures = { cdpEndpoint: string; server: TestServer; httpsServer: TestServer; + mcpHeadless: boolean; + mcpBrowser: string | undefined; }; type WorkerFixtures = { - mcpHeadless: boolean; - mcpBrowser: string | undefined; _workerServers: { server: TestServer, httpsServer: TestServer }; }; @@ -112,11 +112,11 @@ export const test = baseTest.extend({ browserProcess.kill(); }, - mcpHeadless: [async ({ headless }, use) => { + mcpHeadless: async ({ headless }, use) => { await use(headless); - }, { scope: 'worker' }], + }, - mcpBrowser: ['chrome', { option: true, scope: 'worker' }], + mcpBrowser: ['chrome', { option: true }], _workerServers: [async ({}, use, workerInfo) => { const port = 8907 + workerInfo.workerIndex * 4; diff --git a/tests/headed.spec.ts b/tests/headed.spec.ts new file mode 100644 index 0000000..04954c1 --- /dev/null +++ b/tests/headed.spec.ts @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * 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 { test, expect } from './fixtures'; + +for (const mcpHeadless of [false, true]) { + test.describe(`mcpHeadless: ${mcpHeadless}`, () => { + test.use({ mcpHeadless }); + test.skip(process.platform === 'linux', 'Auto-detection wont let this test run on linux'); + test('browser', async ({ client, server, mcpBrowser }) => { + test.skip(!['chrome', 'msedge', 'chromium'].includes(mcpBrowser ?? ''), 'Only chrome is supported for this test'); + server.route('/', (req, res) => { + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(` + + + `); + }); + + const response = await client.callTool({ + name: 'browser_navigate', + arguments: { + url: server.PREFIX, + }, + }); + + expect(response).toContainTextContent(`Mozilla/5.0`); + if (mcpHeadless) + expect(response).toContainTextContent(`HeadlessChrome`); + else + expect(response).not.toContainTextContent(`HeadlessChrome`); + }); + }); +}