Skip to content

test: add sinon mock utils and emulate tool unit tests - #2641

Merged
OrKoN merged 28 commits into
ChromeDevTools:mainfrom
maheshsingh20:test/mock-utils-emulation-unit-tests
Sep 4, 2026
Merged

OrKoN merged 28 commits into
ChromeDevTools:mainfrom
maheshsingh20:test/mock-utils-emulation-unit-tests

Conversation

@maheshsingh20

@maheshsingh20 maheshsingh20 commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

test: mock-based unit tests for emulation, no real browser needed

Relates to #2639.

Summary
Adds tests/mocks.ts — sinon createStubInstance-based factories for McpPage, McpContext, McpResponse, and Puppeteer's Page (via the concrete CdpPage subclass)
createHandlerMocks() helper returns {page, context, response} together for handler tests
Converts the network and cpu describe blocks in emulation.test.ts from real-browser (withMcpContext) to the sinon mocks
Converts emulate() behavior tests in McpPage.test.ts to use a real McpPage instance wrapping a mocked Puppeteer page (createMockPuppeteerPage()), instead of a real browser
No new test files — all changes are in-place edits to existing test files, per review feedback
Remaining emulate()-related tests that need real browser behavior (predefined-condition validation, secondary DevTools session) are intentionally left as real-browser tests
Verification
npm run format
npm run test

Proof-of-concept for issue ChromeDevTools#2639 (optimize tests).

Adds two files:

tests/testMocks.ts
  Sinon-based factory helpers for the three objects that every tool-handler
  test depends on: createMockMcpPage, createMockMcpContext, and
  createMockMcpResponse. The McpPage stub's emulate() mirrors the real
  McpPage.emulate() clear/set semantics without touching a real browser.

tests/tools/emulation.unit.test.ts
  27 unit tests for the emulate tool handler covering all emulation axes:
  networkConditions, cpuThrottlingRate, geolocation, userAgent, colorScheme,
  viewport, and extraHttpHeaders (set and clear paths). No real browser is
  required; the suite completes in ~100 ms vs several seconds for the
  existing real-browser suite.
@google-cla

google-cla Bot commented Sep 2, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

maheshsingh20 and others added 2 commits September 2, 2026 21:47
…s, snapshot tools

Extends the proof-of-concept from the first commit to cover four more
tool handlers — all without a real browser.

tests/testMocks.ts
  Extended createMockMcpResponse with stubs for all response methods used
  by tool handlers: setIncludeConsoleData, attachConsoleMessage,
  setIncludeNetworkRequests, attachNetworkRequest, setIncludePages,
  setListThirdPartyDeveloperTools, setListWebMcpTools, includeSnapshot,
  attachDevToolsData.
  Extended createMockMcpContext with getPageById, selectPage, closePage,
  newPage stubs.

tests/tools/console.unit.test.ts   (8 tests)
  listConsoleMessages: verifies setIncludeConsoleData is called with
  correct value and all option fields (pageSize, pageIdx, types,
  includeStackTraces, serviceWorkerId, includePreservedMessages).
  getConsoleMessage: verifies attachConsoleMessage is called with the
  correct msgid.

tests/tools/network.unit.test.ts   (6 tests)
  listNetworkRequests: verifies setIncludeNetworkRequests and all option
  fields (pageSize, pageIdx, resourceTypes, includePreservedRequests).
  getNetworkRequest: verifies attachNetworkRequest with reqid,
  requestFilePath, responseFilePath.

tests/tools/pages.unit.test.ts     (8 tests)
  listPages: verifies setIncludePages, setListThirdPartyDeveloperTools,
  setListWebMcpTools.
  selectPage: verifies getPageById lookup, selectPage call, setIncludePages.
  closePage: verifies closePage call, setIncludePages, and CLOSE_PAGE_ERROR
  handling.

tests/tools/snapshot.unit.test.ts  (5 tests)
  takeSnapshot: verifies includeSnapshot is called with verbose default,
  verbose override, filePath pass-through.
@maheshsingh20

Copy link
Copy Markdown
Contributor Author

Updated this PR with a second commit that extends the proof-of-concept to cover four more tool handlers.

Now includes:

  • Extended testMocks.ts with stubs for all response/context methods used by tool handlers
  • console.unit.test.ts — 8 tests (listConsoleMessages all options, getConsoleMessage)
  • network.unit.test.ts — 6 tests (listNetworkRequests all options, getNetworkRequest with file paths)
  • pages.unit.test.ts — 8 tests (listPages, selectPage, closePage including CLOSE_PAGE_ERROR path)
  • snapshot.unit.test.ts — 5 tests (takeSnapshot verbose/filePath)

67/67 tests pass, no browser required, ~200ms total.

Formatter tests were audited and are already clean — no real McpContext used anywhere in them.

Let me know if you'd like any adjustments to the pattern before I continue with item (3).

maheshsingh20 and others added 2 commits September 3, 2026 00:30
…files

Per @OrKoN feedback on ChromeDevTools#2641: remove separate *.unit.test.ts files and
instead migrate tests directly inside the existing test files.

tests/testMocks.ts
  Fully implements ContextPage, Context and Response interfaces via sinon
  stubs so mock objects satisfy the handler signatures without any casts.

tests/tools/emulation.test.ts
  Converted the 'network' and 'cpu' describe blocks from withMcpContext
  to createMockMcpPage/createMockMcpContext/createMockMcpResponse.
  The 'Slow 11G' predefined-options test is kept as a real-browser test
  since it exercises McpPage internal validation logic.
Comment thread tests/testMocks.ts Outdated
Comment thread tests/testMocks.ts Outdated
Addresses two review comments from @OrKoN on ChromeDevTools#2641:

1. Use sinon.createStubInstance(McpPage/McpContext/McpResponse) instead
   of hand-rolled mock interfaces. The stubs are derived directly from
   the real class prototypes so no shadow type definitions are needed.

2. Remove the mock implementation of emulate(). Tool handler tests now
   assert that page.emulate() was called with the correct arguments
   rather than simulating emulate()'s internal clear/set logic.
   The actual emulate() behaviour (clear/set semantics, predefined
   conditions validation) is covered by new tests in McpPage.test.ts
   which run against the real McpPage class.

tests/testMocks.ts
  Reduced to three one-liner factory functions using createStubInstance.

tests/tools/emulation.test.ts
  network/cpu mock tests now assert on page.emulate.firstCall.args[0]
  instead of page.networkConditions / page.cpuThrottlingRate.

tests/McpPage.test.ts
  New McpPage.emulate() describe block with 9 real-browser tests covering
  networkConditions (set/clear/unknown), cpuThrottlingRate (set/reset),
  userAgent (set/clear), colorScheme (set/reset via auto).
Comment thread tests/McpPage.test.ts Outdated
Per @OrKoN review: drop withMcpContext from McpPage.emulate() tests.
Instead, construct a real McpPage wrapping a fake Puppeteer page built
on top of the existing getMockPage() helper from utils.ts, extended with
the specific Puppeteer methods that emulate() calls internally:
emulateNetworkConditions, emulateCPUThrottling, setGeolocation,
setUserAgent, emulateMediaFeatures, setViewport, setExtraHTTPHeaders,
setDefaultTimeout, setDefaultNavigationTimeout.

This exercises the real emulate() code path without starting a browser.
Comment thread tests/mocks.ts
Comment thread tests/McpPage.test.ts Outdated
Per @OrKoN review:
- Rename tests/testMocks.ts to tests/mocks.ts (already in tests folder)
- Move getMockPage() from tests/utils.ts into tests/mocks.ts
- tests/utils.ts re-exports getMockPage from mocks.ts for backwards compat
- Update emulation.test.ts and McpPage.test.ts imports accordingly
@maheshsingh20

Copy link
Copy Markdown
Contributor Author

Hi @OrKoN
Done in the latest commit:

Renamed testMocks.ts → mocks.ts
Moved getMockPage() from utils.ts into mocks.ts — utils.ts re-exports it so existing callers aren't broken
createFakePuppeteerPage() in McpPage.test.ts now builds on top of getMockPage() from mocks.ts

Regarding createStubInstance for getMockPage() — Page is an abstract class in Puppeteer, so createStubInstance can't be used directly on it. Kept the existing satisfies Page pattern but moved it into mocks.ts as requested. Happy to explore a different approach if you have one in mind.

Comment thread tests/McpPage.test.ts Outdated
Comment thread tests/McpPage.test.ts Outdated
Comment thread tests/mocks.ts Outdated
Comment thread tests/mocks.ts Outdated
… comments

Addresses three review comments from @OrKoN:

Thread 1 — McpPage.test.ts emulate() tests now assert on the underlying
Puppeteer method calls (emulateNetworkConditions, emulateCPUThrottling,
setUserAgent, emulateMediaFeatures) via sinon.assert.calledWith, not just
on McpPage's internal emulationSettings state.

Thread 2 — Removed redundant section divider comments from mocks.ts.

Thread 3 — Added a JSDoc note to getMockPage() explaining why
createStubInstance cannot be used: Puppeteer's Page is declared as
'abstract class', which sinon.createStubInstance() cannot stub.
Comment thread tests/tools/emulation.test.ts Outdated
Comment thread tests/McpPage.test.ts Outdated
- Add createHandlerMocks() to mocks.ts returning {page, context, response}
  so tests don't repeat the same three setup lines
- Use createHandlerMocks() across all network/cpu tests in emulation.test.ts
- Rename createFakePuppeteerPage -> createMockPuppeteerPage and
  fakePage -> pptrPage in McpPage.test.ts per @OrKoN review
Comment thread tests/McpPage.test.ts Outdated
maheshsingh20 and others added 2 commits September 3, 2026 16:53
…nstance

Per @OrKoN: getMockPage should be a generic stub not tuned for emulation.

- mocks.ts: rename getMockPage -> createMockPuppeteerPage, replace the
  hand-rolled object literal with sinon.createStubInstance(Page) using
  puppeteer-core's abstract Page class
- utils.ts: update import and re-export to createMockPuppeteerPage
- McpPage.test.ts: remove the local createMockPuppeteerPage wrapper,
  import the generic stub from mocks.ts, and configure the emulation-
  specific methods (emulateNetworkConditions, emulateCPUThrottling, etc.)
  inline in createMcpPage() via Object.assign since those methods live on
  CdpPage (concrete subclass) rather than the abstract Page class
Comment thread tests/McpPage.test.ts Outdated
Comment thread tests/mocks.ts Outdated
@maheshsingh20

Copy link
Copy Markdown
Contributor Author

hi @OrKoN
Re-verified everything locally against 82f3a80 before moving on:

Clean rebuild: 0 build errors
Full test suite: 1,204 passing; the only 11 failures are pre-existing Windows-environment issues (daemon PID timing, symlink permissions requiring admin rights, THIRD_PARTY_NOTICES needing npm run bundle, a pre-existing Puppeteer stack-trace snapshot mismatch) — one additional failure (blocks URLs not in allowlist) was a transient retry flake, confirmed passing 7/7 on rerun
McpPage.test.ts + emulation.test.ts: 67/67 passing
PageCollector.test.ts (PageCollector/NetworkCollector/ConsoleCollector): 18/18 passing
npm run check-format: clean
npm run docs:generate: no diff, docs in sync

This is ready for another look whenever you get a chance.

Comment thread tests/McpPage.test.ts Outdated
maheshsingh20 pushed a commit to maheshsingh20/chrome-devtools-mcp that referenced this pull request Sep 4, 2026
@OrKoN
OrKoN enabled auto-merge September 4, 2026 15:01
@OrKoN

OrKoN commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

in #2660 I updated agents.md to capture the learnings from this PR's review. As the next step, we could migrate tests/tools/emulation.test.ts off the withMcpContext helper while ensuring appropriate test coverage on the McpPage / McpContext level.

auto-merge was automatically disabled September 4, 2026 15:25

Head branch was pushed to by a user without write access

@maheshsingh20
maheshsingh20 force-pushed the test/mock-utils-emulation-unit-tests branch from 775ad21 to da16207 Compare September 4, 2026 15:25
@OrKoN

OrKoN commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

@maheshsingh20 please do not rebase or merge the main branch into this branch unnecessarily.

@OrKoN
OrKoN enabled auto-merge September 4, 2026 15:29
@maheshsingh20

Copy link
Copy Markdown
Contributor Author

Hi @OrKoN,
CI Failures: The current failing CI jobs (macos-latest node 26, windows-latest node 22/26, and the required summary check) are pre-existing runner latency timeouts in real-browser tests (pages.test.js and network.test.js hitting Navigation timeout of 10000ms / 20000ms exceeded). On the prior run, Windows node 24 failed on a timeout while node 22/26 passed; on this rerun without code changes, node 24 passed while 22/26 timed out.
All unit tests touched by this PR, as well as lint, format, and doc checks, are 100% green. Could you trigger a re-run on those flaky jobs or take another look? Thanks!

@OrKoN
OrKoN added this pull request to the merge queue Sep 4, 2026
Merged via the queue into ChromeDevTools:main with commit 086299a Sep 4, 2026
26 of 30 checks passed
@maheshsingh20

Copy link
Copy Markdown
Contributor Author

Thanks for merging, @OrKoN! I saw the updates in #2660 and AGENTS.md — that's super helpful.

Should I go ahead and open a new PR to migrate the remaining withMcpContext tests in tests/tools/emulation.test.ts to unit tests and add the corresponding coverage in McpPage / McpContext? Or is there another area/issue you'd prefer to tackle next?

@OrKoN

OrKoN commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Yeah let's finish emulation.test.ts and then go over other tool tests on by one.

@maheshsingh20
maheshsingh20 deleted the test/mock-utils-emulation-unit-tests branch September 4, 2026 17:39
pull Bot pushed a commit to Pet3cy/chrome-devtools-mcp that referenced this pull request Sep 7, 2026
…eDevTools#2665)

Relates to ChromeDevTools#2639.

Follow-up to ChromeDevTools#2641 and feedback in ChromeDevTools#2660 (`AGENTS.md`).

### Summary of Changes

1. **`tests/tools/emulation.test.ts`**:
- Completely migrated off `withMcpContext`, removing all real-browser
launches, `serverHooks`, and HTTP fixtures.
- All tool handler test suites (`geolocation`, `viewport`, `userAgent`,
`extraHttpHeaders`, `colorScheme`, `network`, `cpu`) now use
`createHandlerMocks()` from `tests/mocks.ts` and verify `page.emulate()`
is invoked with exact expected arguments.

2. **`tests/McpPage.test.ts`**:
- Added unit test coverage for `McpPage.emulate()` using
`createMockPuppeteerPage()`:
     - Offline network throttling settings and network blocking guard.
     - Secondary DevTools session CPU throttling delegation.
     - Geolocation set/clear behavior.
     - Viewport set/clear with default parameter merging.
     - Extra HTTP headers set/clear behavior.

### Verification
- `npm run check-format`: Passed (clean ESLint + Prettier)
- `npm run build`: Compiled with exit code 0
- `node scripts/test.js tests/tools/emulation.test.ts`: 50/50 tests
passed
- `node scripts/test.js tests/McpPage.test.ts`: 32/32 tests passed
pull Bot pushed a commit to Mu-L/chrome-devtools-mcp that referenced this pull request Sep 8, 2026
…meDevTools#2683)

This PR migrates `tests/tools/screencast.test.ts` from real-browser
tests (`withMcpContext`) to mock-based unit tests using the established
Sinon mock infrastructure.

### Summary
- References ChromeDevTools#2639 (item 1)
- Follow-up building on ChromeDevTools#2641 and ChromeDevTools#2665
- Rewrites `tests/tools/screencast.test.ts` to use
`createHandlerMocks()` instead of `withMcpContext()`, eliminating real
browser launches.
- Adds `createMockScreenRecorder()` helper and wires
`getScreenRecorder`/`setScreenRecorder` and `ensureExtension` in
`tests/mocks.ts`.
- Re-exports `ScreenRecorder` from `src/third_party/index.ts` to comply
with internal import boundaries.
pull Bot pushed a commit to oogalieboogalie/chrome-devtools-mcp that referenced this pull request Sep 9, 2026
… tests to McpPage (ChromeDevTools#2698)

This PR migrates tests in `tests/tools/snapshot.test.ts` to mock-based
unit tests using the established Sinon mock infrastructure and relocates
the real-browser integration tests to `tests/McpPage.test.ts`.

### Summary
- References ChromeDevTools#2639 (item 1).
- Follow-up building on ChromeDevTools#2641, ChromeDevTools#2665, and ChromeDevTools#2683.
- Relocated the 6 real-browser `waitFor` integration tests to a
dedicated `waitForTextOnPage()` suite in `tests/McpPage.test.ts` to
directly cover the `mcpPage.waitForTextOnPage` method.
- Converted all tool handler tests in `tests/tools/snapshot.test.ts`
(`take_snapshot` and `wait_for`) to mock unit tests using
`createHandlerMocks()`, completely removing `withMcpContext` from the
file.
- Asserted exact method calls on `response` and `page` using
`sinon.assert.calledOnceWithExactly()`.
- Maintained `afterEach(() => sinon.restore())` cleanup per `AGENTS.md`.

### Verification
- `npm run test tests/tools/snapshot.test.ts` (4 passed, 0 failed, exit
code: 0)
- `npm run test tests/McpPage.test.ts` (39 passed, 0 failed, exit code:
0)
- `npm run check-format` (exit code: 0)
- `npm run docs:generate` (exit code: 0)
- `git status` (clean working tree, exit code: 0)
pull Bot pushed a commit to Pet3cy/chrome-devtools-mcp that referenced this pull request Sep 11, 2026
This PR migrates the mock-eligible test in
`tests/tools/extensions.test.ts` from a real-browser test
(`withMcpContext`) to a mock-based unit test using the established Sinon
mock infrastructure.

### Architectural Principle (Category 1 vs. Category 2 Split)
This PR continues issue ChromeDevTools#2639 (item 1), applying the core architectural
separation of concerns established across ChromeDevTools#2641, ChromeDevTools#2665, ChromeDevTools#2683, and
ChromeDevTools#2698:

- **Category 1 (Handler wiring & response verification -> Mock unit
tests)**:
Tests that only verify tool parameter parsing and response manipulation
should not launch real browsers. Launching Chrome just to assert that a
tool invoked `response.setListExtensions()` introduces unnecessary
startup latency and lifecycle flakiness without providing real
integration coverage. These are converted to deterministic unit tests
using `createHandlerMocks()`.

- **Category 2 (Genuine browser, extension, and protocol behavior ->
Retained real-browser tests)**:
Tests that depend on genuine browser mechanics must remain in
`withMcpContext`. Mocking them would require simulating Chrome's
internal extension loader, V8 script execution, or Puppeteer's target
lifecycle inside mocks, creating brittle and artificial tests that do
not validate real behavior.

### Summary of Changes
- **Converted to mocks (Category 1)**:
- `lists installed extensions`: Converted to `createHandlerMocks()`.
Asserts `response.setListExtensions` was invoked with
`sinon.assert.calledOnceWithExactly(response.setListExtensions)`.
- **Intentionally retained as real-browser tests (Category 2)**:
- `installs and uninstalls an extension and verifies it in
chrome://extensions`: Genuinely installs an unpacked extension into
Chrome and verifies real extension lifecycle and management.
- `reloads an extension`: Verifies Chrome's live extension reload
mechanics and registry reappearance.
- `triggers an extension action`: Validates asynchronous Puppeteer
`Target` creation when an extension action fires.
- `verifies that content script console logs are received`: Tests real
content script execution in a live navigated page and CDP console
capture.

### Verification
- `powershell -Command "Remove-Item -Recurse -Force build -ErrorAction
SilentlyContinue"; npm run build` (exit code: 0)
- `node scripts/test.js tests/tools/extensions.test.ts` (6 passed, 0
failed, exit code: 0)
- `npm run check-format` (exit code: 0)
- `npm run docs:generate` (exit code: 0)
- `git status` (clean working tree, exit code: 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants