diff --git a/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts b/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts index e18fa14be1..a67c7092a7 100644 --- a/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts +++ b/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts @@ -50,7 +50,7 @@ export class UserInteractionPlugin extends BasePlugin { private _zonePatched = false; // for addEventListener/removeEventListener state private _wrappedListeners = new WeakMap< - Function, + Function | EventListenerObject, Map> >(); // for event bubbling @@ -178,7 +178,7 @@ export class UserInteractionPlugin extends BasePlugin { private addPatchedListener( on: HTMLElement, type: string, - listener: Function, + listener: Function | EventListenerObject, wrappedListener: Function ): boolean { let listener2Type = this._wrappedListeners.get(listener); @@ -204,7 +204,7 @@ export class UserInteractionPlugin extends BasePlugin { private removePatchedListener( on: HTMLElement, type: string, - listener: Function + listener: Function | EventListenerObject ): Function | undefined { const listener2Type = this._wrappedListeners.get(listener); if (!listener2Type) { @@ -227,6 +227,19 @@ export class UserInteractionPlugin extends BasePlugin { return patched; } + // utility method to deal with the Function|EventListener nature of addEventListener + private _invokeListener( + listener: Function | EventListenerObject, + target: any, + args: any[] + ): any { + if (typeof listener === 'function') { + return listener.apply(target, args); + } else { + return listener.handleEvent(args[0]); + } + } + /** * This patches the addEventListener of HTMLElement to be able to * auto instrument the click events @@ -258,13 +271,13 @@ export class UserInteractionPlugin extends BasePlugin { plugin._eventsSpanMap.set(event, span); } return plugin._tracer.withSpan(span, () => { - const result = listener.apply(target, args); + const result = plugin._invokeListener(listener, target, args); // no zone so end span immediately span.end(); return result; }); } else { - return listener.apply(target, args); + return plugin._invokeListener(listener, target, args); } }; if (plugin.addPatchedListener(this, type, listener, patchedListener)) { diff --git a/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.nozone.test.ts b/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.nozone.test.ts index b4a1d4acb2..3b19aee9d7 100644 --- a/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.nozone.test.ts +++ b/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.nozone.test.ts @@ -161,6 +161,24 @@ describe('UserInteractionPlugin', () => { assert.strictEqual(callCount, 3); }); + it('should handle EventListener callbacks', () => { + let callCount = 0; + const listener = { + handleEvent(evt: Event) { + if (evt) { + callCount++; + } + }, + }; + document.body.addEventListener('EventListenerEvent', listener); + document.body.dispatchEvent(new Event('EventListenerEvent')); + assert.strictEqual(callCount, 1); + callCount = 0; + document.body.removeEventListener('EventListenerEvent', listener); + document.body.dispatchEvent(new Event('EventListenerEvent')); + assert.strictEqual(callCount, 0); + }); + it('should handle task without async operation', () => { fakeInteraction(); assert.equal(exportSpy.args.length, 1, 'should export one span');