blob: d8f1849b7bf3cb696ab8710726b9b0e3823933c2 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as ProtocolClient from '../core/protocol_client/protocol_client.js';
export type CommandHandler<C extends ProtocolClient.CDPConnection.Command> =
(params: ProtocolClient.CDPConnection.CommandParams<C>, sessionId: string|undefined) =>
Promise<{result: ProtocolClient.CDPConnection.CommandResult<C>}|{error: ProtocolClient.CDPConnection.CDPError}>|
{result: ProtocolClient.CDPConnection.CommandResult<C>}|{error: ProtocolClient.CDPConnection.CDPError};
export type CommandAndHandler<C extends ProtocolClient.CDPConnection.Command> = [C, CommandHandler<C>];
/**
* This class fulfills a similar role as `describeWithMockConnection` with the main difference
* being that it doesn't operate global.
*
* The right usage is to create a `MockCDPConnection` instance with your handlers, and then pass
* it along to {@link createTarget}.
*
* This means a `MockCDPConnection` only affects the targets explicitly created with it and doesn't
* leak anywhere else.
*/
export class MockCDPConnection implements ProtocolClient.CDPConnection.CDPConnection {
readonly #observers = new Set<ProtocolClient.CDPConnection.CDPConnectionObserver>();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
readonly #handlers: Map<ProtocolClient.CDPConnection.Command, CommandHandler<any>>;
constructor(handlers: Array<CommandAndHandler<ProtocolClient.CDPConnection.Command>> = []) {
this.#handlers = new Map(handlers);
}
/**
* Sets the provided handler or clears an existing handler when passing `null`.
*
* Throws if a set would overwrite an existing handler.
*/
setHandler<T extends ProtocolClient.CDPConnection.Command>(method: T, handler: CommandHandler<T>|null): void {
if (handler && this.#handlers.has(method)) {
throw new Error(`MockCDPConnection already has a handler for ${method}`);
}
if (handler) {
this.#handlers.set(method, handler);
} else {
this.#handlers.delete(method);
}
}
send<T extends ProtocolClient.CDPConnection.Command>(
method: T, params: ProtocolClient.CDPConnection.CommandParams<T>,
sessionId: string|undefined): Promise<{result: ProtocolClient.CDPConnection.CommandResult<T>}|{
error: ProtocolClient.CDPConnection.CDPError,
}> {
const handler = this.#handlers.get(method);
if (!handler) {
return Promise.resolve({
error: {
message: `Method ${method} is not stubbed in MockCDPConnection`,
code: ProtocolClient.CDPConnection.CDPErrorStatus.DEVTOOLS_STUB_ERROR,
}
});
}
return Promise.resolve(handler(params, sessionId));
}
dispatchEvent<T extends ProtocolClient.CDPConnection.Event>(
event: T, params: ProtocolClient.CDPConnection.EventParams<T>, sessionId: string|undefined): void {
this.#observers.forEach(observer => observer.onEvent({
sessionId,
method: event,
params,
}));
}
observe(observer: ProtocolClient.CDPConnection.CDPConnectionObserver): void {
this.#observers.add(observer);
}
unobserve(observer: ProtocolClient.CDPConnection.CDPConnectionObserver): void {
this.#observers.delete(observer);
}
}