Skip to content

Commit

Permalink
test for context execution identifier in Debugger.scriptParsed event (#…
Browse files Browse the repository at this point in the history
…10562)

* test for context execution identifier in Debugger.scriptParsed event

* CR feedback
  • Loading branch information
aeulitz committed Sep 14, 2022
1 parent b97559d commit b272b34
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 12 deletions.
102 changes: 96 additions & 6 deletions packages/debug-test/CDPDebugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,27 @@ export async function getDebugTargets(
* Names of events that can get raised by CDPDebugger instances.
*/
export type EventName =
| 'paused' // Event indicating that debugger backend is paused.
| 'resumed'; // Event indicating that debugger backend has resumed script execution.
// Event indicating that debugger backend is paused.
//
// The backend raises this event in response to the Debugger.pause command.
// See https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#event-paused
| 'Debugger.paused'

// Event indicating that debugger backend has resumed script execution.
//
// The backend raises this event in response to the Debugger.resume command.
// See https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#event-resumed
| 'Debugger.resumed'

// Event indicating that debugger backend has parsed a script.
// See https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#event-scriptParsed
| 'Debugger.scriptParsed'

// Event indicating that debugger backend has created an execution context.
//
// The backend raises this event in response to the Runtime.enable command.
// See https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-executionContextCreated
| 'Runtime.executionContextCreated';

/**
* Signature of handlers for events raised by CDPDebugger instances.
Expand Down Expand Up @@ -166,6 +185,7 @@ export class CDPDebugger {
*
* Sends a Debugger.enable CDP message (see https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#method-enable).
* @param maxScriptsCacheSize Maximum size in bytes of collected scripts the debugger can hold.
* @returns {Promise<void>} Promise indicating that the debugger backend has received the command.
*/
public async debuggerEnable(
maxScriptsCacheSize: number = 10000000,
Expand Down Expand Up @@ -199,6 +219,20 @@ export class CDPDebugger {
]);
});

this.expectedResponses.push([
`Debugger.scriptParsed response for ${commandDescription}`,
response => {
if (
response.hasOwnProperty('method') &&
response.method === 'Debugger.scriptParsed'
) {
this.raise('Debugger.scriptParsed', () => response.params);
return true;
}
return false;
},
]);

await this.wsOpened;
testLog.message(`sending ${commandDescription}`);
this.ws.send(command);
Expand Down Expand Up @@ -253,7 +287,7 @@ export class CDPDebugger {
*
* Sends a Debugger.pause CDP message (see https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#method-pause).
* @returns {Promise<void>} Promise indicating that the debugger backend has received the command.
* @fires CDPDebugger#paused The 'paused' event indicates that the debugger backend has reached the 'paused' state.
* @fires Debugger.paused event indicating that the debugger backend has reached the 'paused' state.
*/
public async debuggerPause(): Promise<void> {
const commandId = this.nextCommandId++;
Expand Down Expand Up @@ -290,7 +324,7 @@ export class CDPDebugger {
response.hasOwnProperty('method') &&
response.method === 'Debugger.paused'
) {
this.raise('paused', () => response.params);
this.raise('Debugger.paused', () => response.params);
return true;
}
return false;
Expand All @@ -309,7 +343,7 @@ export class CDPDebugger {
*
* Sends a Debugger.resume CDP message (see https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#method-resume)
* @returns {Promise<void>} Promise indicating that the debugger backend has received the command.
* @fires CDPDebugger#resumed The 'paused' event indicates that the debugger backend has reached the 'paused' state.
* @fires Debugger.resumed event indicating that the debugger backend has resumed execution.
*/
public async debuggerResume(): Promise<void> {
const commandId = this.nextCommandId++;
Expand Down Expand Up @@ -348,7 +382,7 @@ export class CDPDebugger {
response.hasOwnProperty('method') &&
response.method === 'Debugger.resumed'
) {
this.raise('resumed', () => {});
this.raise('Debugger.resumed', () => {});
return true;
}
return false;
Expand Down Expand Up @@ -512,6 +546,62 @@ export class CDPDebugger {
return resultPromise;
}

/**
* Enables reporting of execution context creation via executionContextCreated events.
*
* Sends a Runtime.enable CDP message (see https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-enable).
* @returns {Promise<void>} Promise indicating that the debugger backend has received the command.
* @fires Runtime.executionContextCreated event indicating that an execution context has been created.
*/
public async runtimeEnable(): Promise<void> {
const commandId = this.nextCommandId++;

// the actual CDP message
const command = JSON.stringify({
id: commandId,
method: 'Runtime.enable',
});

// a short description for logging
const commandDescription = `Runtime.enable (id: ${commandId})`;

const resultPromise = new Promise<void>((resolve, _reject) => {
const expectedResponse = {id: commandId, result: {}};
this.expectedResponses.push([
`result response for ${commandDescription}`,
response => {
// relying on object comparison to be independent of key order differences
if (lodash.isEqual(response, expectedResponse)) {
resolve();
return true;
}
return false;
},
]);
});

this.expectedResponses.push([
`Runtime.executionContextCreated response for ${commandDescription}`,
response => {
if (
response.hasOwnProperty('method') &&
response.method === 'Runtime.executionContextCreated'
) {
this.raise('Runtime.executionContextCreated', () => response.params);
return true;
}
return false;
},
]);

await this.wsOpened;
testLog.message(`sending ${commandDescription}`);
this.ws.send(command);
this.lastCommand = commandDescription;

return resultPromise;
}

/**
* Checks whether all expected responses to previous commands have been retrieved.
*
Expand Down
59 changes: 53 additions & 6 deletions packages/debug-test/DebuggingFeatures.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ test('pause, resume', async () => {

await dbg.debuggerEnable();

const pausedEvent = dbg.expectEvent('paused');
const pausedEvent = dbg.expectEvent('Debugger.paused');
await dbg.debuggerPause();
const eventArgs = await pausedEvent;

Expand Down Expand Up @@ -183,7 +183,7 @@ test('pause, resume', async () => {
expect(eventArgs.callFrames.length).toBeGreaterThanOrEqual(1);
expect(eventArgs.callFrames[0]).toHaveProperty('functionName');

const resumedEvent = dbg.expectEvent('resumed');
const resumedEvent = dbg.expectEvent('Debugger.resumed');
await dbg.debuggerResume();
await resumedEvent;

Expand Down Expand Up @@ -212,7 +212,7 @@ test('set, remove breakpoint', async () => {

await dbg.debuggerEnable();

const pausedEvent = dbg.expectEvent('paused');
const pausedEvent = dbg.expectEvent('Debugger.paused');
await dbg.debuggerPause();
await pausedEvent;

Expand All @@ -228,7 +228,7 @@ test('set, remove breakpoint', async () => {

await dbg.debuggerRemoveBreakpoint(breakpointId);

const resumedEvent = dbg.expectEvent('resumed');
const resumedEvent = dbg.expectEvent('Debugger.resumed');
await dbg.debuggerResume();
await resumedEvent;

Expand Down Expand Up @@ -259,11 +259,11 @@ test('reload after continue', async () => {

await dbg.debuggerEnable();

const pausedEvent = dbg.expectEvent('paused');
const pausedEvent = dbg.expectEvent('Debugger.paused');
await dbg.debuggerPause();
await pausedEvent;

const resumedEvent = dbg.expectEvent('resumed');
const resumedEvent = dbg.expectEvent('Debugger.resumed');
await dbg.debuggerResume();
await resumedEvent;

Expand All @@ -279,3 +279,50 @@ test('reload after continue', async () => {
await settings.restore();
}
});

// Regression test for the fix for RN:34639 (https://github.com/facebook/react-native/issues/34639).
//
// This test method needs to remain disabled until RNW import the hermes-windows version containing
// https://github.com/microsoft/hermes-windows/commit/016aab4e0c76180b3f06f8efdcd2c07b44809cc5 (hermes-windows patch) or
// https://github.com/facebook/react-native/commit/545366aea30c3db6cb28c77ce85208e9973cc1fb (upstream in RN Core).
test.skip('execution context identifier in Debugger.scriptParsed event', async () => {
testLog.message(`executing 'pause, resume' test on PID ${pid}`);

const settings = await PlaygroundDebugSettings.set({
webDebugger: false,
directDebugging: true,
jsEngine: 'Hermes',
});
try {
const isBundleServed = metro.isBundleServed('debugTest01');
await loadPackage('Samples\\debugTest01', isBundleServed);

const debugTargets = await getDebugTargets();
const dbg = new CDPDebugger(debugTargets[0].webSocketDebuggerUrl);

const executionContextCreatedEvent = dbg.expectEvent(
'Runtime.executionContextCreated',
);
await dbg.runtimeEnable();

const scriptParsedEvent = dbg.expectEvent('Debugger.scriptParsed');
await dbg.debuggerEnable();

const executionContextCreatedEventArgs = await executionContextCreatedEvent;
const scriptParsedEventArgs = await scriptParsedEvent;

expect(executionContextCreatedEventArgs).toHaveProperty('context');
expect(executionContextCreatedEventArgs.context).toHaveProperty('id');
expect(scriptParsedEventArgs).toHaveProperty('executionContextId');

expect(scriptParsedEventArgs.executionContextId).toEqual(
executionContextCreatedEventArgs.context.id,
);

await dbg.checkOutstandingResponses(3000);

dbg.close();
} finally {
await settings.restore();
}
});

0 comments on commit b272b34

Please sign in to comment.