diff --git a/packages/rum-core/src/domain/configuration.spec.ts b/packages/rum-core/src/domain/configuration.spec.ts index 6d71c6b3ae..a2a9056838 100644 --- a/packages/rum-core/src/domain/configuration.spec.ts +++ b/packages/rum-core/src/domain/configuration.spec.ts @@ -302,35 +302,6 @@ describe('validateAndBuildRumConfiguration', () => { }) }) - describe('trackFrustrations', () => { - it('defaults to false', () => { - expect(validateAndBuildRumConfiguration(DEFAULT_INIT_CONFIGURATION)!.trackFrustrations).toBeFalse() - }) - - it('the initialization parameter is set to provided value', () => { - expect( - validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, trackFrustrations: true })!.trackFrustrations - ).toBeTrue() - expect( - validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, trackFrustrations: false })!.trackFrustrations - ).toBeFalse() - }) - - it('the initialization parameter the provided value is cast to boolean', () => { - expect( - validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, trackFrustrations: 'foo' as any })! - .trackFrustrations - ).toBeTrue() - }) - - it('implies "trackUserInteractions"', () => { - expect( - validateAndBuildRumConfiguration({ ...DEFAULT_INIT_CONFIGURATION, trackFrustrations: true })! - .trackUserInteractions - ).toBeTrue() - }) - }) - describe('trackViewsManually', () => { it('defaults to false', () => { expect(validateAndBuildRumConfiguration(DEFAULT_INIT_CONFIGURATION)!.trackViewsManually).toBeFalse() diff --git a/packages/rum-core/src/domain/configuration.ts b/packages/rum-core/src/domain/configuration.ts index 0162f87157..6453947535 100644 --- a/packages/rum-core/src/domain/configuration.ts +++ b/packages/rum-core/src/domain/configuration.ts @@ -41,7 +41,6 @@ export interface RumInitConfiguration extends InitConfiguration { // action options trackUserInteractions?: boolean | undefined - trackFrustrations?: boolean | undefined actionNameAttribute?: string | undefined // view options @@ -64,7 +63,6 @@ export interface RumConfiguration extends Configuration { oldPlansBehavior: boolean sessionReplaySampleRate: number trackUserInteractions: boolean - trackFrustrations: boolean trackViewsManually: boolean trackResources: boolean | undefined trackLongTasks: boolean | undefined @@ -121,8 +119,6 @@ export function validateAndBuildRumConfiguration( return } - const trackFrustrations = !!initConfiguration.trackFrustrations - return assign( { applicationId: initConfiguration.applicationId, @@ -133,8 +129,7 @@ export function validateAndBuildRumConfiguration( traceSampleRate: initConfiguration.traceSampleRate, allowedTracingUrls, excludedActivityUrls: initConfiguration.excludedActivityUrls ?? [], - trackUserInteractions: !!initConfiguration.trackUserInteractions || trackFrustrations, - trackFrustrations, + trackUserInteractions: !!initConfiguration.trackUserInteractions, trackViewsManually: !!initConfiguration.trackViewsManually, trackResources: initConfiguration.trackResources, trackLongTasks: initConfiguration.trackLongTasks, @@ -218,7 +213,6 @@ export function serializeRumConfiguration(configuration: RumInitConfiguration): default_privacy_level: configuration.defaultPrivacyLevel, use_excluded_activity_urls: Array.isArray(configuration.excludedActivityUrls) && configuration.excludedActivityUrls.length > 0, - track_frustrations: configuration.trackFrustrations, track_views_manually: configuration.trackViewsManually, track_user_interactions: configuration.trackUserInteractions, }, diff --git a/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.spec.ts index 198d89a428..3d70e81dee 100644 --- a/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.spec.ts @@ -167,268 +167,195 @@ describe('trackClickActions', () => { expect(events[0].name).toBe('test-1') }) - describe('without tracking frustrations', () => { - it('discards any click action with a negative duration', () => { - const { clock } = setupBuilder.build() - emulateClick({ activity: { delay: -1 } }) - expect(findActionId()).not.toBeUndefined() - clock.tick(EXPIRE_DELAY) + it('discards any click action with a negative duration', () => { + const { clock } = setupBuilder.build() + emulateClick({ activity: { delay: -1 } }) + expect(findActionId()!.length).toEqual(2) + clock.tick(EXPIRE_DELAY) - expect(events).toEqual([]) - expect(findActionId()).toBeUndefined() - }) + expect(events).toEqual([]) + expect(findActionId()).toEqual([]) + }) - it('discards ongoing click action on view ended', () => { - const { lifeCycle, clock } = setupBuilder.build() - emulateClick({ activity: {} }) - expect(findActionId()).not.toBeUndefined() + it('ongoing click action is stopped on view end', () => { + const { lifeCycle, clock } = setupBuilder.build() + emulateClick({ activity: { delay: BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY } }) - lifeCycle.notify(LifeCycleEventType.VIEW_ENDED, { - endClocks: clocksNow(), - }) - clock.tick(EXPIRE_DELAY) + clock.tick(BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY) - expect(events).toEqual([]) - expect(findActionId()).toBeUndefined() + lifeCycle.notify(LifeCycleEventType.VIEW_ENDED, { + endClocks: clocksNow(), }) - it('ignores any starting click action while another one is ongoing', () => { - const { clock } = setupBuilder.build() + expect(events.length).toBe(1) + expect(events[0].duration).toBe((2 * BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY) as Duration) + }) + it('collect click actions even if another one is ongoing', () => { + const { clock } = setupBuilder.build() + + const firstPointerDownTimeStamp = timeStampNow() + emulateClick({ activity: {} }) + const secondPointerDownTimeStamp = timeStampNow() + emulateClick({ activity: {} }) + + clock.tick(EXPIRE_DELAY) + expect(events.length).toBe(2) + expect(events[0].startClocks.timeStamp).toBe(addDuration(firstPointerDownTimeStamp, EMULATED_CLICK_DURATION)) + expect(events[1].startClocks.timeStamp).toBe(addDuration(secondPointerDownTimeStamp, EMULATED_CLICK_DURATION)) + }) + + it('collect click actions even if nothing happens after a click (dead click)', () => { + const { clock } = setupBuilder.build() + emulateClick() + + clock.tick(EXPIRE_DELAY) + expect(events.length).toBe(1) + expect(events[0].frustrationTypes).toEqual([FrustrationType.DEAD_CLICK]) + expect(findActionId()).toEqual([]) + }) + + it('does not set a duration for dead clicks', () => { + const { clock } = setupBuilder.build() + emulateClick() + + clock.tick(EXPIRE_DELAY) + expect(events.length).toBe(1) + expect(events[0].duration).toBeUndefined() + }) + + it('collect click actions even if it fails to find a name', () => { + const { clock } = setupBuilder.build() + emulateClick({ activity: {}, target: emptyElement }) + expect(findActionId()!.length).toBeGreaterThan(0) + clock.tick(EXPIRE_DELAY) + + expect(events.length).toBe(1) + }) + + describe('rage clicks', () => { + it('considers a chain of three clicks or more as a single action with "rage" frustration type', () => { + const { clock } = setupBuilder.build() const firstPointerDownTimeStamp = timeStampNow() - emulateClick({ activity: {} }) - emulateClick({ activity: {} }) + const activityDelay = 5 + emulateClick({ activity: { delay: activityDelay } }) + emulateClick({ activity: { delay: activityDelay } }) + emulateClick({ activity: { delay: activityDelay } }) clock.tick(EXPIRE_DELAY) expect(events.length).toBe(1) expect(events[0].startClocks.timeStamp).toBe(addDuration(firstPointerDownTimeStamp, EMULATED_CLICK_DURATION)) + expect(events[0].frustrationTypes).toEqual([FrustrationType.RAGE_CLICK]) + expect(events[0].duration).toBe( + (MAX_DURATION_BETWEEN_CLICKS + 2 * activityDelay + 2 * EMULATED_CLICK_DURATION) as Duration + ) }) - it('discards a click action when nothing happens after a click', () => { + it('should contain original events from of rage sequence', () => { const { clock } = setupBuilder.build() - emulateClick() + const activityDelay = 5 + emulateClick({ activity: { delay: activityDelay } }) + emulateClick({ activity: { delay: activityDelay } }) + emulateClick({ activity: { delay: activityDelay } }) clock.tick(EXPIRE_DELAY) - expect(events).toEqual([]) - expect(findActionId()).toBeUndefined() - }) - - it('ignores a click action if it fails to find a name', () => { - const { clock } = setupBuilder.build() - emulateClick({ activity: {}, target: emptyElement }) - expect(findActionId()).toBeUndefined() - clock.tick(EXPIRE_DELAY) - - expect(events).toEqual([]) + expect(events.length).toBe(1) + expect(events[0].frustrationTypes).toEqual([FrustrationType.RAGE_CLICK]) + expect(events[0].events?.length).toBe(3) }) - it('does not populate the frustrationTypes array', () => { + it('aggregates frustrationTypes from all clicks', () => { const { lifeCycle, clock } = setupBuilder.build() + // Dead + emulateClick() + clock.tick(PAGE_ACTIVITY_VALIDATION_DELAY) + + // Error emulateClick({ activity: {} }) lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) + clock.tick(PAGE_ACTIVITY_VALIDATION_DELAY) + + // Third click to make a rage click + emulateClick({ activity: {} }) clock.tick(EXPIRE_DELAY) expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual([]) + expect(events[0].frustrationTypes).toEqual( + jasmine.arrayWithExactContents([ + FrustrationType.DEAD_CLICK, + FrustrationType.ERROR_CLICK, + FrustrationType.RAGE_CLICK, + ]) + ) }) }) - describe('when tracking frustrations', () => { - beforeEach(() => { - setupBuilder.withConfiguration({ trackFrustrations: true }) - }) - - it('discards any click action with a negative duration', () => { - const { clock } = setupBuilder.build() - emulateClick({ activity: { delay: -1 } }) - expect(findActionId()!.length).toEqual(2) - clock.tick(EXPIRE_DELAY) - - expect(events).toEqual([]) - expect(findActionId()).toEqual([]) - }) - - it('ongoing click action is stopped on view end', () => { + describe('error clicks', () => { + it('considers a "click with activity" followed by an error as a click action with "error" frustration type', () => { const { lifeCycle, clock } = setupBuilder.build() - emulateClick({ activity: { delay: BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY } }) - clock.tick(BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY) - - lifeCycle.notify(LifeCycleEventType.VIEW_ENDED, { - endClocks: clocksNow(), - }) + emulateClick({ activity: {} }) + lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) + clock.tick(EXPIRE_DELAY) expect(events.length).toBe(1) - expect(events[0].duration).toBe((2 * BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY) as Duration) + expect(events[0].frustrationTypes).toEqual([FrustrationType.ERROR_CLICK]) }) - it('collect click actions even if another one is ongoing', () => { - const { clock } = setupBuilder.build() + it('considers a "click without activity" followed by an error as a click action with "error" (and "dead") frustration type', () => { + const { lifeCycle, clock } = setupBuilder.build() - const firstPointerDownTimeStamp = timeStampNow() - emulateClick({ activity: {} }) - const secondPointerDownTimeStamp = timeStampNow() - emulateClick({ activity: {} }) + emulateClick() + lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(2) - expect(events[0].startClocks.timeStamp).toBe(addDuration(firstPointerDownTimeStamp, EMULATED_CLICK_DURATION)) - expect(events[1].startClocks.timeStamp).toBe(addDuration(secondPointerDownTimeStamp, EMULATED_CLICK_DURATION)) + expect(events.length).toBe(1) + expect(events[0].frustrationTypes).toEqual( + jasmine.arrayWithExactContents([FrustrationType.ERROR_CLICK, FrustrationType.DEAD_CLICK]) + ) }) + }) - it('collect click actions even if nothing happens after a click (dead click)', () => { + describe('dead clicks', () => { + it('considers a "click without activity" as a dead click', () => { const { clock } = setupBuilder.build() + emulateClick() clock.tick(EXPIRE_DELAY) expect(events.length).toBe(1) expect(events[0].frustrationTypes).toEqual([FrustrationType.DEAD_CLICK]) - expect(findActionId()).toEqual([]) }) - it('does not set a duration for dead clicks', () => { + it('does not consider a click with activity happening on pointerdown as a dead click', () => { const { clock } = setupBuilder.build() - emulateClick() - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].duration).toBeUndefined() - }) + emulateClick({ activity: { on: 'pointerdown' } }) - it('collect click actions even if it fails to find a name', () => { - const { clock } = setupBuilder.build() - emulateClick({ activity: {}, target: emptyElement }) - expect(findActionId()!.length).toBeGreaterThan(0) clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) + expect(events[0].frustrationTypes).toEqual([]) }) - describe('rage clicks', () => { - it('considers a chain of three clicks or more as a single action with "rage" frustration type', () => { - const { clock } = setupBuilder.build() - const firstPointerDownTimeStamp = timeStampNow() - const activityDelay = 5 - emulateClick({ activity: { delay: activityDelay } }) - emulateClick({ activity: { delay: activityDelay } }) - emulateClick({ activity: { delay: activityDelay } }) - - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].startClocks.timeStamp).toBe(addDuration(firstPointerDownTimeStamp, EMULATED_CLICK_DURATION)) - expect(events[0].frustrationTypes).toEqual([FrustrationType.RAGE_CLICK]) - expect(events[0].duration).toBe( - (MAX_DURATION_BETWEEN_CLICKS + 2 * activityDelay + 2 * EMULATED_CLICK_DURATION) as Duration - ) - }) - - it('should contain original events from of rage sequence', () => { - const { clock } = setupBuilder.build() - const activityDelay = 5 - emulateClick({ activity: { delay: activityDelay } }) - emulateClick({ activity: { delay: activityDelay } }) - emulateClick({ activity: { delay: activityDelay } }) - - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual([FrustrationType.RAGE_CLICK]) - expect(events[0].events?.length).toBe(3) - }) - - it('aggregates frustrationTypes from all clicks', () => { - const { lifeCycle, clock } = setupBuilder.build() - - // Dead - emulateClick() - clock.tick(PAGE_ACTIVITY_VALIDATION_DELAY) - - // Error - emulateClick({ activity: {} }) - lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) - clock.tick(PAGE_ACTIVITY_VALIDATION_DELAY) - - // Third click to make a rage click - emulateClick({ activity: {} }) - - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual( - jasmine.arrayWithExactContents([ - FrustrationType.DEAD_CLICK, - FrustrationType.ERROR_CLICK, - FrustrationType.RAGE_CLICK, - ]) - ) - }) - }) - - describe('error clicks', () => { - it('considers a "click with activity" followed by an error as a click action with "error" frustration type', () => { - const { lifeCycle, clock } = setupBuilder.build() - - emulateClick({ activity: {} }) - lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) - - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual([FrustrationType.ERROR_CLICK]) - }) - - it('considers a "click without activity" followed by an error as a click action with "error" (and "dead") frustration type', () => { - const { lifeCycle, clock } = setupBuilder.build() + it('activity happening on pointerdown is not taken into account for the action duration', () => { + const { clock } = setupBuilder.build() - emulateClick() - lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) + emulateClick({ activity: { on: 'pointerdown' } }) - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual( - jasmine.arrayWithExactContents([FrustrationType.ERROR_CLICK, FrustrationType.DEAD_CLICK]) - ) - }) + clock.tick(EXPIRE_DELAY) + expect(events.length).toBe(1) + expect(events[0].duration).toBe(0 as Duration) }) - describe('dead clicks', () => { - it('considers a "click without activity" as a dead click', () => { - const { clock } = setupBuilder.build() - - emulateClick() - - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual([FrustrationType.DEAD_CLICK]) - }) - - it('does not consider a click with activity happening on pointerdown as a dead click', () => { - const { clock } = setupBuilder.build() - - emulateClick({ activity: { on: 'pointerdown' } }) - - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual([]) - }) - - it('activity happening on pointerdown is not taken into account for the action duration', () => { - const { clock } = setupBuilder.build() - - emulateClick({ activity: { on: 'pointerdown' } }) - - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].duration).toBe(0 as Duration) - }) - - it('does not consider a click with activity happening on pointerup as a dead click', () => { - const { clock } = setupBuilder.build() + it('does not consider a click with activity happening on pointerup as a dead click', () => { + const { clock } = setupBuilder.build() - emulateClick({ activity: { on: 'pointerup' } }) + emulateClick({ activity: { on: 'pointerup' } }) - clock.tick(EXPIRE_DELAY) - expect(events.length).toBe(1) - expect(events[0].frustrationTypes).toEqual([]) - }) + clock.tick(EXPIRE_DELAY) + expect(events.length).toBe(1) + expect(events[0].frustrationTypes).toEqual([]) }) }) diff --git a/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.ts b/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.ts index 357c8d6b4e..4b5a58fd76 100644 --- a/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/rumEventsCollection/action/trackClickActions.ts @@ -82,7 +82,7 @@ export function trackClickActions( hadActivityOnPointerDown: () => boolean }>({ onPointerDown: (pointerDownEvent) => - processPointerDown(configuration, lifeCycle, domMutationObservable, history, pointerDownEvent), + processPointerDown(configuration, lifeCycle, domMutationObservable, pointerDownEvent), onPointerUp: ({ clickActionBase, hadActivityOnPointerDown }, startEvent, getUserActivity) => startClickAction( configuration, @@ -99,8 +99,7 @@ export function trackClickActions( }) const actionContexts: ActionContexts = { - findActionId: (startTime?: RelativeTime) => - configuration.trackFrustrations ? history.findAll(startTime) : history.find(startTime), + findActionId: (startTime?: RelativeTime) => history.findAll(startTime), } return { @@ -132,21 +131,9 @@ function processPointerDown( configuration: RumConfiguration, lifeCycle: LifeCycle, domMutationObservable: Observable, - history: ClickActionIdHistory, pointerDownEvent: MouseEventOnElement ) { - if (!configuration.trackFrustrations && history.find()) { - // TODO: remove this in a future major version. To keep retrocompatibility, ignore any new - // action if another one is already occurring. - return - } - const clickActionBase = computeClickActionBase(pointerDownEvent, configuration.actionNameAttribute) - if (!configuration.trackFrustrations && !clickActionBase.name) { - // TODO: remove this in a future major version. To keep retrocompatibility, ignore any action - // with a blank name - return - } let hadActivityOnPointerDown = false @@ -178,10 +165,7 @@ function startClickAction( hadActivityOnPointerDown: () => boolean ) { const click = newClick(lifeCycle, history, getUserActivity, clickActionBase, startEvent) - - if (configuration.trackFrustrations) { - appendClickToClickChain(click) - } + appendClickToClickChain(click) const { stop: stopWaitPageActivityEnd } = waitPageActivityEnd( lifeCycle, @@ -203,18 +187,6 @@ function startClickAction( } else { click.stop() } - - // Validate or discard the click only if we don't track frustrations. It'll be done when - // the click chain is finalized. - if (!configuration.trackFrustrations) { - if (!pageActivityEndEvent.hadActivity) { - // If we are not tracking frustrations, we should discard the click to keep backward - // compatibility. - click.discard() - } else { - click.validate() - } - } } }, CLICK_ACTION_MAX_DURATION diff --git a/test/e2e/scenario/recorder/recorder.scenario.ts b/test/e2e/scenario/recorder/recorder.scenario.ts index bead027797..6a2699ed5c 100644 --- a/test/e2e/scenario/recorder/recorder.scenario.ts +++ b/test/e2e/scenario/recorder/recorder.scenario.ts @@ -691,7 +691,7 @@ describe('recorder', () => { describe('frustration records', () => { createTest('should detect a dead click and match it to mouse interaction record') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withRumInit(initRumAndStartRecording) .withSetup(bundleSetup) .run(async ({ serverEvents }) => { @@ -715,7 +715,7 @@ describe('recorder', () => { }) createTest('should detect a rage click and match it to mouse interaction records') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withRumInit(initRumAndStartRecording) .withSetup(bundleSetup) .withBody( diff --git a/test/e2e/scenario/rum/actions.scenario.ts b/test/e2e/scenario/rum/actions.scenario.ts index c3e8c288e6..66d52955d0 100644 --- a/test/e2e/scenario/rum/actions.scenario.ts +++ b/test/e2e/scenario/rum/actions.scenario.ts @@ -62,7 +62,7 @@ describe('action collection', () => { }) createTest('compute action target information before the UI changes') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody( html` @@ -91,7 +91,7 @@ describe('action collection', () => { // click event. Skip this test. if (getBrowserName() !== 'firefox') { createTest('does not report a click on the body when the target element changes between mousedown and mouseup') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody( html` @@ -160,15 +160,13 @@ describe('action collection', () => { }) expect(resourceEvents.length).toBe(1) - expect(resourceEvents[0].action!.id).toBe(actionEvents[0].action.id!) + // resource action id should contain the collected action id + the discarded rage click id + expect(resourceEvents[0].action!.id.length).toBe(2) + expect(resourceEvents[0].action!.id).toContain(actionEvents[0].action.id!) }) createTest('increment the view.action.count of the view active when the action started') - .withRum({ - // Frustrations need to be collected for this test case, else actions leading to a new view - // are ignored - trackFrustrations: true, - }) + .withRum({ trackUserInteractions: true }) .withBody( html` @@ -195,7 +193,7 @@ describe('action collection', () => { }) createTest('collect an "error click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody( html` @@ -226,7 +224,7 @@ describe('action collection', () => { }) createTest('collect a "dead click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody(html` `) .run(async ({ serverEvents }) => { const button = await $('button') @@ -241,7 +239,7 @@ describe('action collection', () => { }) createTest('do not consider a click on a checkbox as "dead_click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody(html` `) .run(async ({ serverEvents }) => { const input = await $('input') @@ -254,7 +252,7 @@ describe('action collection', () => { }) createTest('do not consider a click to change the value of a "range" input as "dead_click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody(html` `) .run(async ({ serverEvents }) => { const input = await $('input') @@ -267,7 +265,7 @@ describe('action collection', () => { }) createTest('consider a click on an already checked "radio" input as "dead_click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody(html` `) .run(async ({ serverEvents }) => { const input = await $('input') @@ -280,7 +278,7 @@ describe('action collection', () => { }) createTest('do not consider a click on text input as "dead_click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody(html` `) .run(async ({ serverEvents }) => { const input = await $('input') @@ -293,7 +291,7 @@ describe('action collection', () => { }) createTest('do not consider a click that open a new window as "dead_click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody( html` @@ -322,7 +320,7 @@ describe('action collection', () => { }) createTest('collect a "rage click"') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody( html` @@ -345,7 +343,7 @@ describe('action collection', () => { }) createTest('collect multiple frustrations in one action') - .withRum({ trackFrustrations: true }) + .withRum({ trackUserInteractions: true }) .withBody( html`