mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/42299 Changelog: [Internal] TSIA Reviewed By: hoxyq Differential Revision: D52798108 fbshipit-source-id: 9ba980b9fb439b1aeee3eb1b08535b95556d72bb
123 lines
3.0 KiB
JavaScript
123 lines
3.0 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow strict-local
|
|
* @format
|
|
* @oncall react_native
|
|
*/
|
|
|
|
import type {JSONSerializable} from '../inspector-proxy/types';
|
|
import type {
|
|
CdpMessageToTarget,
|
|
CdpResponseFromTarget,
|
|
} from './InspectorProtocolUtils';
|
|
|
|
import nullthrows from 'nullthrows';
|
|
import until from 'wait-for-expect';
|
|
import WebSocket from 'ws';
|
|
|
|
export class DebuggerAgent {
|
|
#ws: ?WebSocket;
|
|
#readyPromise: Promise<void>;
|
|
|
|
constructor(url: string, signal?: AbortSignal) {
|
|
const ws = new WebSocket(url, {
|
|
// The mock server uses a self-signed certificate.
|
|
rejectUnauthorized: false,
|
|
});
|
|
this.#ws = ws;
|
|
ws.on('message', data => {
|
|
this.__handle(JSON.parse(data.toString()));
|
|
});
|
|
if (signal != null) {
|
|
signal.addEventListener('abort', () => {
|
|
this.close();
|
|
});
|
|
}
|
|
this.#readyPromise = new Promise<void>((resolve, reject) => {
|
|
ws.once('open', () => {
|
|
resolve();
|
|
});
|
|
ws.once('error', error => {
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
__handle(message: JSONSerializable): void {}
|
|
|
|
send(message: JSONSerializable) {
|
|
if (!this.#ws) {
|
|
return;
|
|
}
|
|
this.#ws.send(JSON.stringify(message));
|
|
}
|
|
|
|
ready(): Promise<void> {
|
|
return this.#readyPromise;
|
|
}
|
|
|
|
close() {
|
|
if (!this.#ws) {
|
|
return;
|
|
}
|
|
try {
|
|
this.#ws.terminate();
|
|
} catch {}
|
|
this.#ws = null;
|
|
}
|
|
|
|
// $FlowIgnore[unsafe-getters-setters]
|
|
get socket(): WebSocket {
|
|
return nullthrows(this.#ws);
|
|
}
|
|
}
|
|
|
|
export class DebuggerMock extends DebuggerAgent {
|
|
// Empty handlers
|
|
+handle: JestMockFn<[message: JSONSerializable], void> = jest.fn();
|
|
|
|
__handle(message: JSONSerializable): void {
|
|
this.handle(message);
|
|
}
|
|
|
|
async sendAndGetResponse(
|
|
message: CdpMessageToTarget,
|
|
): Promise<CdpResponseFromTarget> {
|
|
const originalHandleCallsArray = this.handle.mock.calls;
|
|
const originalHandleCallCount = originalHandleCallsArray.length;
|
|
this.send(message);
|
|
await until(() =>
|
|
expect(this.handle).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
id: message.id,
|
|
}),
|
|
),
|
|
);
|
|
// Find the first matching handle call that wasn't already in the mock calls
|
|
// array before we sent the message.
|
|
const newHandleCalls =
|
|
originalHandleCallsArray === this.handle.mock.calls
|
|
? this.handle.mock.calls.slice(originalHandleCallCount)
|
|
: this.handle.mock.calls;
|
|
// $FlowIgnore[incompatible-use]
|
|
// $FlowIgnore[prop-missing]
|
|
const [response] = newHandleCalls.find(args => args[0].id === message.id);
|
|
// $FlowIgnore[incompatible-return]
|
|
// $FlowIgnore[incompatible-indexer]
|
|
return response;
|
|
}
|
|
}
|
|
|
|
export async function createDebuggerMock(
|
|
url: string,
|
|
signal: AbortSignal,
|
|
): Promise<DebuggerMock> {
|
|
const debuggerMock = new DebuggerMock(url, signal);
|
|
await debuggerMock.ready();
|
|
return debuggerMock;
|
|
}
|