From 3edaf8e2db455bcaeb6e027dea55413edf557938 Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Fri, 27 Sep 2024 11:14:41 -0400 Subject: [PATCH] feat: support spawnOpts for geckodriver child process (#552) * feat: support spawnOpts for geckodriver child process * add documentation on new spawnOpts parameter * correctly reflect spawnOptions argument * update readme docs with correct spawnOpts type --- README.md | 9 +++++++++ src/index.ts | 4 ++-- src/types.ts | 10 ++++++++++ tests/start-unit.test.ts | 41 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/start-unit.test.ts diff --git a/README.md b/README.md index 86348752..95e3ef02 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,15 @@ The path to the root of the cache directory. Type: `string`
Default: `process.env.GECKODRIVER_CACHE_DIR || os.tmpdir()` +### `spawnOpts` +Options to pass into the geckodriver process. This can be useful if needing +Firefox to spawn with `MOZ_` prefix variables, such as `MOZ_HEADLESS_WIDTH`. +See https://nodejs.org/api/child_process.html#child_processspawncommand-args-options for +all options. + +Type: `SpawnOptionsWithoutStdio | SpawnOptionsWithStdioTuple`
+Default: `undefined` + # Other Browser Driver If you also look for other browser driver NPM wrappers, you can find them here: diff --git a/src/index.ts b/src/index.ts index 05d2f347..17e2eace 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,7 @@ import type { GeckodriverParameters } from './types.js' const log = logger('geckodriver') export async function start (params: GeckodriverParameters) { - const { cacheDir, customGeckoDriverPath, ...startArgs } = params + const { cacheDir, customGeckoDriverPath, spawnOpts, ...startArgs } = params let geckoDriverPath = ( customGeckoDriverPath || process.env.GECKODRIVER_PATH || @@ -42,7 +42,7 @@ export async function start (params: GeckodriverParameters) { const args = parseParams(startArgs) log.info(`Starting Geckodriver at ${geckoDriverPath} with params: ${args.join(' ')}`) - return cp.spawn(geckoDriverPath, args) + return cp.spawn(geckoDriverPath, args, spawnOpts) } export const download = downloadDriver diff --git a/src/types.ts b/src/types.ts index 15557e95..10fa7733 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,8 @@ +import type { SpawnOptionsWithoutStdio, SpawnOptionsWithStdioTuple, StdioPipe, StdioNull } from 'node:child_process' + export type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'config' | 'debug' | 'trace' +type StdioOption = StdioNull | StdioPipe export interface GeckodriverParameters { /** * List of hostnames to allow. By default the value of --host is allowed, and in addition if that's a well @@ -77,6 +80,13 @@ export interface GeckodriverParameters { * @default process.env.GECKODRIVER_CACHE_DIR || os.tmpdir() */ cacheDir?: string + + /** + * options to be passed into the process. + * @see options in https://nodejs.org/api/child_process.html#child_processspawncommand-args-options + * @default undefined + */ + spawnOpts?: SpawnOptionsWithoutStdio | SpawnOptionsWithStdioTuple } declare global { diff --git a/tests/start-unit.test.ts b/tests/start-unit.test.ts new file mode 100644 index 00000000..18bd860b --- /dev/null +++ b/tests/start-unit.test.ts @@ -0,0 +1,41 @@ + +import cp from 'node:child_process' +import { vi, test, expect } from 'vitest' +import { type GeckodriverParameters, start } from '../src/index.ts' + +test('start', async () => { + vi.mock('../src/install.js', () => { + return { + download: vi.fn().mockResolvedValue('foo') + } + }) + + vi.mock('../src/utils.js', async (original) => { + const actual: any = await original() + return { + hasAccess: vi.fn().mockResolvedValue(true), + parseParams: actual.parseParams + } + }) + + vi.mock('node:child_process', () => ({ + default: { + spawn: vi.fn(), + } + })) + + const args: GeckodriverParameters = { + spawnOpts: { + env: { + MOZ_HEADLESS_WIDTH: '720' + } + } + } + + await start(args) + expect(cp.spawn).toHaveBeenCalledWith('foo', ['--host=0.0.0.0', '--websocket-port=0'], { + env: { + MOZ_HEADLESS_WIDTH: '720' + } + }) +}) \ No newline at end of file