fix: Apply CPU throttling to secondary CDP session (#2092)

This addresses #1955 

CPU throttling needs to be applied to both the primary puppeteer session
and the secondary CDP session from the DevTools universe to have an
effect.

For network throttling this does not seem to be the case, I can see a
slowdown with the current implementation which only applies the network
throttling to the primary CDP session.

I also had to increase the navigation timeout to prevent timeout errors.
This commit is contained in:
Wolfgang Beyer
2026-05-22 09:17:30 +02:00
committed by GitHub
parent ce31594d6c
commit 3ade962a8d
3 changed files with 47 additions and 3 deletions
+4 -1
View File
@@ -9,6 +9,7 @@ import {Mutex} from './Mutex.js';
import {DevTools} from './third_party/index.js';
import type {
Browser,
CDPSession,
ConsoleMessage,
Page,
Protocol,
@@ -49,6 +50,8 @@ export interface TargetUniverse {
/** The DevTools target corresponding to the puppeteer Page */
target: DevTools.Target;
universe: DevTools.Foundation.Universe.Universe;
/** The secondary session created for this page */
session: CDPSession;
}
export type TargetUniverseFactoryFn = (page: Page) => Promise<TargetUniverse>;
@@ -158,7 +161,7 @@ const DEFAULT_FACTORY: TargetUniverseFactoryFn = async (page: Page) => {
undefined,
connection,
);
return {target, universe};
return {target, universe, session};
};
// We don't want to pause any DevTools universe session ever on the MCP side.
+12 -1
View File
@@ -329,11 +329,22 @@ export class McpContext implements Context {
newSettings.networkConditions = options.networkConditions;
}
const secondarySession = this.getDevToolsUniverse(mcpPage)?.session;
if (!options.cpuThrottlingRate) {
await page.emulateCPUThrottling(1);
if (secondarySession) {
await secondarySession.send('Emulation.setCPUThrottlingRate', {
rate: 1,
});
}
delete newSettings.cpuThrottlingRate;
} else {
await page.emulateCPUThrottling(options.cpuThrottlingRate);
if (secondarySession) {
await secondarySession.send('Emulation.setCPUThrottlingRate', {
rate: options.cpuThrottlingRate,
});
}
newSettings.cpuThrottlingRate = options.cpuThrottlingRate;
}
@@ -481,7 +492,7 @@ export class McpContext implements Context {
page.networkConditions,
);
page.pptrPage.setDefaultNavigationTimeout(
NAVIGATION_TIMEOUT * networkMultiplier,
NAVIGATION_TIMEOUT * networkMultiplier * cpuMultiplier,
);
}
+31 -1
View File
@@ -6,7 +6,7 @@
import assert from 'node:assert';
import type {IncomingHttpHeaders} from 'node:http';
import {beforeEach, describe, it} from 'node:test';
import {beforeEach, describe, it, mock} from 'node:test';
import {emulate} from '../../src/tools/emulation.js';
import {
@@ -209,6 +209,36 @@ describe('emulation', () => {
});
});
it('applies cpu throttling to secondary session', async () => {
await withMcpContext(async (response, context) => {
const mcpPage = context.getSelectedMcpPage();
const universe = context.getDevToolsUniverse(mcpPage);
assert.ok(universe);
const sendSpy = mock.method(universe.session, 'send');
await emulate.handler(
{
params: {
cpuThrottlingRate: 4,
},
page: mcpPage,
},
response,
context,
);
assert.ok(sendSpy.mock.calls.length > 0);
const cpuCall = sendSpy.mock.calls.find(
call => call.arguments[0] === 'Emulation.setCPUThrottlingRate',
);
assert.ok(cpuCall);
assert.deepStrictEqual(cpuCall.arguments[1], {rate: 4});
sendSpy.mock.restore();
});
});
it('disables cpu throttling', async () => {
await withMcpContext(async (response, context) => {
await context.emulate({