Skip to content

Commit 1b117fe

Browse files
committed
Merge branch 'NR-443293-network-requests' into NR-443294-navigations
2 parents 486dace + 92b561e commit 1b117fe

File tree

4 files changed

+51
-8
lines changed

4 files changed

+51
-8
lines changed

src/features/generic_events/aggregate/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class Aggregate extends AggregateBase {
5959

6060
let addUserAction = () => { /** no-op */ }
6161
if (isBrowserScope && agentRef.init.user_actions.enabled) {
62-
this.userActionAggregator = new UserActionsAggregator()
62+
this.userActionAggregator = new UserActionsAggregator(agentRef.init.feature_flags.includes('user_frustrations'))
6363
this.harvestOpts.beforeUnload = () => addUserAction?.(this.userActionAggregator.aggregationEvent)
6464

6565
addUserAction = (aggregatedUserAction) => {

src/features/generic_events/aggregate/user-actions/user-actions-aggregator.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@ export class UserActionsAggregator {
1111
/** @type {AggregatedUserAction=} */
1212
#aggregationEvent = undefined
1313
#aggregationKey = ''
14+
#ufEnabled = false
1415
#deadClickTimer = undefined
1516
#domObserver = {
1617
instance: undefined
1718
}
1819

1920
#errorClickTimer = undefined
2021

21-
constructor () {
22-
if (MutationObserver) {
22+
constructor (userFrustrationsEnabled) {
23+
if (userFrustrationsEnabled && MutationObserver) {
2324
this.#domObserver.instance = new MutationObserver(this.treatAsLiveClick.bind(this))
25+
this.#ufEnabled = true
2426
}
2527
}
2628

@@ -49,13 +51,13 @@ export class UserActionsAggregator {
4951
} else {
5052
// return the prev existing one (if there is one)
5153
const finishedEvent = this.#aggregationEvent
52-
this.#deadClickCleanup()
53-
this.#errorClickCleanup()
54+
this.#ufEnabled && this.#deadClickCleanup()
55+
this.#ufEnabled && this.#errorClickCleanup()
5456

5557
// then start new event aggregation
5658
this.#aggregationKey = aggregationKey
5759
this.#aggregationEvent = new AggregatedUserAction(evt, selectorInfo)
58-
if (evt.type === 'click' && (selectorInfo.hasButton || selectorInfo.hasLink)) {
60+
if (this.#ufEnabled && evt.type === 'click' && (selectorInfo.hasButton || selectorInfo.hasLink)) {
5961
this.#deadClickSetup(this.#aggregationEvent)
6062
this.#errorClickSetup()
6163
}

tests/specs/npm/index.e2e.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ describe('basic npm agent', () => {
9595
expect(agentSession.localStorage).toEqual({})
9696
})
9797

98+
// Note: the order of this test and the "session manager cannot be imported" test is important
9899
it('vite-react-wrapper sends basic calls', async () => {
99100
const [rumHarvests] = await Promise.all([
100101
rumCapture.waitForResult({ totalCount: 1 }),

tests/unit/features/generic_events/aggregate/user-actions/user-actions-aggregator.test.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,32 @@ describe('UserActionsAggregator - Dead Clicks', () => {
8080
let aggregator
8181
beforeEach(() => {
8282
jest.useFakeTimers()
83-
aggregator = new UserActionsAggregator()
83+
aggregator = new UserActionsAggregator(true)
8484
})
8585
afterEach(() => {
8686
jest.useRealTimers()
8787
})
88+
89+
test('should NOT set deadClick if user frustrations is disabled', () => {
90+
aggregator = new UserActionsAggregator(false)
91+
const link = document.createElement('a')
92+
document.body.appendChild(link)
93+
const evt = { type: 'click', target: link }
94+
aggregator.process(evt)
95+
expect(aggregator.isEvaluatingDeadClick()).toBe(false)
96+
97+
jest.advanceTimersByTime(2000)
98+
99+
const userAction = aggregator.aggregationEvent
100+
expect(userAction.deadClick).toBe(false)
101+
})
102+
88103
test('should set deadClick to true if no change detected after 2 seconds - buttons', () => {
89104
const btn = document.createElement('button')
90105
document.body.appendChild(btn)
91106
const evt = { type: 'click', target: btn }
92107
aggregator.process(evt)
108+
expect(aggregator.isEvaluatingDeadClick()).toBe(true)
93109

94110
jest.advanceTimersByTime(2000)
95111

@@ -102,6 +118,7 @@ describe('UserActionsAggregator - Dead Clicks', () => {
102118
document.body.appendChild(link)
103119
const evt = { type: 'click', target: link }
104120
aggregator.process(evt)
121+
expect(aggregator.isEvaluatingDeadClick()).toBe(true)
105122

106123
jest.advanceTimersByTime(2000)
107124

@@ -114,6 +131,7 @@ describe('UserActionsAggregator - Dead Clicks', () => {
114131
document.body.appendChild(span)
115132
const evt = { type: 'click', target: span }
116133
aggregator.process(evt)
134+
expect(aggregator.isEvaluatingDeadClick()).toBe(false)
117135

118136
jest.advanceTimersByTime(2000)
119137

@@ -126,6 +144,7 @@ describe('UserActionsAggregator - Dead Clicks', () => {
126144
document.body.appendChild(btn)
127145
const evt = { type: 'click', target: btn }
128146
aggregator.process(evt)
147+
expect(aggregator.isEvaluatingDeadClick()).toBe(true)
129148

130149
// Simulate a DOM mutation before the timer ends
131150
btn.setAttribute('data-test', 'mutated')
@@ -159,6 +178,7 @@ describe('UserActionsAggregator - Dead Clicks', () => {
159178
const keydownEvt = { type: 'keydown', target: btn }
160179

161180
aggregator.process(clickEvt)
181+
expect(aggregator.isEvaluatingDeadClick()).toBe(true)
162182
const finishedEvent = aggregator.process(keydownEvt) // Ends aggregation before timer
163183

164184
jest.advanceTimersByTime(2000)
@@ -171,11 +191,31 @@ describe('UserActionsAggregator - Error Clicks', () => {
171191
let aggregator
172192
beforeEach(() => {
173193
jest.useFakeTimers()
174-
aggregator = new UserActionsAggregator()
194+
aggregator = new UserActionsAggregator(true)
175195
})
176196
afterEach(() => {
177197
jest.useRealTimers()
178198
})
199+
test('should NOT set errorClick if user frustrations is disabled', () => {
200+
aggregator = new UserActionsAggregator(false)
201+
const btn = document.createElement('button')
202+
btn.onclick = () => {
203+
console.log('Simulating an error')
204+
throw new Error('Simulated error')
205+
}
206+
document.body.appendChild(btn)
207+
const evt = {
208+
type: 'click',
209+
target: btn
210+
}
211+
aggregator.process(evt, ['id', 'className', 'tagName', 'type'])
212+
jest.advanceTimersByTime(1999)
213+
aggregator.markAsErrorClick() // Simulate the error click
214+
jest.advanceTimersByTime(1)
215+
216+
const userAction = aggregator.aggregationEvent
217+
expect(userAction.errorClick).toBe(false)
218+
})
179219
test('should set errorClick to true if an error is detected within 2 seconds - buttons', () => {
180220
const btn = document.createElement('button')
181221
btn.onclick = () => {

0 commit comments

Comments
 (0)