Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(user-interaction): EventTarget is undefined in IE #627

Merged
merged 13 commits into from Oct 12, 2021

Conversation

t2t2
Copy link
Contributor

@t2t2 t2t2 commented Aug 18, 2021

Which problem is this PR solving?

#537 changed the patched interface from HTMLElement to EventTarget. Problem is EventTarget doesn't exist in Internet Explorer (11)

image

Instead addEventListener & removeEventListener are provided on interface closest to where EventTarget would be on prototype chain:

image

(for comparison same code in chrome confirming EventTarget on modern browsers)

image

Short description of the changes

Added check if browser has EventTarget, using a list of alternative targets if not.

There is a small difference between IE and modern browsers as EventTarget is used by more interfaces, this difference could be removed by using a list of targets as zone.js uses but I'm not seeing any of those being a target of user interactions so don't think it's worth it for now.

@t2t2 t2t2 requested a review from a team as a code owner August 18, 2021 14:49
@dyladan dyladan added the bug Something isn't working label Aug 18, 2021
@codecov
Copy link

codecov bot commented Aug 18, 2021

Codecov Report

Merging #627 (9350016) into main (25c0e30) will increase coverage by 0.93%.
The diff coverage is n/a.

❗ Current head 9350016 differs from pull request most recent head ec471f5. Consider uploading reports for the commit ec471f5 to get more accurate results

@@            Coverage Diff             @@
##             main     #627      +/-   ##
==========================================
+ Coverage   96.82%   97.75%   +0.93%     
==========================================
  Files           9        7       -2     
  Lines         630      357     -273     
  Branches      124       56      -68     
==========================================
- Hits          610      349     -261     
+ Misses         20        8      -12     
Impacted Files Coverage Δ
...umentation-user-interaction/src/instrumentation.ts
...ation-user-interaction/src/enums/AttributeNames.ts

Copy link
Member

@obecny obecny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is really nice finding, one question and I'm just missing some unit tests

@t2t2
Copy link
Contributor Author

t2t2 commented Aug 23, 2021

Don't think this can be tested with just adding an unit test but rather this requires a full cross-browser testing setup (as it's dependent on the browser / running environment). In fact the current tests, only ran in IE, would catch this issue as they fail due to non-existant EventTarget

@dyladan
Copy link
Member

dyladan commented Aug 24, 2021

@obecny was working on multi-browser testing but i'm not sure what the current state is on that

@dyladan
Copy link
Member

dyladan commented Aug 25, 2021

I'd like to wait for @obecny approval since he wrote this plugin

Copy link
Member

@obecny obecny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think this can be tested with just adding an unit test but rather this requires a full cross-browser testing setup (as it's dependent on the browser / running environment). In fact the current tests, only ran in IE, would catch this issue as they fail due to non-existant EventTarget

you can simply do a unit tests with mocking window object so that you can simulate this and then make sure it was called.

this._unwrap(EventTarget.prototype, 'removeEventListener');
api.diag.debug(
'removing previous patch from method removeEventListener'
EVENT_TARGETS.forEach(target => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IE doesn't have addEventListener() rather we should be using attachEvent(both of which hang off window (for IE)).

I think it would be better to check for the existence of "attachEvent" and if so wrap as before otherwise wrap addEventListener.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above is assuming that we want to support IE <= 8

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to worry about anything below ie11 tbh.

* Document -> Node * -> EventTarget **! -> Object
* Window * -> WindowProperties ! -> EventTarget **! -> Object
*/
const EVENT_TARGETS = window.EventTarget
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As isWrapped handles detection of whether a function has already been wrapped, why not just always list the entry points that we want to wrap, rather than the split (which really would require tests to be run against IE to ensure this doesn't get broken).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also assumes (which is generally true), that the root object names "Node", "Window" "EventTarget" always exist in all runtimes (which they may not).

Would suggest that we have an additional "wrap" function that can take the target and funcName so that it can do the following and wrap the correct level.

  • Check if target is not null/undefined (if true -- nothing to wrap => abort wrap)
  • Check if target[funcName] is defined (effectively check for instance level override) (if true wrap instance function (for wrapping simple polyfill's); if false check next)
  • Get prototype of target (this can be tricky for all environments)
  • Check if targetPrototype[funcName] exists (if true wrap; otherwise abort wrap)

Examples of getting the correct target are in the ApplicationInsights code I wrote, this is more than what OT needs as it supports a larger set of runtimes (ie. all browsers (IE7+), Node, React, Angular, ReactNative and variants etc.) https://github.com/microsoft/ApplicationInsights-JS/blob/master/shared/AppInsightsCore/src/JavaScriptSDK/InstrumentHooks.ts#L152-L181

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tracked through the this._wrap which is really the shimmer project dependency, it does almost all of the above except for the prototype lookup if it's not defined on the target. It also has a dependency on Object.defineProperty (which I assume is not the only place in the IT code 😄 ) so my previous comment about IE <= 8 is mute as this just won't work anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering opentelemetry's support for browsers ("should work in currently supported versions of major browsers.") and microsoft's lifecycle policy for IE I think it's fair to let older versions of IE rest and sometime next century (optimistic, I know) maybe this and IE 11 can be thrown away.

This also assumes (which is generally true), that the root object names "Node", "Window" "EventTarget" always exist in all runtimes (which they may not).

Think a browser runtime that doesn't support DOM spec essentials like those has bigger issues than opentelemetry support, separate question if/how much browser instrumentations should protect the user from trying to run it in server side environments or expect users to know better than that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping @MSNev was your concerns resolved ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think a browser runtime that doesn't support DOM spec essentials like those has bigger issues than opentelemetry support

It's not the browser runtimes you need to be aware of as they generally have them all, it's other native runtimes that "support" JavaScript...

maybe this and IE 11 can be thrown away.

I'm still waiting for IE7/8 to be thrown away and as part of the ApplicationInsights work we have to make sure it keeps working (mostly for the health industry) as they tend to lag and still have older versions of Windows and IE. Additionally, when you run IE 11 as an "embedded" browser (create a C# app and drop a browser component on it), by default it runs in IE7 mode.

I haven't checked if you have created separate tests (I suspect not, based on comments and the runtime), so this would mean that this comment is still valid

why not just always list the entry points that we want to wrap, rather than the split (which really would require tests to be run against IE to ensure this doesn't get broken).

So this really means that we are adding a code path this is never tested (the primary concern)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MSNev what do you think should be changed and how so that we can proceed with this PR further. In current state do you think this PR provides any regression or still adds some value comparing to what we have now - even if some tests are missing ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not seeing any regression -- signed off

would be nice if local errors were anywhere close to CI-s output but no
Copy link
Member

@obecny obecny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, just a suggestion to try to use sinon sandbox so that you don't have to worry about cleaning up

@obecny obecny merged commit 5a00bed into open-telemetry:main Oct 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants