chrometools-mcp 3.3.6 → 3.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,59 @@
7
7
  import { getBrowser } from './browser-manager.js';
8
8
  // Note: injectRecorder removed - now using Chrome Extension for recording
9
9
 
10
+ /**
11
+ * Click listener tracking script - injected via evaluateOnNewDocument
12
+ * Monkey-patches addEventListener to track which elements have click listeners
13
+ * This enables detection of click handlers added by frameworks like Angular
14
+ */
15
+ const CLICK_LISTENER_TRACKER_SCRIPT = `
16
+ (function() {
17
+ // Only inject once
18
+ if (window.__clickListenerTracker) return;
19
+ window.__clickListenerTracker = true;
20
+
21
+ // WeakMap to track elements with click listeners (prevents memory leaks)
22
+ const clickListeners = new WeakMap();
23
+
24
+ // Store original methods
25
+ const originalAddEventListener = EventTarget.prototype.addEventListener;
26
+ const originalRemoveEventListener = EventTarget.prototype.removeEventListener;
27
+
28
+ // Patch addEventListener
29
+ EventTarget.prototype.addEventListener = function(type, listener, options) {
30
+ if (type === 'click' && this instanceof Element) {
31
+ // Track this element has click listener
32
+ const count = clickListeners.get(this) || 0;
33
+ clickListeners.set(this, count + 1);
34
+ }
35
+ return originalAddEventListener.call(this, type, listener, options);
36
+ };
37
+
38
+ // Patch removeEventListener for accuracy
39
+ EventTarget.prototype.removeEventListener = function(type, listener, options) {
40
+ if (type === 'click' && this instanceof Element) {
41
+ const count = clickListeners.get(this) || 0;
42
+ if (count > 0) {
43
+ clickListeners.set(this, count - 1);
44
+ }
45
+ }
46
+ return originalRemoveEventListener.call(this, type, listener, options);
47
+ };
48
+
49
+ // Global function to check if element has click listener
50
+ window.__hasClickListener = function(element) {
51
+ if (!element) return false;
52
+ const count = clickListeners.get(element);
53
+ return count && count > 0;
54
+ };
55
+
56
+ // Also expose for debugging
57
+ window.__getClickListenerCount = function(element) {
58
+ return clickListeners.get(element) || 0;
59
+ };
60
+ })();
61
+ `;
62
+
10
63
  /**
11
64
  * Debug log helper (only logs to stderr when DEBUG=1)
12
65
  * @param {...any} args - Arguments to log
@@ -159,6 +212,20 @@ export async function setupNetworkMonitoring(page) {
159
212
 
160
213
  // Note: setupRecorderAutoReinjection removed - Chrome Extension handles recording now
161
214
 
215
+ /**
216
+ * Inject click listener tracker into page
217
+ * Must be called BEFORE page.goto() to catch all listeners
218
+ * @param {Page} page - Puppeteer page instance
219
+ */
220
+ async function injectClickListenerTracker(page) {
221
+ try {
222
+ await page.evaluateOnNewDocument(CLICK_LISTENER_TRACKER_SCRIPT);
223
+ debugLog('Click listener tracker injected');
224
+ } catch (error) {
225
+ debugLog('Failed to inject click listener tracker:', error.message);
226
+ }
227
+ }
228
+
162
229
  /**
163
230
  * Get or create page for URL
164
231
  * @param {string} url - URL to navigate to
@@ -180,6 +247,9 @@ export async function getOrCreatePage(url) {
180
247
  // Create new page
181
248
  const page = await browser.newPage();
182
249
 
250
+ // Inject click listener tracker BEFORE navigation
251
+ await injectClickListenerTracker(page);
252
+
183
253
  // Set up console log capture
184
254
  const client = await page.target().createCDPSession();
185
255
  await client.send('Runtime.enable');
@@ -277,6 +347,19 @@ export function setLastPage(page) {
277
347
  * @returns {Promise<void>}
278
348
  */
279
349
  export async function setupNewPage(page, source = 'manual') {
350
+ // Inject click listener tracker
351
+ // For new tabs, we need both:
352
+ // 1. evaluateOnNewDocument for future navigations
353
+ // 2. evaluate for already-loaded content (won't catch existing listeners, but will catch new ones)
354
+ try {
355
+ await page.evaluateOnNewDocument(CLICK_LISTENER_TRACKER_SCRIPT);
356
+ // Also inject immediately for current page (in case content already loaded)
357
+ await page.evaluate(CLICK_LISTENER_TRACKER_SCRIPT);
358
+ debugLog(`Click listener tracker injected for ${source} page`);
359
+ } catch (error) {
360
+ debugLog('Failed to inject click listener tracker:', error.message);
361
+ }
362
+
280
363
  // Set up console log capture
281
364
  try {
282
365
  const client = await page.target().createCDPSession();