fix contexts missing on second runs
This commit is contained in:
@@ -30,6 +30,11 @@ interface AttachedTab {
|
|||||||
targetId: string;
|
targetId: string;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
targetInfo: Protocol.Target.TargetInfo;
|
targetInfo: Protocol.Target.TargetInfo;
|
||||||
|
// Cache execution contexts for this tab. When Playwright reconnects and calls Runtime.enable,
|
||||||
|
// Chrome's debugger does NOT re-send Runtime.executionContextCreated events for contexts that
|
||||||
|
// already exist. We must manually replay them so Playwright knows what contexts are available.
|
||||||
|
// Without this, page.evaluate() hangs because Playwright has no valid execution context IDs.
|
||||||
|
executionContexts: Map<number, Protocol.Runtime.ExecutionContextCreatedEvent>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RelayConnection {
|
export class RelayConnection {
|
||||||
@@ -91,7 +96,8 @@ export class RelayConnection {
|
|||||||
debuggee,
|
debuggee,
|
||||||
targetId: targetInfo.targetId,
|
targetId: targetInfo.targetId,
|
||||||
sessionId,
|
sessionId,
|
||||||
targetInfo
|
targetInfo,
|
||||||
|
executionContexts: new Map()
|
||||||
});
|
});
|
||||||
|
|
||||||
debugLog('Sending Target.attachedToTarget event, WebSocket state:', this._ws.readyState);
|
debugLog('Sending Target.attachedToTarget event, WebSocket state:', this._ws.readyState);
|
||||||
@@ -169,6 +175,22 @@ export class RelayConnection {
|
|||||||
const tab = this._attachedTabs.get(source.tabId!);
|
const tab = this._attachedTabs.get(source.tabId!);
|
||||||
if (!tab) return;
|
if (!tab) return;
|
||||||
|
|
||||||
|
// Track execution contexts so we can replay them when Playwright reconnects.
|
||||||
|
// Chrome's debugger only sends Runtime.executionContextCreated events once per context,
|
||||||
|
// not on every Runtime.enable call. We cache them here and replay on reconnection.
|
||||||
|
if (method === 'Runtime.executionContextCreated') {
|
||||||
|
const contextEvent = params as Protocol.Runtime.ExecutionContextCreatedEvent;
|
||||||
|
tab.executionContexts.set(contextEvent.context.id, contextEvent);
|
||||||
|
debugLog('Cached execution context:', contextEvent.context.id, 'for tab:', source.tabId, 'total contexts:', tab.executionContexts.size);
|
||||||
|
} else if (method === 'Runtime.executionContextDestroyed') {
|
||||||
|
const destroyedEvent = params as Protocol.Runtime.ExecutionContextDestroyedEvent;
|
||||||
|
tab.executionContexts.delete(destroyedEvent.executionContextId);
|
||||||
|
debugLog('Removed execution context:', destroyedEvent.executionContextId, 'from tab:', source.tabId, 'remaining:', tab.executionContexts.size);
|
||||||
|
} else if (method === 'Runtime.executionContextsCleared') {
|
||||||
|
tab.executionContexts.clear();
|
||||||
|
debugLog('Cleared all execution contexts for tab:', source.tabId);
|
||||||
|
}
|
||||||
|
|
||||||
debugLog('Forwarding CDP event:', method, 'from tab:', source.tabId);
|
debugLog('Forwarding CDP event:', method, 'from tab:', source.tabId);
|
||||||
|
|
||||||
this._sendMessage({
|
this._sendMessage({
|
||||||
@@ -267,11 +289,33 @@ export class RelayConnection {
|
|||||||
sessionId: sessionId !== targetTab.sessionId ? sessionId : undefined,
|
sessionId: sessionId !== targetTab.sessionId ? sessionId : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
return await chrome.debugger.sendCommand(
|
const result = await chrome.debugger.sendCommand(
|
||||||
debuggerSession,
|
debuggerSession,
|
||||||
method,
|
method,
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// When Playwright reconnects and calls Runtime.enable, Chrome does NOT automatically
|
||||||
|
// re-send Runtime.executionContextCreated events for contexts that already exist.
|
||||||
|
// This causes page.evaluate() to hang because Playwright has no execution context IDs.
|
||||||
|
// Solution: manually replay all cached contexts so Playwright gets fresh, valid IDs.
|
||||||
|
if (method === 'Runtime.enable' && targetTab.executionContexts.size > 0) {
|
||||||
|
debugLog('Runtime.enable called, replaying', targetTab.executionContexts.size, 'cached execution contexts for tab:', targetTab.debuggee.tabId);
|
||||||
|
|
||||||
|
for (const contextEvent of targetTab.executionContexts.values()) {
|
||||||
|
debugLog('Replaying execution context:', contextEvent.context.id);
|
||||||
|
this._sendMessage({
|
||||||
|
method: 'forwardCDPEvent',
|
||||||
|
params: {
|
||||||
|
sessionId: sessionId,
|
||||||
|
method: 'Runtime.executionContextCreated',
|
||||||
|
params: contextEvent,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user