diff --git a/src/firefox/core.ts b/src/firefox/core.ts index ceb9d30..d65201a 100644 --- a/src/firefox/core.ts +++ b/src/firefox/core.ts @@ -349,18 +349,11 @@ export class FirefoxCore { } } - let serviceBuilder; - if (process.platform === 'win32') { - // On windows, firefox.ServiceBuilder() invoked from the MCP will hang. - // geckodriver has to be in the PATH. See Bug 2040849. - const geckodriverPath = await findGeckodriver(); - logDebug(`Using geckodriver: ${geckodriverPath}`); - serviceBuilder = new firefox.ServiceBuilder(geckodriverPath); - } else { - // On other platforms, the default ServiceBuilder should locate and - // start geckodriver successfully. - serviceBuilder = new firefox.ServiceBuilder(); - } + // Always resolve geckodriver ourselves rather than relying on selenium + // entirely. See Bug 2062055, 2040849. + const geckodriverPath = await findGeckodriver(); + logDebug(`Using geckodriver: ${geckodriverPath}`); + const serviceBuilder = new firefox.ServiceBuilder(geckodriverPath); if (this.logFilePath) { // Open file for appending, create if doesn't exist diff --git a/tests/firefox/core.test.ts b/tests/firefox/core.test.ts index e9311a5..f00e437 100644 --- a/tests/firefox/core.test.ts +++ b/tests/firefox/core.test.ts @@ -317,6 +317,7 @@ describe('FirefoxCore connect() profile handling', () => { const mockWindowSize = vi.fn(); const mockSetAcceptInsecureCerts = vi.fn(); const mockSetStdio = vi.fn(); + const mockServiceBuilderCtor = vi.fn(); beforeEach(() => { vi.clearAllMocks(); @@ -333,7 +334,11 @@ describe('FirefoxCore connect() profile handling', () => { setAcceptInsecureCerts = mockSetAcceptInsecureCerts; }, ServiceBuilder: class { + constructor(...args: unknown[]) { + mockServiceBuilderCtor(...args); + } setStdio = mockSetStdio; + addArguments = vi.fn(); }, }, })); @@ -383,4 +388,18 @@ describe('FirefoxCore connect() profile handling', () => { join('/path/to/test/profile', MCP_PROFILE_DIR_NAME) ); }); + + // Bug 2062055: geckodriver path should always be resolved before calling + // the ServiceBuilder. + it('should build the geckodriver service with an explicit binary path', async () => { + const { FirefoxCore } = await import('@/firefox/core.js'); + + const core = new FirefoxCore({ headless: true }); + await core.connect(); + + expect(mockServiceBuilderCtor).toHaveBeenCalledTimes(1); + const [geckodriverPath] = mockServiceBuilderCtor.mock.calls[0] as [unknown]; + expect(typeof geckodriverPath).toBe('string'); + expect(String(geckodriverPath)).toContain('geckodriver'); + }); });