-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(browser): Fix memory leak in
addEventListener
instrumentation (#…
- Loading branch information
Showing
11 changed files
with
203 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
...ests/suites/public-api/instrumentation/eventListener-instrumentation-behaviour/subject.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Simple function event listener | ||
const functionListener = () => { | ||
functionListenerCallback(); | ||
}; | ||
|
||
// Attach event listener twice | ||
window.addEventListener('click', functionListener); | ||
window.addEventListener('click', functionListener); | ||
|
||
// Event listener that has handleEvent() method: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#listener | ||
class EventHandlerClass { | ||
handleEvent() { | ||
objectListenerCallback(); | ||
} | ||
} | ||
|
||
const objectListener = new EventHandlerClass(); | ||
|
||
// Attach event listener twice | ||
window.addEventListener('click', objectListener); | ||
window.addEventListener('click', objectListener); |
28 changes: 28 additions & 0 deletions
28
...n-tests/suites/public-api/instrumentation/eventListener-instrumentation-behaviour/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { expect } from '@playwright/test'; | ||
|
||
import { sentryTest } from '../../../../utils/fixtures'; | ||
|
||
sentryTest( | ||
'Event listener instrumentation should attach the same event listener only once', | ||
async ({ getLocalTestPath, page }) => { | ||
const url = await getLocalTestPath({ testDir: __dirname }); | ||
await page.goto(url); | ||
|
||
let functionListenerCalls = 0; | ||
await page.exposeFunction('functionListenerCallback', () => { | ||
functionListenerCalls = functionListenerCalls + 1; | ||
}); | ||
|
||
let objectListenerCalls = 0; | ||
await page.exposeFunction('objectListenerCallback', () => { | ||
objectListenerCalls = objectListenerCalls + 1; | ||
}); | ||
|
||
// Trigger event listeners twice | ||
await page.evaluate('document.body.click()'); | ||
await page.evaluate('document.body.click()'); | ||
|
||
expect(functionListenerCalls).toBe(2); | ||
expect(objectListenerCalls).toBe(2); | ||
}, | ||
); |
24 changes: 24 additions & 0 deletions
24
...ration-tests/suites/public-api/instrumentation/eventListener-this-preservation/subject.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const btn = document.createElement('button'); | ||
btn.id = 'btn'; | ||
document.body.appendChild(btn); | ||
|
||
const functionListener = function () { | ||
functionCallback(this.constructor.name); | ||
}; | ||
|
||
class EventHandlerClass { | ||
handleEvent() { | ||
classInstanceCallback(this.constructor.name); | ||
} | ||
} | ||
const objectListener = new EventHandlerClass(); | ||
|
||
// Attach event listeners a few times for good measure | ||
|
||
btn.addEventListener('click', functionListener); | ||
btn.addEventListener('click', functionListener); | ||
btn.addEventListener('click', functionListener); | ||
|
||
btn.addEventListener('click', objectListener); | ||
btn.addEventListener('click', objectListener); | ||
btn.addEventListener('click', objectListener); |
24 changes: 24 additions & 0 deletions
24
...tegration-tests/suites/public-api/instrumentation/eventListener-this-preservation/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { expect } from '@playwright/test'; | ||
|
||
import { sentryTest } from '../../../../utils/fixtures'; | ||
|
||
sentryTest('Event listener instrumentation preserves "this" context', async ({ getLocalTestPath, page }) => { | ||
const url = await getLocalTestPath({ testDir: __dirname }); | ||
await page.goto(url); | ||
|
||
let assertions = 0; | ||
|
||
await page.exposeFunction('functionCallback', (thisInstanceName: unknown) => { | ||
expect(thisInstanceName).toBe('HTMLButtonElement'); | ||
assertions = assertions + 1; | ||
}); | ||
|
||
await page.exposeFunction('classInstanceCallback', (thisInstanceName: unknown) => { | ||
expect(thisInstanceName).toBe('EventHandlerClass'); | ||
assertions = assertions + 1; | ||
}); | ||
|
||
await page.evaluate('document.getElementById("btn").click()'); | ||
|
||
expect(assertions).toBe(2); | ||
}); |
18 changes: 18 additions & 0 deletions
18
...ges/integration-tests/suites/public-api/instrumentation/eventListener-wrapping/subject.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Simple function event listener | ||
const functionListener = () => { | ||
reportFunctionListenerStackHeight(new Error().stack.split('\n').length); | ||
}; | ||
|
||
// Event listener that has handleEvent() method: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#listener | ||
class EventHandlerClass { | ||
handleEvent() { | ||
reportObjectListenerStackHeight(new Error().stack.split('\n').length); | ||
} | ||
} | ||
|
||
const objectListener = new EventHandlerClass(); | ||
|
||
window.attachListeners = function () { | ||
window.addEventListener('click', functionListener); | ||
window.addEventListener('click', objectListener); | ||
}; |
38 changes: 38 additions & 0 deletions
38
packages/integration-tests/suites/public-api/instrumentation/eventListener-wrapping/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { expect } from '@playwright/test'; | ||
|
||
import { sentryTest } from '../../../../utils/fixtures'; | ||
|
||
sentryTest( | ||
'Event listener instrumentation should not wrap event listeners multiple times', | ||
async ({ getLocalTestPath, page }) => { | ||
const url = await getLocalTestPath({ testDir: __dirname }); | ||
await page.goto(url); | ||
|
||
const functionListenerStackHeights: number[] = []; | ||
const objectListenerStackHeights: number[] = []; | ||
|
||
await page.exposeFunction('reportFunctionListenerStackHeight', (height: number) => { | ||
functionListenerStackHeights.push(height); | ||
}); | ||
|
||
await page.exposeFunction('reportObjectListenerStackHeight', (height: number) => { | ||
objectListenerStackHeights.push(height); | ||
}); | ||
|
||
// Attach initial listeners | ||
await page.evaluate('window.attachListeners()'); | ||
await page.evaluate('document.body.click()'); | ||
|
||
await page.evaluate('window.attachListeners()'); | ||
await page.evaluate('window.attachListeners()'); | ||
await page.evaluate('window.attachListeners()'); | ||
await page.evaluate('document.body.click()'); | ||
|
||
expect(functionListenerStackHeights).toHaveLength(2); | ||
expect(objectListenerStackHeights).toHaveLength(2); | ||
|
||
// check if all error stack traces are the same height | ||
expect(functionListenerStackHeights.every((val, _i, arr) => val === arr[0])).toBeTruthy(); | ||
expect(objectListenerStackHeights.every((val, _i, arr) => val === arr[0])).toBeTruthy(); | ||
}, | ||
); |
5 changes: 5 additions & 0 deletions
5
packages/integration-tests/suites/public-api/instrumentation/eventListener/subject.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
window.addEventListener('click', () => { | ||
throw new Error('event_listener_error'); | ||
}); | ||
|
||
document.body.click(); |
27 changes: 27 additions & 0 deletions
27
packages/integration-tests/suites/public-api/instrumentation/eventListener/test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { expect } from '@playwright/test'; | ||
import { Event } from '@sentry/types'; | ||
|
||
import { sentryTest } from '../../../../utils/fixtures'; | ||
import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; | ||
|
||
sentryTest( | ||
'Event listener instrumentation should capture an error thrown in an event handler', | ||
async ({ getLocalTestPath, page }) => { | ||
const url = await getLocalTestPath({ testDir: __dirname }); | ||
|
||
const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url); | ||
|
||
expect(eventData.exception?.values).toHaveLength(1); | ||
expect(eventData.exception?.values?.[0]).toMatchObject({ | ||
type: 'Error', | ||
value: 'event_listener_error', | ||
mechanism: { | ||
type: 'instrument', | ||
handled: true, | ||
}, | ||
stacktrace: { | ||
frames: expect.any(Array), | ||
}, | ||
}); | ||
}, | ||
); |
7 changes: 7 additions & 0 deletions
7
packages/integration-tests/suites/public-api/instrumentation/init.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import * as Sentry from '@sentry/browser'; | ||
|
||
window.Sentry = Sentry; | ||
|
||
Sentry.init({ | ||
dsn: 'https://public@dsn.ingest.sentry.io/1337', | ||
}); |