From 4bb034a87832ca41796530423bfcd548963a5571 Mon Sep 17 00:00:00 2001 From: Vishnu Vardhan Date: Thu, 8 Oct 2026 01:30:28 +0530 Subject: [PATCH] fix(nightwatch): open the dashboard over WebDriver, not the devtools protocol automationProtocol 'devtools' needs the devtools package, so the plugin declared devtools ^8.42.0 as a peer and npm installed it, plus an old Puppeteer, into every project; without it the dashboard window failed to open. chromedriver is already resolved for the test sessions, so the dashboard uses it too. Same change as the WDIO service launcher. --- ...the-nightwatch-dashboard-over-webdriver.md | 5 ++ packages/nightwatch-devtools/package.json | 1 - .../nightwatch-devtools/src/run-lifecycle.ts | 15 ++--- .../tests/runLifecycle.test.ts | 65 +++++++++++++++++++ pnpm-lock.yaml | 3 - 5 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 .changeset/open-the-nightwatch-dashboard-over-webdriver.md create mode 100644 packages/nightwatch-devtools/tests/runLifecycle.test.ts diff --git a/.changeset/open-the-nightwatch-dashboard-over-webdriver.md b/.changeset/open-the-nightwatch-dashboard-over-webdriver.md new file mode 100644 index 00000000..97aa9ee1 --- /dev/null +++ b/.changeset/open-the-nightwatch-dashboard-over-webdriver.md @@ -0,0 +1,5 @@ +--- +'@wdio/nightwatch-devtools': patch +--- + +Open the dashboard window over WebDriver and stop requiring the `devtools` package. The plugin opened it with `automationProtocol: 'devtools'`, which loads the `devtools` package, so `devtools` `^8.42.0` was a peer and npm installed it and an old Puppeteer into every project. Without it the dashboard window did not open (`Couldn't find automation protocol "devtools"`). The window now opens through chromedriver, still without the "controlled by automated test software" bar, and `devtools` is no longer a peer. diff --git a/packages/nightwatch-devtools/package.json b/packages/nightwatch-devtools/package.json index 720cdc58..5940737b 100644 --- a/packages/nightwatch-devtools/package.json +++ b/packages/nightwatch-devtools/package.json @@ -71,7 +71,6 @@ "typescript": "^6.0.3" }, "peerDependencies": { - "devtools": "^8.42.0", "nightwatch": ">=3.0.0" } } diff --git a/packages/nightwatch-devtools/src/run-lifecycle.ts b/packages/nightwatch-devtools/src/run-lifecycle.ts index 8badb144..f1383674 100644 --- a/packages/nightwatch-devtools/src/run-lifecycle.ts +++ b/packages/nightwatch-devtools/src/run-lifecycle.ts @@ -135,25 +135,18 @@ export async function openDevtoolsBrowser( } ctx.devtoolsBrowser = await remote({ logLevel: 'info', - automationProtocol: 'devtools', capabilities: { browserName: 'chrome', 'goog:chromeOptions': { + excludeSwitches: ['enable-automation'], args: [ '--window-size=1600,1200', `--user-data-dir=${ctx.userDataDir}`, '--no-first-run', '--no-default-browser-check' ] - }, - // Dashboard uses the Puppeteer-based 'devtools' protocol; drop the - // "controlled by automated test software" infobar by ignoring - // Puppeteer's --enable-automation default. (Runtime-valid capability - // not present in the type.) - 'wdio:devtoolsOptions': { - ignoreDefaultArgs: ['--enable-automation'] } - } as WebdriverIO.Capabilities + } }) await ctx.devtoolsBrowser.url(url) } catch (err) { @@ -201,7 +194,7 @@ export async function waitForDevtoolsBrowserClose( return } ;(logger as { setLevel: (ns: string, lvl: string) => void }).setLevel( - 'devtools', + 'webdriver', 'warn' ) let exitBySignal = false @@ -229,7 +222,7 @@ export async function waitForDevtoolsBrowserClose( process.removeListener('SIGINT', signalHandler) process.removeListener('SIGTERM', signalHandler) ;(logger as { setLevel: (ns: string, lvl: string) => void }).setLevel( - 'devtools', + 'webdriver', 'info' ) try { diff --git a/packages/nightwatch-devtools/tests/runLifecycle.test.ts b/packages/nightwatch-devtools/tests/runLifecycle.test.ts new file mode 100644 index 00000000..684974e9 --- /dev/null +++ b/packages/nightwatch-devtools/tests/runLifecycle.test.ts @@ -0,0 +1,65 @@ +import * as fs from 'node:fs' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { remote } from 'webdriverio' + +import { + openDevtoolsBrowser, + type RunLifecycleCtx +} from '../src/run-lifecycle.js' + +vi.mock('webdriverio', () => ({ remote: vi.fn() })) +vi.mock('@wdio/devtools-backend', () => ({ start: vi.fn(), stop: vi.fn() })) + +function makeCtx(): RunLifecycleCtx { + // openDevtoolsBrowser reads only these fields; the managers and reporter are irrelevant here. + return { + options: { hostname: 'localhost', port: 3000 }, + devtoolsBrowser: undefined, + userDataDir: undefined + } as unknown as RunLifecycleCtx +} + +describe('openDevtoolsBrowser', () => { + const browser = { url: vi.fn().mockResolvedValue(undefined) } + let ctx: RunLifecycleCtx + + beforeEach(() => { + vi.mocked(remote).mockResolvedValue(browser as never) + ctx = makeCtx() + }) + + afterEach(() => { + if (ctx.userDataDir) { + fs.rmSync(ctx.userDataDir, { recursive: true, force: true }) + } + vi.clearAllMocks() + }) + + it('opens the dashboard over WebDriver, which needs no `devtools` package', async () => { + await openDevtoolsBrowser(ctx, 'http://localhost:3000') + + const [params] = vi.mocked(remote).mock.calls[0] + expect(params).not.toHaveProperty('automationProtocol') + expect(params.capabilities).not.toHaveProperty('wdio:devtoolsOptions') + expect(params.capabilities).toEqual( + expect.objectContaining({ + browserName: 'chrome', + 'goog:chromeOptions': expect.objectContaining({ + excludeSwitches: ['enable-automation'], + args: expect.arrayContaining([`--user-data-dir=${ctx.userDataDir}`]) + }) + }) + ) + expect(browser.url).toHaveBeenCalledWith('http://localhost:3000') + expect(ctx.devtoolsBrowser).toBe(browser) + }) + + it('leaves the run going when the window cannot be opened', async () => { + vi.mocked(remote).mockRejectedValue(new Error('no chromedriver')) + + await expect( + openDevtoolsBrowser(ctx, 'http://localhost:3000') + ).resolves.toBeUndefined() + expect(ctx.devtoolsBrowser).toBeUndefined() + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e98995ee..9d546994 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -404,9 +404,6 @@ importers: '@xmldom/xmldom': specifier: ^0.9.12 version: 0.9.12 - devtools: - specifier: ^8.42.0 - version: 8.42.0 fluent-ffmpeg: specifier: ^2.1.3 version: 2.1.3