From 2f089aa5eff02aa9b22812aa3e4af44a60b80679 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Thu, 25 Jul 2024 16:33:25 +0200 Subject: [PATCH 01/37] Add telemetry for null INP target --- .../domain/view/viewMetrics/trackInteractionToNextPaint.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 51ad3a2403..cd287c36cc 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,4 +1,4 @@ -import { elapsed, noop, ONE_MINUTE } from '@datadog/browser-core' +import { addTelemetryDebug, elapsed, noop, ONE_MINUTE } from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' import { RumPerformanceEntryType, supportPerformanceTimingEvent } from '../../../browser/performanceObservable' import type { RumFirstInputTiming, RumPerformanceEventTiming } from '../../../browser/performanceObservable' @@ -74,6 +74,9 @@ export function trackInteractionToNextPaint( configuration.actionNameAttribute ) } else { + addTelemetryDebug('INP target is null or not an element node', { + interactionToNextPaintStartTime, + }) interactionToNextPaintTargetSelector = undefined } } From c031764559af9989930dd14f49e5b4005bd5c99d Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 26 Jul 2024 15:39:03 +0200 Subject: [PATCH 02/37] Format --- .../viewMetrics/trackInteractionToNextPaint.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index cd287c36cc..dcee544427 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -65,18 +65,19 @@ export function trackInteractionToNextPaint( const newInteraction = longestInteractions.estimateP98Interaction() if (newInteraction && newInteraction.duration !== interactionToNextPaint) { + const inpTarget = newInteraction.target interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) - if (newInteraction.target && isElementNode(newInteraction.target)) { - interactionToNextPaintTargetSelector = getSelectorFromElement( - newInteraction.target, - configuration.actionNameAttribute - ) + addTelemetryDebug('INP target is null or not an element node', { + hasTarget: !!inpTarget, + targetIsConnected: inpTarget ? inpTarget.isConnected : null, + inp: newInteraction.duration, + }) + + if (inpTarget && isElementNode(inpTarget)) { + interactionToNextPaintTargetSelector = getSelectorFromElement(inpTarget, configuration.actionNameAttribute) } else { - addTelemetryDebug('INP target is null or not an element node', { - interactionToNextPaintStartTime, - }) interactionToNextPaintTargetSelector = undefined } } From 8fe1537e5b8669ca8d8decc507be3e947acb9301 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 26 Jul 2024 17:21:17 +0200 Subject: [PATCH 03/37] Add feature flag and reduce the amount of telemetry --- .../core/src/tools/experimentalFeatures.ts | 1 + .../trackInteractionToNextPaint.ts | 23 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/core/src/tools/experimentalFeatures.ts b/packages/core/src/tools/experimentalFeatures.ts index 6191d46327..c009e5aadb 100644 --- a/packages/core/src/tools/experimentalFeatures.ts +++ b/packages/core/src/tools/experimentalFeatures.ts @@ -19,6 +19,7 @@ export enum ExperimentalFeature { TOLERANT_RESOURCE_TIMINGS = 'tolerant_resource_timings', REMOTE_CONFIGURATION = 'remote_configuration', UPDATE_VIEW_NAME = 'update_view_name', + WEB_VITALS_INP = 'web_vitals_inp', } const enabledExperimentalFeatures: Set = new Set() diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index dcee544427..6b65602cd0 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,4 +1,4 @@ -import { addTelemetryDebug, elapsed, noop, ONE_MINUTE } from '@datadog/browser-core' +import { addTelemetryDebug, elapsed, ExperimentalFeature, isExperimentalFeatureEnabled, noop, ONE_MINUTE } from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' import { RumPerformanceEntryType, supportPerformanceTimingEvent } from '../../../browser/performanceObservable' import type { RumFirstInputTiming, RumPerformanceEventTiming } from '../../../browser/performanceObservable' @@ -68,16 +68,25 @@ export function trackInteractionToNextPaint( const inpTarget = newInteraction.target interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) - - addTelemetryDebug('INP target is null or not an element node', { - hasTarget: !!inpTarget, - targetIsConnected: inpTarget ? inpTarget.isConnected : null, - inp: newInteraction.duration, - }) + const isInpEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.WEB_VITALS_INP) if (inpTarget && isElementNode(inpTarget)) { interactionToNextPaintTargetSelector = getSelectorFromElement(inpTarget, configuration.actionNameAttribute) + if (!interactionToNextPaintTargetSelector && isInpEnabled) { + addTelemetryDebug('INP target selector is null', { + targetIsConnected: inpTarget.isConnected, + inp: newInteraction.duration, + }) + } } else { + if(isInpEnabled) { + addTelemetryDebug('INP target is null or not an element node', { + hasTarget: !!inpTarget, + targetIsConnected: inpTarget ? inpTarget.isConnected : null, + inp: newInteraction.duration, + }) + } + interactionToNextPaintTargetSelector = undefined } } From c0721516db4202d91d0f7ad9863030cfe5245a03 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 26 Jul 2024 17:29:05 +0200 Subject: [PATCH 04/37] Format --- .../view/viewMetrics/trackInteractionToNextPaint.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 6b65602cd0..0c9fe6805c 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,4 +1,11 @@ -import { addTelemetryDebug, elapsed, ExperimentalFeature, isExperimentalFeatureEnabled, noop, ONE_MINUTE } from '@datadog/browser-core' +import { + addTelemetryDebug, + elapsed, + ExperimentalFeature, + isExperimentalFeatureEnabled, + noop, + ONE_MINUTE, +} from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' import { RumPerformanceEntryType, supportPerformanceTimingEvent } from '../../../browser/performanceObservable' import type { RumFirstInputTiming, RumPerformanceEventTiming } from '../../../browser/performanceObservable' @@ -79,7 +86,7 @@ export function trackInteractionToNextPaint( }) } } else { - if(isInpEnabled) { + if (isInpEnabled) { addTelemetryDebug('INP target is null or not an element node', { hasTarget: !!inpTarget, targetIsConnected: inpTarget ? inpTarget.isConnected : null, From 518f9c64bd3e2555b11d32ffd4eb86e05a2455ad Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 29 Jul 2024 16:24:47 +0200 Subject: [PATCH 05/37] Rename ff --- packages/core/src/tools/experimentalFeatures.ts | 2 +- .../src/domain/view/viewMetrics/trackInteractionToNextPaint.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/tools/experimentalFeatures.ts b/packages/core/src/tools/experimentalFeatures.ts index c009e5aadb..7ffa745ea5 100644 --- a/packages/core/src/tools/experimentalFeatures.ts +++ b/packages/core/src/tools/experimentalFeatures.ts @@ -19,7 +19,7 @@ export enum ExperimentalFeature { TOLERANT_RESOURCE_TIMINGS = 'tolerant_resource_timings', REMOTE_CONFIGURATION = 'remote_configuration', UPDATE_VIEW_NAME = 'update_view_name', - WEB_VITALS_INP = 'web_vitals_inp', + NULL_INP_TELEMETRY = 'null_inp_telemetry', } const enabledExperimentalFeatures: Set = new Set() diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 0c9fe6805c..3c2af2af2b 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -75,7 +75,7 @@ export function trackInteractionToNextPaint( const inpTarget = newInteraction.target interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) - const isInpEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.WEB_VITALS_INP) + const isInpEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY) if (inpTarget && isElementNode(inpTarget)) { interactionToNextPaintTargetSelector = getSelectorFromElement(inpTarget, configuration.actionNameAttribute) From d6e95750a3225cf811da2d1667afff8f1b570eef Mon Sep 17 00:00:00 2001 From: cy-moi Date: Tue, 30 Jul 2024 10:23:39 +0200 Subject: [PATCH 06/37] Rename --- .../domain/view/viewMetrics/trackInteractionToNextPaint.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 3c2af2af2b..7f128a69dc 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -75,18 +75,18 @@ export function trackInteractionToNextPaint( const inpTarget = newInteraction.target interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) - const isInpEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY) + const isTelEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY) if (inpTarget && isElementNode(inpTarget)) { interactionToNextPaintTargetSelector = getSelectorFromElement(inpTarget, configuration.actionNameAttribute) - if (!interactionToNextPaintTargetSelector && isInpEnabled) { + if (!interactionToNextPaintTargetSelector && isTelEnabled) { addTelemetryDebug('INP target selector is null', { targetIsConnected: inpTarget.isConnected, inp: newInteraction.duration, }) } } else { - if (isInpEnabled) { + if (isTelEnabled) { addTelemetryDebug('INP target is null or not an element node', { hasTarget: !!inpTarget, targetIsConnected: inpTarget ? inpTarget.isConnected : null, From 784a92fd92ad379740f92a5624b5ce399dbe3dbd Mon Sep 17 00:00:00 2001 From: cy-moi Date: Tue, 30 Jul 2024 10:28:50 +0200 Subject: [PATCH 07/37] Simplify and collect isElementNode --- .../trackInteractionToNextPaint.ts | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 7f128a69dc..40b3d9cc53 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -75,27 +75,20 @@ export function trackInteractionToNextPaint( const inpTarget = newInteraction.target interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) - const isTelEnabled = isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY) if (inpTarget && isElementNode(inpTarget)) { interactionToNextPaintTargetSelector = getSelectorFromElement(inpTarget, configuration.actionNameAttribute) - if (!interactionToNextPaintTargetSelector && isTelEnabled) { - addTelemetryDebug('INP target selector is null', { - targetIsConnected: inpTarget.isConnected, - inp: newInteraction.duration, - }) - } } else { - if (isTelEnabled) { - addTelemetryDebug('INP target is null or not an element node', { - hasTarget: !!inpTarget, - targetIsConnected: inpTarget ? inpTarget.isConnected : null, - inp: newInteraction.duration, - }) - } - interactionToNextPaintTargetSelector = undefined } + if (!interactionToNextPaintTargetSelector && isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { + addTelemetryDebug('Fail to get INP target selector', { + hasTarget: !!inpTarget, + targetIsConnected: inpTarget ? inpTarget.isConnected : undefined, + targetIsElementNode: inpTarget ? isElementNode(inpTarget) : undefined, + inp: newInteraction.duration + }) + } } }) From 32dfdcf22ae7dafa8fb8601b629c432b2d48677e Mon Sep 17 00:00:00 2001 From: cy-moi Date: Tue, 30 Jul 2024 10:33:36 +0200 Subject: [PATCH 08/37] Format --- .../viewMetrics/trackInteractionToNextPaint.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 40b3d9cc53..6d0009fcd3 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -81,13 +81,16 @@ export function trackInteractionToNextPaint( } else { interactionToNextPaintTargetSelector = undefined } - if (!interactionToNextPaintTargetSelector && isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { - addTelemetryDebug('Fail to get INP target selector', { - hasTarget: !!inpTarget, - targetIsConnected: inpTarget ? inpTarget.isConnected : undefined, - targetIsElementNode: inpTarget ? isElementNode(inpTarget) : undefined, - inp: newInteraction.duration - }) + if ( + !interactionToNextPaintTargetSelector && + isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY) + ) { + addTelemetryDebug('Fail to get INP target selector', { + hasTarget: !!inpTarget, + targetIsConnected: inpTarget ? inpTarget.isConnected : undefined, + targetIsElementNode: inpTarget ? isElementNode(inpTarget) : undefined, + inp: newInteraction.duration, + }) } } }) From c98fd4be9ae7c5e3514f4d76f62355b999d33aeb Mon Sep 17 00:00:00 2001 From: cy-moi Date: Tue, 20 Aug 2024 16:08:30 +0200 Subject: [PATCH 09/37] Add selector timestamp implementation and telemetry --- .../src/domain/action/trackClickActions.ts | 17 +++++++++++++++++ .../viewMetrics/trackInteractionToNextPaint.ts | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index e6d8553c70..c4718e34d9 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -11,6 +11,9 @@ import { ONE_SECOND, elapsed, createValueHistory, + isExperimentalFeatureEnabled, + ExperimentalFeature, + addTelemetryDebug, } from '@datadog/browser-core' import type { FrustrationType } from '../../rawRumEvent.types' import { ActionType } from '../../rawRumEvent.types' @@ -61,6 +64,7 @@ type ClickActionIdHistory = ValueHistory // Maximum duration for click actions export const CLICK_ACTION_MAX_DURATION = 10 * ONE_SECOND export const ACTION_CONTEXT_TIME_OUT_DELAY = 5 * ONE_MINUTE // arbitrary +export const interactionSelectorMap = new Map() // key is timestamp export function trackClickActions( lifeCycle: LifeCycle, @@ -201,6 +205,19 @@ function startClickAction( CLICK_ACTION_MAX_DURATION ) + const selector = clickActionBase.target?.selector + + // save selector in InteractionTargetMap + if (isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { + if (!selector) { + addTelemetryDebug('Fail to get selector from element', { + hasTarget: !!clickActionBase.target, + timeStamp: startEvent.timeStamp, + }) + } + interactionSelectorMap.set(startEvent.timeStamp, selector) + } + const viewEndedSubscription = lifeCycle.subscribe(LifeCycleEventType.VIEW_ENDED, ({ endClocks }) => { click.stop(endClocks.timeStamp) }) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 6d0009fcd3..fd8424afb4 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -15,6 +15,7 @@ import { ViewLoadingType } from '../../../rawRumEvent.types' import { getSelectorFromElement } from '../../getSelectorFromElement' import { isElementNode } from '../../../browser/htmlDomUtils' import type { RumConfiguration } from '../../configuration' +import { interactionSelectorMap } from '../../action/trackClickActions' import { getInteractionCount, initInteractionCountPolyfill } from './interactionCountPolyfill' // Arbitrary value to prevent unnecessary memory usage on views with lots of interactions. @@ -85,11 +86,15 @@ export function trackInteractionToNextPaint( !interactionToNextPaintTargetSelector && isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY) ) { + if (interactionSelectorMap.has(newInteraction.startTime)) { + interactionToNextPaintTargetSelector = interactionSelectorMap.get(newInteraction.startTime) + } addTelemetryDebug('Fail to get INP target selector', { hasTarget: !!inpTarget, targetIsConnected: inpTarget ? inpTarget.isConnected : undefined, targetIsElementNode: inpTarget ? isElementNode(inpTarget) : undefined, inp: newInteraction.duration, + isFoundInMap: !!interactionToNextPaintTargetSelector, }) } } From 48282ce2c43279e417e0b27ca4204d9f46a09a87 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Thu, 22 Aug 2024 16:14:33 +0200 Subject: [PATCH 10/37] test in processPointerDown --- packages/rum-core/src/domain/action/trackClickActions.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index c4718e34d9..af66cae1bb 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -241,13 +241,18 @@ function computeClickActionBase( configuration: RumConfiguration ): ClickActionBase { const rect = event.target.getBoundingClientRect() + const selector = getSelectorFromElement(event.target, configuration.actionNameAttribute) + + if (isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { + interactionSelectorMap.set(event.timeStamp, selector) + } return { type: ActionType.CLICK, target: { width: Math.round(rect.width), height: Math.round(rect.height), - selector: getSelectorFromElement(event.target, configuration.actionNameAttribute), + selector, }, position: { // Use clientX and Y because for SVG element offsetX and Y are relatives to the element From 09b0bea67e54ecf5f8983438c89b8a36d3ebaf15 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 23 Aug 2024 13:05:41 +0200 Subject: [PATCH 11/37] Test with both pointerup and pointerdown timestamp --- .../rum-core/src/domain/action/trackClickActions.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index af66cae1bb..0472880967 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -205,17 +205,10 @@ function startClickAction( CLICK_ACTION_MAX_DURATION ) - const selector = clickActionBase.target?.selector - - // save selector in InteractionTargetMap if (isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { - if (!selector) { - addTelemetryDebug('Fail to get selector from element', { - hasTarget: !!clickActionBase.target, - timeStamp: startEvent.timeStamp, - }) + if (clickActionBase.target) { + interactionSelectorMap.set(startEvent.timeStamp, clickActionBase.target?.selector) } - interactionSelectorMap.set(startEvent.timeStamp, selector) } const viewEndedSubscription = lifeCycle.subscribe(LifeCycleEventType.VIEW_ENDED, ({ endClocks }) => { From 1c99ed5555ea9cd323c1bf2aaafd6571d38e87b7 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 23 Aug 2024 13:09:27 +0200 Subject: [PATCH 12/37] remove unused function --- packages/rum-core/src/domain/action/trackClickActions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 0472880967..fd8d72eab5 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -13,7 +13,6 @@ import { createValueHistory, isExperimentalFeatureEnabled, ExperimentalFeature, - addTelemetryDebug, } from '@datadog/browser-core' import type { FrustrationType } from '../../rawRumEvent.types' import { ActionType } from '../../rawRumEvent.types' From 7d8b51434a11b7426cbd1950ee076ac1d593d6b4 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 26 Aug 2024 13:30:38 +0200 Subject: [PATCH 13/37] remove testing --- packages/rum-core/src/domain/action/trackClickActions.ts | 6 ------ .../domain/view/viewMetrics/trackInteractionToNextPaint.ts | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index fd8d72eab5..655c01f3b8 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -204,12 +204,6 @@ function startClickAction( CLICK_ACTION_MAX_DURATION ) - if (isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { - if (clickActionBase.target) { - interactionSelectorMap.set(startEvent.timeStamp, clickActionBase.target?.selector) - } - } - const viewEndedSubscription = lifeCycle.subscribe(LifeCycleEventType.VIEW_ENDED, ({ endClocks }) => { click.stop(endClocks.timeStamp) }) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index fd8424afb4..022e92813c 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -88,6 +88,7 @@ export function trackInteractionToNextPaint( ) { if (interactionSelectorMap.has(newInteraction.startTime)) { interactionToNextPaintTargetSelector = interactionSelectorMap.get(newInteraction.startTime) + interactionSelectorMap.delete(newInteraction.startTime) } addTelemetryDebug('Fail to get INP target selector', { hasTarget: !!inpTarget, From afa3ed99e706637b2132b74b313bbf3f39854f3f Mon Sep 17 00:00:00 2001 From: cy-moi Date: Thu, 29 Aug 2024 17:41:25 +0200 Subject: [PATCH 14/37] Format --- .../view/viewMetrics/trackInteractionToNextPaint.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 22f2863443..de1cfcb0a9 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,4 +1,11 @@ -import { addTelemetryDebug, elapsed, ExperimentalFeature, isExperimentalFeatureEnabled, noop, ONE_MINUTE } from '@datadog/browser-core' +import { + addTelemetryDebug, + elapsed, + ExperimentalFeature, + isExperimentalFeatureEnabled, + noop, + ONE_MINUTE, +} from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' import { RumPerformanceEntryType, supportPerformanceTimingEvent } from '../../../browser/performanceObservable' import type { RumFirstInputTiming, RumPerformanceEventTiming } from '../../../browser/performanceObservable' From add9d1a2d6bcbe954df2992cefc8f449fc939f9b Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 30 Aug 2024 11:07:36 +0200 Subject: [PATCH 15/37] Add map clearing in view ended --- packages/rum/src/domain/segmentCollection/segmentCollection.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/rum/src/domain/segmentCollection/segmentCollection.ts b/packages/rum/src/domain/segmentCollection/segmentCollection.ts index 2098d8866c..7db9ee81f4 100644 --- a/packages/rum/src/domain/segmentCollection/segmentCollection.ts +++ b/packages/rum/src/domain/segmentCollection/segmentCollection.ts @@ -6,6 +6,7 @@ import type { BrowserRecord, CreationReason, SegmentContext } from '../../types' import { buildReplayPayload } from './buildReplayPayload' import type { FlushReason, Segment } from './segment' import { createSegment } from './segment' +import { interactionSelectorMap } from 'packages/rum-core/src/domain/action/trackClickActions' export const SEGMENT_DURATION_LIMIT = 30 * ONE_SECOND /** @@ -87,6 +88,7 @@ export function doStartSegmentCollection( const { unsubscribe: unsubscribeViewCreated } = lifeCycle.subscribe(LifeCycleEventType.VIEW_CREATED, () => { flushSegment('view_change') + interactionSelectorMap.clear() }) const { unsubscribe: unsubscribePageExited } = lifeCycle.subscribe( From 92daf77b9ae48cc9e846fe330ad77abbc8d903a4 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 30 Aug 2024 11:16:17 +0200 Subject: [PATCH 16/37] format --- packages/rum-core/src/index.ts | 1 + packages/rum/src/domain/segmentCollection/segmentCollection.ts | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rum-core/src/index.ts b/packages/rum-core/src/index.ts index 1292120b31..47201775d3 100644 --- a/packages/rum-core/src/index.ts +++ b/packages/rum-core/src/index.ts @@ -39,3 +39,4 @@ export { isLongDataUrl, sanitizeDataUrl, MAX_ATTRIBUTE_VALUE_CHAR_LENGTH } from export * from './domain/privacy' export { SessionReplayState } from './domain/rumSessionManager' export type { RumPlugin } from './domain/plugins' +export { interactionSelectorMap } from './domain/action/trackClickActions' diff --git a/packages/rum/src/domain/segmentCollection/segmentCollection.ts b/packages/rum/src/domain/segmentCollection/segmentCollection.ts index 7db9ee81f4..a3d517a6ba 100644 --- a/packages/rum/src/domain/segmentCollection/segmentCollection.ts +++ b/packages/rum/src/domain/segmentCollection/segmentCollection.ts @@ -1,12 +1,11 @@ import type { DeflateEncoder, HttpRequest, TimeoutId } from '@datadog/browser-core' import { isPageExitReason, ONE_SECOND, clearTimeout, setTimeout } from '@datadog/browser-core' import type { LifeCycle, ViewContexts, RumSessionManager, RumConfiguration } from '@datadog/browser-rum-core' -import { LifeCycleEventType } from '@datadog/browser-rum-core' +import { LifeCycleEventType, interactionSelectorMap } from '@datadog/browser-rum-core' import type { BrowserRecord, CreationReason, SegmentContext } from '../../types' import { buildReplayPayload } from './buildReplayPayload' import type { FlushReason, Segment } from './segment' import { createSegment } from './segment' -import { interactionSelectorMap } from 'packages/rum-core/src/domain/action/trackClickActions' export const SEGMENT_DURATION_LIMIT = 30 * ONE_SECOND /** From 33ecfdaa74f64d54c38abb1bc7f69cc589a5a7da Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 9 Sep 2024 13:00:05 +0200 Subject: [PATCH 17/37] Clear the map in perf timing unsubscribe --- .../domain/view/viewMetrics/trackInteractionToNextPaint.ts | 5 ++++- .../rum/src/domain/segmentCollection/segmentCollection.ts | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index de1cfcb0a9..8cbd320059 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -124,7 +124,10 @@ export function trackInteractionToNextPaint( viewEnd = viewEndTime stopViewInteractionCount() }, - stop, + stop: () => { + stop() + interactionSelectorMap.clear() + }, } } diff --git a/packages/rum/src/domain/segmentCollection/segmentCollection.ts b/packages/rum/src/domain/segmentCollection/segmentCollection.ts index a3d517a6ba..2098d8866c 100644 --- a/packages/rum/src/domain/segmentCollection/segmentCollection.ts +++ b/packages/rum/src/domain/segmentCollection/segmentCollection.ts @@ -1,7 +1,7 @@ import type { DeflateEncoder, HttpRequest, TimeoutId } from '@datadog/browser-core' import { isPageExitReason, ONE_SECOND, clearTimeout, setTimeout } from '@datadog/browser-core' import type { LifeCycle, ViewContexts, RumSessionManager, RumConfiguration } from '@datadog/browser-rum-core' -import { LifeCycleEventType, interactionSelectorMap } from '@datadog/browser-rum-core' +import { LifeCycleEventType } from '@datadog/browser-rum-core' import type { BrowserRecord, CreationReason, SegmentContext } from '../../types' import { buildReplayPayload } from './buildReplayPayload' import type { FlushReason, Segment } from './segment' @@ -87,7 +87,6 @@ export function doStartSegmentCollection( const { unsubscribe: unsubscribeViewCreated } = lifeCycle.subscribe(LifeCycleEventType.VIEW_CREATED, () => { flushSegment('view_change') - interactionSelectorMap.clear() }) const { unsubscribe: unsubscribePageExited } = lifeCycle.subscribe( From d6a41d05e9c32b1f20bb31f952297d6d299ae5f2 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Wed, 11 Sep 2024 11:16:47 +0200 Subject: [PATCH 18/37] Add pointerUp selector collect and clear outdated entries --- packages/rum-core/src/domain/action/trackClickActions.ts | 7 +++++++ .../view/viewMetrics/trackInteractionToNextPaint.ts | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 655c01f3b8..26651cbf11 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -179,6 +179,13 @@ function startClickAction( const click = newClick(lifeCycle, history, getUserActivity, clickActionBase, startEvent) appendClickToClickChain(click) + if (clickActionBase.target && isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { + const { selector } = clickActionBase.target + if (selector) { + interactionSelectorMap.set(startEvent.timeStamp, selector) + } + } + const { stop: stopWaitPageActivityEnd } = waitPageActivityEnd( lifeCycle, domMutationObservable, diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 8cbd320059..0381f7fd44 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,9 +1,11 @@ import { addTelemetryDebug, + dateNow, elapsed, ExperimentalFeature, isExperimentalFeatureEnabled, noop, + ONE_HOUR, ONE_MINUTE, } from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' @@ -126,7 +128,11 @@ export function trackInteractionToNextPaint( }, stop: () => { stop() - interactionSelectorMap.clear() + interactionSelectorMap.forEach((_, key) => { + if (dateNow() - key > ONE_HOUR) { + interactionSelectorMap.delete(key) + } + }) }, } } From 62c4f63cce838dd7a0b8c025e3e1ea41db043a0b Mon Sep 17 00:00:00 2001 From: cy-moi Date: Wed, 11 Sep 2024 16:15:26 +0200 Subject: [PATCH 19/37] Change one hour to one day --- .../domain/view/viewMetrics/trackInteractionToNextPaint.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 0381f7fd44..2ff0ddb244 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -5,7 +5,7 @@ import { ExperimentalFeature, isExperimentalFeatureEnabled, noop, - ONE_HOUR, + ONE_DAY, ONE_MINUTE, } from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' @@ -129,7 +129,7 @@ export function trackInteractionToNextPaint( stop: () => { stop() interactionSelectorMap.forEach((_, key) => { - if (dateNow() - key > ONE_HOUR) { + if (dateNow() - key > ONE_DAY) { interactionSelectorMap.delete(key) } }) From 74268f8cdafbd06aafc7235d6406171a667bc622 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 13 Sep 2024 14:53:07 +0200 Subject: [PATCH 20/37] Fix bug in comparing time --- .../src/domain/view/viewMetrics/trackInteractionToNextPaint.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 2ff0ddb244..94fb627810 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -6,6 +6,7 @@ import { isExperimentalFeatureEnabled, noop, ONE_DAY, + ONE_HOUR, ONE_MINUTE, } from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' @@ -129,7 +130,7 @@ export function trackInteractionToNextPaint( stop: () => { stop() interactionSelectorMap.forEach((_, key) => { - if (dateNow() - key > ONE_DAY) { + if (key > ONE_HOUR) { interactionSelectorMap.delete(key) } }) From 0b6e4a09ff1bf0589e096adb6affd2ae0b9b5ad2 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 13 Sep 2024 15:00:08 +0200 Subject: [PATCH 21/37] Remove unused import --- .../src/domain/view/viewMetrics/trackInteractionToNextPaint.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 94fb627810..3ceac4ca26 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,11 +1,9 @@ import { addTelemetryDebug, - dateNow, elapsed, ExperimentalFeature, isExperimentalFeatureEnabled, noop, - ONE_DAY, ONE_HOUR, ONE_MINUTE, } from '@datadog/browser-core' From 4ae666f728f20903e3e6ccc6fb153371414bcac9 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 16 Sep 2024 13:32:02 +0200 Subject: [PATCH 22/37] Clear the map at 10 seconds --- .../viewMetrics/trackInteractionToNextPaint.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 3ceac4ca26..cffbc10653 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -4,8 +4,8 @@ import { ExperimentalFeature, isExperimentalFeatureEnabled, noop, - ONE_HOUR, ONE_MINUTE, + ONE_SECOND, } from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' import { RumPerformanceEntryType, supportPerformanceTimingEvent } from '../../../browser/performanceObservable' @@ -102,6 +102,11 @@ export function trackInteractionToNextPaint( isFoundInMap: !!interactionToNextPaintTargetSelector, }) } + interactionSelectorMap.forEach((_, key) => { + if (key > 10 * ONE_SECOND) { + interactionSelectorMap.delete(key) + } + }) } }) @@ -125,14 +130,7 @@ export function trackInteractionToNextPaint( viewEnd = viewEndTime stopViewInteractionCount() }, - stop: () => { - stop() - interactionSelectorMap.forEach((_, key) => { - if (key > ONE_HOUR) { - interactionSelectorMap.delete(key) - } - }) - }, + stop, } } From 6afb5d529d975b7e24a6a0563a55f82ab728e384 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Thu, 19 Sep 2024 14:31:44 +0200 Subject: [PATCH 23/37] Remove telemetry after experiments --- .../view/viewMetrics/trackInteractionToNextPaint.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index cffbc10653..11ffae493b 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,5 +1,4 @@ import { - addTelemetryDebug, elapsed, ExperimentalFeature, isExperimentalFeatureEnabled, @@ -74,7 +73,6 @@ export function trackInteractionToNextPaint( const newInteraction = longestInteractions.estimateP98Interaction() if (newInteraction && newInteraction.duration !== interactionToNextPaint) { - const inpTarget = newInteraction.target interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) @@ -94,13 +92,6 @@ export function trackInteractionToNextPaint( interactionToNextPaintTargetSelector = interactionSelectorMap.get(newInteraction.startTime) interactionSelectorMap.delete(newInteraction.startTime) } - addTelemetryDebug('Fail to get INP target selector', { - hasTarget: !!inpTarget, - targetIsConnected: inpTarget ? inpTarget.isConnected : undefined, - targetIsElementNode: inpTarget ? isElementNode(inpTarget) : undefined, - inp: newInteraction.duration, - isFoundInMap: !!interactionToNextPaintTargetSelector, - }) } interactionSelectorMap.forEach((_, key) => { if (key > 10 * ONE_SECOND) { From 399fb3acdb3c83277baca9bb48e594eb5ee1df97 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 20 Sep 2024 18:08:24 +0200 Subject: [PATCH 24/37] Fix for comments and remove telemetry feature flag --- .../src/domain/action/listenActionEvents.ts | 3 +- .../domain/action/trackClickActions.spec.ts | 23 +++++++++++++ .../src/domain/action/trackClickActions.ts | 18 ++++++++--- .../trackInteractionToNextPaint.spec.ts | 14 ++++++++ .../trackInteractionToNextPaint.ts | 32 ++++--------------- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/packages/rum-core/src/domain/action/listenActionEvents.ts b/packages/rum-core/src/domain/action/listenActionEvents.ts index 76e75a0f4b..5d3b7ddf1b 100644 --- a/packages/rum-core/src/domain/action/listenActionEvents.ts +++ b/packages/rum-core/src/domain/action/listenActionEvents.ts @@ -1,7 +1,8 @@ import { addEventListener, DOM_EVENT } from '@datadog/browser-core' +import type { RelativeTime } from '@datadog/browser-core' import type { RumConfiguration } from '../configuration' -export type MouseEventOnElement = PointerEvent & { target: Element } +export type MouseEventOnElement = PointerEvent & { target: Element; timeStamp: RelativeTime } export interface UserActivity { selection: boolean diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index 436f244708..a65911ceea 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -425,15 +425,37 @@ describe('trackClickActions', () => { }) }) + describe('interactionSelectorMap', () => { + it('pointer down is added to the map', () => { + startClickActionsTracking() + const setInteractionMapSpy = spyOn(Map.prototype, 'set').and.callThrough() + emulateClick({ activity: { on: 'pointerdown' } }) + expect(setInteractionMapSpy).toHaveBeenCalled() + }) + + it('clear outdated entries when pointer up', () => { + startClickActionsTracking() + const deleteInteractionMapSpy = spyOn(Map.prototype, 'delete').and.callThrough() + + emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 0 } }) + clock.tick(EXPIRE_DELAY) + emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 10 } }) + + expect(deleteInteractionMapSpy).toHaveBeenCalled() + }) + }) + function emulateClick({ target = button, activity, + eventProperty, }: { target?: HTMLElement activity?: { delay?: number on?: 'pointerup' | 'click' | 'pointerdown' } + eventProperty?: { [key: string]: any } } = {}) { const targetPosition = target.getBoundingClientRect() const offsetX = targetPosition.width / 2 @@ -446,6 +468,7 @@ describe('trackClickActions', () => { offsetY, timeStamp: timeStampNow(), isPrimary: true, + ...eventProperty, } target.dispatchEvent(createNewEvent('pointerdown', eventProperties)) emulateActivityIfNeeded('pointerdown') diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 26651cbf11..58b55dc324 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -13,6 +13,7 @@ import { createValueHistory, isExperimentalFeatureEnabled, ExperimentalFeature, + relativeNow, } from '@datadog/browser-core' import type { FrustrationType } from '../../rawRumEvent.types' import { ActionType } from '../../rawRumEvent.types' @@ -63,7 +64,15 @@ type ClickActionIdHistory = ValueHistory // Maximum duration for click actions export const CLICK_ACTION_MAX_DURATION = 10 * ONE_SECOND export const ACTION_CONTEXT_TIME_OUT_DELAY = 5 * ONE_MINUTE // arbitrary -export const interactionSelectorMap = new Map() // key is timestamp +export const interactionSelectorMap = new Map() // key is relative time + +export const deleteOutdatedInteractionSelectors = () => { + interactionSelectorMap.forEach((_, key) => { + if (relativeNow() - key > 10 * ONE_SECOND) { + interactionSelectorMap.delete(key) + } + }) +} export function trackClickActions( lifeCycle: LifeCycle, @@ -182,7 +191,9 @@ function startClickAction( if (clickActionBase.target && isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { const { selector } = clickActionBase.target if (selector) { + // save the selector for the interaction to next paint interactionSelectorMap.set(startEvent.timeStamp, selector) + deleteOutdatedInteractionSelectors() } } @@ -236,9 +247,8 @@ function computeClickActionBase( const rect = event.target.getBoundingClientRect() const selector = getSelectorFromElement(event.target, configuration.actionNameAttribute) - if (isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { - interactionSelectorMap.set(event.timeStamp, selector) - } + interactionSelectorMap.set(event.timeStamp, selector) + deleteOutdatedInteractionSelectors() return { type: ActionType.CLICK, diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts index 0dc2212d96..6bf8a2db5a 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts @@ -240,6 +240,20 @@ describe('trackInteractionToNextPaint', () => { expect(getInteractionToNextPaint()?.targetSelector).toEqual('#bar') }) + + it('should check interactionSelectorMap for entries', () => { + startINPTracking() + const getInteractionMapSpy = spyOn(Map.prototype, 'get').and.callThrough() + const deleteInteractionMapSpy = spyOn(Map.prototype, 'delete').and.callThrough() + + newInteraction(lifeCycle, { + interactionId: 1, + duration: 10 as Duration, + target: appendElement(''), + }) + expect(getInteractionMapSpy).toHaveBeenCalled() + expect(deleteInteractionMapSpy).toHaveBeenCalled() + }) }) }) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 11ffae493b..3918aafae8 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -1,11 +1,4 @@ -import { - elapsed, - ExperimentalFeature, - isExperimentalFeatureEnabled, - noop, - ONE_MINUTE, - ONE_SECOND, -} from '@datadog/browser-core' +import { elapsed, noop, ONE_MINUTE } from '@datadog/browser-core' import type { Duration, RelativeTime } from '@datadog/browser-core' import { RumPerformanceEntryType, supportPerformanceTimingEvent } from '../../../browser/performanceObservable' import type { RumFirstInputTiming, RumPerformanceEventTiming } from '../../../browser/performanceObservable' @@ -77,27 +70,14 @@ export function trackInteractionToNextPaint( interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) if (newInteraction.target && isElementNode(newInteraction.target)) { - interactionToNextPaintTargetSelector = getSelectorFromElement( - newInteraction.target, - configuration.actionNameAttribute - ) + interactionToNextPaintTargetSelector = + interactionSelectorMap.get(newInteraction.startTime) || + getSelectorFromElement(newInteraction.target, configuration.actionNameAttribute) + + interactionSelectorMap.delete(newInteraction.startTime) } else { interactionToNextPaintTargetSelector = undefined } - if ( - !interactionToNextPaintTargetSelector && - isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY) - ) { - if (interactionSelectorMap.has(newInteraction.startTime)) { - interactionToNextPaintTargetSelector = interactionSelectorMap.get(newInteraction.startTime) - interactionSelectorMap.delete(newInteraction.startTime) - } - } - interactionSelectorMap.forEach((_, key) => { - if (key > 10 * ONE_SECOND) { - interactionSelectorMap.delete(key) - } - }) } }) From a64b276ece35f560b07d657f634dbf9120c4dda4 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Fri, 20 Sep 2024 18:24:53 +0200 Subject: [PATCH 25/37] Fix type for mouse event --- packages/core/test/emulate/createNewEvent.ts | 6 ++---- packages/rum-core/src/domain/action/listenActionEvents.ts | 6 +++++- packages/rum-core/src/index.ts | 1 + packages/rum-core/test/createFakeClick.ts | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/core/test/emulate/createNewEvent.ts b/packages/core/test/emulate/createNewEvent.ts index 4d9d298802..6dd20e687e 100644 --- a/packages/core/test/emulate/createNewEvent.ts +++ b/packages/core/test/emulate/createNewEvent.ts @@ -1,11 +1,9 @@ +import type { MouseEventOnElement } from '@datadog/browser-rum-core' import type { TrustableEvent } from '../../src' import { objectEntries } from '../../src' export function createNewEvent(eventName: 'click', properties?: Partial): MouseEvent -export function createNewEvent( - eventName: 'pointerup', - properties?: Partial -): PointerEvent & { target: Element } +export function createNewEvent(eventName: 'pointerup', properties?: Partial): MouseEventOnElement export function createNewEvent(eventName: 'message', properties?: Partial): MessageEvent export function createNewEvent( eventName: 'securitypolicyviolation', diff --git a/packages/rum-core/src/domain/action/listenActionEvents.ts b/packages/rum-core/src/domain/action/listenActionEvents.ts index 5d3b7ddf1b..a04a8c278d 100644 --- a/packages/rum-core/src/domain/action/listenActionEvents.ts +++ b/packages/rum-core/src/domain/action/listenActionEvents.ts @@ -2,7 +2,11 @@ import { addEventListener, DOM_EVENT } from '@datadog/browser-core' import type { RelativeTime } from '@datadog/browser-core' import type { RumConfiguration } from '../configuration' -export type MouseEventOnElement = PointerEvent & { target: Element; timeStamp: RelativeTime } +export type ExtraPointerEventFields = { + target: Element + timeStamp: RelativeTime +} +export type MouseEventOnElement = PointerEvent & ExtraPointerEventFields export interface UserActivity { selection: boolean diff --git a/packages/rum-core/src/index.ts b/packages/rum-core/src/index.ts index 47201775d3..ecf03dde67 100644 --- a/packages/rum-core/src/index.ts +++ b/packages/rum-core/src/index.ts @@ -40,3 +40,4 @@ export * from './domain/privacy' export { SessionReplayState } from './domain/rumSessionManager' export type { RumPlugin } from './domain/plugins' export { interactionSelectorMap } from './domain/action/trackClickActions' +export type { MouseEventOnElement } from './domain/action/listenActionEvents' diff --git a/packages/rum-core/test/createFakeClick.ts b/packages/rum-core/test/createFakeClick.ts index 53c2da67d2..56dee4c14c 100644 --- a/packages/rum-core/test/createFakeClick.ts +++ b/packages/rum-core/test/createFakeClick.ts @@ -1,7 +1,7 @@ import { clocksNow, Observable, timeStampNow } from '@datadog/browser-core' import { createNewEvent } from '@datadog/browser-core/test' import type { Click } from '../src/domain/action/trackClickActions' -import type { UserActivity } from '../src/domain/action/listenActionEvents' +import type { MouseEventOnElement, UserActivity } from '../src/domain/action/listenActionEvents' export type FakeClick = Readonly> @@ -14,7 +14,7 @@ export function createFakeClick({ hasError?: boolean hasPageActivity?: boolean userActivity?: Partial - event?: Partial + event?: Partial } = {}) { const stopObservable = new Observable() let isStopped = false From e8356a87189692835a28e73ec17da16f3ea503a6 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 23 Sep 2024 14:33:41 +0200 Subject: [PATCH 26/37] Add trackClickAction test coverage --- .../src/domain/action/trackClickActions.spec.ts | 11 +++++++++-- .../rum-core/src/domain/action/trackClickActions.ts | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index a65911ceea..23c4305680 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -426,14 +426,21 @@ describe('trackClickActions', () => { }) describe('interactionSelectorMap', () => { - it('pointer down is added to the map', () => { + it('should add pointer down to the map', () => { startClickActionsTracking() const setInteractionMapSpy = spyOn(Map.prototype, 'set').and.callThrough() emulateClick({ activity: { on: 'pointerdown' } }) expect(setInteractionMapSpy).toHaveBeenCalled() }) - it('clear outdated entries when pointer up', () => { + it('should add pointerup to the map', () => { + startClickActionsTracking() + const setInteractionMapSpy = spyOn(Map.prototype, 'set').and.callThrough() + emulateClick({ activity: { on: 'pointerup' } }) + expect(setInteractionMapSpy).toHaveBeenCalled() + }) + + it('should clear outdated entries when pointer up', () => { startClickActionsTracking() const deleteInteractionMapSpy = spyOn(Map.prototype, 'delete').and.callThrough() diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 58b55dc324..3a5b3b62f9 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -188,7 +188,7 @@ function startClickAction( const click = newClick(lifeCycle, history, getUserActivity, clickActionBase, startEvent) appendClickToClickChain(click) - if (clickActionBase.target && isExperimentalFeatureEnabled(ExperimentalFeature.NULL_INP_TELEMETRY)) { + if (clickActionBase.target) { const { selector } = clickActionBase.target if (selector) { // save the selector for the interaction to next paint From 9ba669120154c23e6dd88806a6e1e164c4c04456 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 23 Sep 2024 14:39:02 +0200 Subject: [PATCH 27/37] Remove ff NULL_INP_TELEMETRY --- packages/core/src/tools/experimentalFeatures.ts | 1 - packages/rum-core/src/domain/action/trackClickActions.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/core/src/tools/experimentalFeatures.ts b/packages/core/src/tools/experimentalFeatures.ts index e77a67c2bd..05007e9a3f 100644 --- a/packages/core/src/tools/experimentalFeatures.ts +++ b/packages/core/src/tools/experimentalFeatures.ts @@ -18,7 +18,6 @@ export enum ExperimentalFeature { TOLERANT_RESOURCE_TIMINGS = 'tolerant_resource_timings', REMOTE_CONFIGURATION = 'remote_configuration', UPDATE_VIEW_NAME = 'update_view_name', - NULL_INP_TELEMETRY = 'null_inp_telemetry', LONG_ANIMATION_FRAME = 'long_animation_frame', VIEW_SPECIFIC_CONTEXT = 'view_specific_context', } diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 3a5b3b62f9..880b49d4c9 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -11,8 +11,6 @@ import { ONE_SECOND, elapsed, createValueHistory, - isExperimentalFeatureEnabled, - ExperimentalFeature, relativeNow, } from '@datadog/browser-core' import type { FrustrationType } from '../../rawRumEvent.types' From b2ad82b1f87f384552aab9ee3e90291fd6a313d4 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Wed, 2 Oct 2024 18:30:11 +0200 Subject: [PATCH 28/37] Extract logic to a separate file and fix tests --- .../domain/action/interactionSelectorCache.ts | 23 ++++++++++++++++++ .../domain/action/trackClickActions.spec.ts | 22 ++++++++--------- .../src/domain/action/trackClickActions.ts | 24 ++++--------------- .../trackInteractionToNextPaint.spec.ts | 17 +++++++------ .../trackInteractionToNextPaint.ts | 17 ++++++------- 5 files changed, 55 insertions(+), 48 deletions(-) create mode 100644 packages/rum-core/src/domain/action/interactionSelectorCache.ts diff --git a/packages/rum-core/src/domain/action/interactionSelectorCache.ts b/packages/rum-core/src/domain/action/interactionSelectorCache.ts new file mode 100644 index 0000000000..21cd0e0082 --- /dev/null +++ b/packages/rum-core/src/domain/action/interactionSelectorCache.ts @@ -0,0 +1,23 @@ +import { elapsed, ONE_SECOND, relativeNow } from '@datadog/browser-core' +import type { RelativeTime } from '@datadog/browser-core' + +// Maximum duration for click actions +export const CLICK_ACTION_MAX_DURATION = 10 * ONE_SECOND +const cache = new Map() + +export const interactionSelectorCache = { + interactionSelectors: cache, + get: (relativeTimestamp: RelativeTime) => { + const selector = cache.get(relativeTimestamp) + cache.delete(relativeTimestamp) + return selector + }, + set: (relativeTimestamp: RelativeTime, selector: string) => { + cache.set(relativeTimestamp, selector) + cache.forEach((_, relativeTimestamp) => { + if (elapsed(relativeTimestamp, relativeNow()) > CLICK_ACTION_MAX_DURATION) { + cache.delete(relativeTimestamp) + } + }) + }, +} diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index 23c4305680..b8d33fe966 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -1,4 +1,4 @@ -import type { Context, Duration } from '@datadog/browser-core' +import type { Context, Duration, RelativeTime } from '@datadog/browser-core' import { addDuration, clocksNow, @@ -17,8 +17,9 @@ import { PAGE_ACTIVITY_VALIDATION_DELAY } from '../waitPageActivityEnd' import type { RumConfiguration } from '../configuration' import type { ActionContexts } from './actionCollection' import type { ClickAction } from './trackClickActions' -import { finalizeClicks, CLICK_ACTION_MAX_DURATION, trackClickActions } from './trackClickActions' +import { finalizeClicks, trackClickActions } from './trackClickActions' import { MAX_DURATION_BETWEEN_CLICKS } from './clickChain' +import { interactionSelectorCache, CLICK_ACTION_MAX_DURATION } from './interactionSelectorCache' // Used to wait some time after the creation of an action const BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY = PAGE_ACTIVITY_VALIDATION_DELAY * 0.8 @@ -149,7 +150,6 @@ describe('trackClickActions', () => { clock.tick(BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY) domMutationObservable.notify() lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) - clock.tick(EXPIRE_DELAY) lifeCycle.notify(LifeCycleEventType.RUM_EVENT_COLLECTED, createFakeErrorEvent()) @@ -425,30 +425,28 @@ describe('trackClickActions', () => { }) }) - describe('interactionSelectorMap', () => { + describe('interactionSelectorCache', () => { + const { get: getSelectorFromCache } = interactionSelectorCache it('should add pointer down to the map', () => { startClickActionsTracking() - const setInteractionMapSpy = spyOn(Map.prototype, 'set').and.callThrough() - emulateClick({ activity: { on: 'pointerdown' } }) - expect(setInteractionMapSpy).toHaveBeenCalled() + emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 0 } }) + expect(getSelectorFromCache(0 as RelativeTime)).toBe('#button') }) it('should add pointerup to the map', () => { startClickActionsTracking() - const setInteractionMapSpy = spyOn(Map.prototype, 'set').and.callThrough() - emulateClick({ activity: { on: 'pointerup' } }) - expect(setInteractionMapSpy).toHaveBeenCalled() + emulateClick({ activity: { on: 'pointerup' }, eventProperty: { timeStamp: 0 } }) + expect(getSelectorFromCache(0 as RelativeTime)).toBe('#button') }) it('should clear outdated entries when pointer up', () => { startClickActionsTracking() - const deleteInteractionMapSpy = spyOn(Map.prototype, 'delete').and.callThrough() emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 0 } }) clock.tick(EXPIRE_DELAY) emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 10 } }) - expect(deleteInteractionMapSpy).toHaveBeenCalled() + expect(getSelectorFromCache(0 as RelativeTime)).toBeUndefined() }) }) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 880b49d4c9..0e695c430a 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -8,10 +8,8 @@ import { ONE_MINUTE, generateUUID, clocksNow, - ONE_SECOND, elapsed, createValueHistory, - relativeNow, } from '@datadog/browser-core' import type { FrustrationType } from '../../rawRumEvent.types' import { ActionType } from '../../rawRumEvent.types' @@ -28,6 +26,7 @@ import { getActionNameFromElement } from './getActionNameFromElement' import type { MouseEventOnElement, UserActivity } from './listenActionEvents' import { listenActionEvents } from './listenActionEvents' import { computeFrustration } from './computeFrustration' +import { CLICK_ACTION_MAX_DURATION, interactionSelectorCache } from './interactionSelectorCache' interface ActionCounts { errorCount: number @@ -59,18 +58,7 @@ export interface ActionContexts { type ClickActionIdHistory = ValueHistory -// Maximum duration for click actions -export const CLICK_ACTION_MAX_DURATION = 10 * ONE_SECOND export const ACTION_CONTEXT_TIME_OUT_DELAY = 5 * ONE_MINUTE // arbitrary -export const interactionSelectorMap = new Map() // key is relative time - -export const deleteOutdatedInteractionSelectors = () => { - interactionSelectorMap.forEach((_, key) => { - if (relativeNow() - key > 10 * ONE_SECOND) { - interactionSelectorMap.delete(key) - } - }) -} export function trackClickActions( lifeCycle: LifeCycle, @@ -189,9 +177,7 @@ function startClickAction( if (clickActionBase.target) { const { selector } = clickActionBase.target if (selector) { - // save the selector for the interaction to next paint - interactionSelectorMap.set(startEvent.timeStamp, selector) - deleteOutdatedInteractionSelectors() + interactionSelectorCache.set(startEvent.timeStamp, selector) } } @@ -244,9 +230,9 @@ function computeClickActionBase( ): ClickActionBase { const rect = event.target.getBoundingClientRect() const selector = getSelectorFromElement(event.target, configuration.actionNameAttribute) - - interactionSelectorMap.set(event.timeStamp, selector) - deleteOutdatedInteractionSelectors() + if (selector) { + interactionSelectorCache.set(event.timeStamp, selector) + } return { type: ActionType.CLICK, diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts index 6bf8a2db5a..f15190a557 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts @@ -9,6 +9,7 @@ import type { RumPerformanceEventTiming, } from '../../../browser/performanceObservable' import { ViewLoadingType } from '../../../rawRumEvent.types' +import { interactionSelectorCache } from '../../action/interactionSelectorCache' import { LifeCycle, LifeCycleEventType } from '../../lifeCycle' import { trackInteractionToNextPaint, @@ -241,18 +242,20 @@ describe('trackInteractionToNextPaint', () => { expect(getInteractionToNextPaint()?.targetSelector).toEqual('#bar') }) - it('should check interactionSelectorMap for entries', () => { + it('should check interactionSelectorCache for entries', () => { startINPTracking() - const getInteractionMapSpy = spyOn(Map.prototype, 'get').and.callThrough() - const deleteInteractionMapSpy = spyOn(Map.prototype, 'delete').and.callThrough() + const { set: setSelectorInCache, interactionSelectors } = interactionSelectorCache + setSelectorInCache(10 as RelativeTime, '#foo') newInteraction(lifeCycle, { interactionId: 1, - duration: 10 as Duration, - target: appendElement(''), + duration: 1 as Duration, + startTime: 10 as RelativeTime, + target: undefined, }) - expect(getInteractionMapSpy).toHaveBeenCalled() - expect(deleteInteractionMapSpy).toHaveBeenCalled() + + expect(getInteractionToNextPaint()?.targetSelector).toEqual('#foo') + expect(interactionSelectors.get(10 as RelativeTime)).toBeUndefined() }) }) }) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 3918aafae8..44307e4b62 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -7,8 +7,8 @@ import type { LifeCycle } from '../../lifeCycle' import { ViewLoadingType } from '../../../rawRumEvent.types' import { getSelectorFromElement } from '../../getSelectorFromElement' import { isElementNode } from '../../../browser/htmlDomUtils' +import { interactionSelectorCache } from '../../action/interactionSelectorCache' import type { RumConfiguration } from '../../configuration' -import { interactionSelectorMap } from '../../action/trackClickActions' import { getInteractionCount, initInteractionCountPolyfill } from './interactionCountPolyfill' // Arbitrary value to prevent unnecessary memory usage on views with lots of interactions. @@ -68,15 +68,12 @@ export function trackInteractionToNextPaint( if (newInteraction && newInteraction.duration !== interactionToNextPaint) { interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) - - if (newInteraction.target && isElementNode(newInteraction.target)) { - interactionToNextPaintTargetSelector = - interactionSelectorMap.get(newInteraction.startTime) || - getSelectorFromElement(newInteraction.target, configuration.actionNameAttribute) - - interactionSelectorMap.delete(newInteraction.startTime) - } else { - interactionToNextPaintTargetSelector = undefined + interactionToNextPaintTargetSelector = interactionSelectorCache.get(newInteraction.startTime) + if (!interactionToNextPaintTargetSelector && newInteraction.target && isElementNode(newInteraction.target)) { + interactionToNextPaintTargetSelector = getSelectorFromElement( + newInteraction.target, + configuration.actionNameAttribute + ) } } }) From 309100d17c1ce400ccd0c93a8ca42e9befc6f14c Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 7 Oct 2024 11:02:32 +0200 Subject: [PATCH 29/37] Separate cache object to functions --- .../domain/action/interactionSelectorCache.ts | 47 ++++++++++++------- .../domain/action/trackClickActions.spec.ts | 9 ++-- .../src/domain/action/trackClickActions.ts | 6 +-- .../trackInteractionToNextPaint.spec.ts | 9 ++-- .../trackInteractionToNextPaint.ts | 4 +- 5 files changed, 44 insertions(+), 31 deletions(-) diff --git a/packages/rum-core/src/domain/action/interactionSelectorCache.ts b/packages/rum-core/src/domain/action/interactionSelectorCache.ts index 21cd0e0082..b403247819 100644 --- a/packages/rum-core/src/domain/action/interactionSelectorCache.ts +++ b/packages/rum-core/src/domain/action/interactionSelectorCache.ts @@ -3,21 +3,36 @@ import type { RelativeTime } from '@datadog/browser-core' // Maximum duration for click actions export const CLICK_ACTION_MAX_DURATION = 10 * ONE_SECOND -const cache = new Map() +export const interactionSelectorCache = new Map() -export const interactionSelectorCache = { - interactionSelectors: cache, - get: (relativeTimestamp: RelativeTime) => { - const selector = cache.get(relativeTimestamp) - cache.delete(relativeTimestamp) - return selector - }, - set: (relativeTimestamp: RelativeTime, selector: string) => { - cache.set(relativeTimestamp, selector) - cache.forEach((_, relativeTimestamp) => { - if (elapsed(relativeTimestamp, relativeNow()) > CLICK_ACTION_MAX_DURATION) { - cache.delete(relativeTimestamp) - } - }) - }, +export const getInteractionSelector = (relativeTimestamp: RelativeTime) => { + const selector = interactionSelectorCache.get(relativeTimestamp) + interactionSelectorCache.delete(relativeTimestamp) + return selector } + +export const setInteractionSelector = (relativeTimestamp: RelativeTime, selector: string) => { + interactionSelectorCache.set(relativeTimestamp, selector) + interactionSelectorCache.forEach((_, relativeTimestamp) => { + if (elapsed(relativeTimestamp, relativeNow()) > CLICK_ACTION_MAX_DURATION) { + interactionSelectorCache.delete(relativeTimestamp) + } + }) +} + +// export const interactionSelectorCache = { +// interactionSelectors: cache, +// get: (relativeTimestamp: RelativeTime) => { +// const selector = cache.get(relativeTimestamp) +// cache.delete(relativeTimestamp) +// return selector +// }, +// set: (relativeTimestamp: RelativeTime, selector: string) => { +// cache.set(relativeTimestamp, selector) +// cache.forEach((_, relativeTimestamp) => { +// if (elapsed(relativeTimestamp, relativeNow()) > CLICK_ACTION_MAX_DURATION) { +// cache.delete(relativeTimestamp) +// } +// }) +// }, +// } diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index b8d33fe966..cb28c94b56 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -19,7 +19,7 @@ import type { ActionContexts } from './actionCollection' import type { ClickAction } from './trackClickActions' import { finalizeClicks, trackClickActions } from './trackClickActions' import { MAX_DURATION_BETWEEN_CLICKS } from './clickChain' -import { interactionSelectorCache, CLICK_ACTION_MAX_DURATION } from './interactionSelectorCache' +import { getInteractionSelector, CLICK_ACTION_MAX_DURATION } from './interactionSelectorCache' // Used to wait some time after the creation of an action const BEFORE_PAGE_ACTIVITY_VALIDATION_DELAY = PAGE_ACTIVITY_VALIDATION_DELAY * 0.8 @@ -426,17 +426,16 @@ describe('trackClickActions', () => { }) describe('interactionSelectorCache', () => { - const { get: getSelectorFromCache } = interactionSelectorCache it('should add pointer down to the map', () => { startClickActionsTracking() emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 0 } }) - expect(getSelectorFromCache(0 as RelativeTime)).toBe('#button') + expect(getInteractionSelector(0 as RelativeTime)).toBe('#button') }) it('should add pointerup to the map', () => { startClickActionsTracking() emulateClick({ activity: { on: 'pointerup' }, eventProperty: { timeStamp: 0 } }) - expect(getSelectorFromCache(0 as RelativeTime)).toBe('#button') + expect(getInteractionSelector(0 as RelativeTime)).toBe('#button') }) it('should clear outdated entries when pointer up', () => { @@ -446,7 +445,7 @@ describe('trackClickActions', () => { clock.tick(EXPIRE_DELAY) emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 10 } }) - expect(getSelectorFromCache(0 as RelativeTime)).toBeUndefined() + expect(getInteractionSelector(0 as RelativeTime)).toBeUndefined() }) }) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 0e695c430a..b4b343730c 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -26,7 +26,7 @@ import { getActionNameFromElement } from './getActionNameFromElement' import type { MouseEventOnElement, UserActivity } from './listenActionEvents' import { listenActionEvents } from './listenActionEvents' import { computeFrustration } from './computeFrustration' -import { CLICK_ACTION_MAX_DURATION, interactionSelectorCache } from './interactionSelectorCache' +import { CLICK_ACTION_MAX_DURATION, setInteractionSelector } from './interactionSelectorCache' interface ActionCounts { errorCount: number @@ -177,7 +177,7 @@ function startClickAction( if (clickActionBase.target) { const { selector } = clickActionBase.target if (selector) { - interactionSelectorCache.set(startEvent.timeStamp, selector) + setInteractionSelector(startEvent.timeStamp, selector) } } @@ -231,7 +231,7 @@ function computeClickActionBase( const rect = event.target.getBoundingClientRect() const selector = getSelectorFromElement(event.target, configuration.actionNameAttribute) if (selector) { - interactionSelectorCache.set(event.timeStamp, selector) + setInteractionSelector(event.timeStamp, selector) } return { diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts index f15190a557..a2b9546d5f 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts @@ -9,7 +9,7 @@ import type { RumPerformanceEventTiming, } from '../../../browser/performanceObservable' import { ViewLoadingType } from '../../../rawRumEvent.types' -import { interactionSelectorCache } from '../../action/interactionSelectorCache' +import { getInteractionSelector, setInteractionSelector } from '../../action/interactionSelectorCache' import { LifeCycle, LifeCycleEventType } from '../../lifeCycle' import { trackInteractionToNextPaint, @@ -244,18 +244,17 @@ describe('trackInteractionToNextPaint', () => { it('should check interactionSelectorCache for entries', () => { startINPTracking() - const { set: setSelectorInCache, interactionSelectors } = interactionSelectorCache - setSelectorInCache(10 as RelativeTime, '#foo') + setInteractionSelector(1 as RelativeTime, '#foo') newInteraction(lifeCycle, { interactionId: 1, duration: 1 as Duration, - startTime: 10 as RelativeTime, + startTime: 1 as RelativeTime, target: undefined, }) expect(getInteractionToNextPaint()?.targetSelector).toEqual('#foo') - expect(interactionSelectors.get(10 as RelativeTime)).toBeUndefined() + expect(getInteractionSelector(1 as RelativeTime)).toBeUndefined() }) }) }) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts index 44307e4b62..b45f20aa62 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.ts @@ -7,7 +7,7 @@ import type { LifeCycle } from '../../lifeCycle' import { ViewLoadingType } from '../../../rawRumEvent.types' import { getSelectorFromElement } from '../../getSelectorFromElement' import { isElementNode } from '../../../browser/htmlDomUtils' -import { interactionSelectorCache } from '../../action/interactionSelectorCache' +import { getInteractionSelector } from '../../action/interactionSelectorCache' import type { RumConfiguration } from '../../configuration' import { getInteractionCount, initInteractionCountPolyfill } from './interactionCountPolyfill' @@ -68,7 +68,7 @@ export function trackInteractionToNextPaint( if (newInteraction && newInteraction.duration !== interactionToNextPaint) { interactionToNextPaint = newInteraction.duration interactionToNextPaintStartTime = elapsed(viewStart, newInteraction.startTime) - interactionToNextPaintTargetSelector = interactionSelectorCache.get(newInteraction.startTime) + interactionToNextPaintTargetSelector = getInteractionSelector(newInteraction.startTime) if (!interactionToNextPaintTargetSelector && newInteraction.target && isElementNode(newInteraction.target)) { interactionToNextPaintTargetSelector = getSelectorFromElement( newInteraction.target, From e5b88948335b93c23613453a93a41acdcbcc5a15 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 7 Oct 2024 11:08:51 +0200 Subject: [PATCH 30/37] Simplify and avoid verbose --- packages/rum-core/src/domain/action/trackClickActions.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index b4b343730c..7a7eb61ce1 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -174,13 +174,12 @@ function startClickAction( const click = newClick(lifeCycle, history, getUserActivity, clickActionBase, startEvent) appendClickToClickChain(click) - if (clickActionBase.target) { - const { selector } = clickActionBase.target - if (selector) { - setInteractionSelector(startEvent.timeStamp, selector) - } + const selector = clickActionBase?.target?.selector + if (selector) { + setInteractionSelector(startEvent.timeStamp, selector) } + const { stop: stopWaitPageActivityEnd } = waitPageActivityEnd( lifeCycle, domMutationObservable, From bee48e36c9d2bbf98724ed8ca565647654f98f63 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 7 Oct 2024 11:40:14 +0200 Subject: [PATCH 31/37] Remove commented codes --- .../domain/action/interactionSelectorCache.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/packages/rum-core/src/domain/action/interactionSelectorCache.ts b/packages/rum-core/src/domain/action/interactionSelectorCache.ts index b403247819..501dba1a8f 100644 --- a/packages/rum-core/src/domain/action/interactionSelectorCache.ts +++ b/packages/rum-core/src/domain/action/interactionSelectorCache.ts @@ -19,20 +19,3 @@ export const setInteractionSelector = (relativeTimestamp: RelativeTime, selector } }) } - -// export const interactionSelectorCache = { -// interactionSelectors: cache, -// get: (relativeTimestamp: RelativeTime) => { -// const selector = cache.get(relativeTimestamp) -// cache.delete(relativeTimestamp) -// return selector -// }, -// set: (relativeTimestamp: RelativeTime, selector: string) => { -// cache.set(relativeTimestamp, selector) -// cache.forEach((_, relativeTimestamp) => { -// if (elapsed(relativeTimestamp, relativeNow()) > CLICK_ACTION_MAX_DURATION) { -// cache.delete(relativeTimestamp) -// } -// }) -// }, -// } From 9d2469480029b0e239691973cf0cc0ebefcf9029 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 7 Oct 2024 13:43:20 +0200 Subject: [PATCH 32/37] Rename functions to be more precise --- .../rum-core/src/domain/action/interactionSelectorCache.ts | 2 +- packages/rum-core/src/domain/action/trackClickActions.ts | 6 +++--- .../view/viewMetrics/trackInteractionToNextPaint.spec.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/rum-core/src/domain/action/interactionSelectorCache.ts b/packages/rum-core/src/domain/action/interactionSelectorCache.ts index 501dba1a8f..1eb956be5e 100644 --- a/packages/rum-core/src/domain/action/interactionSelectorCache.ts +++ b/packages/rum-core/src/domain/action/interactionSelectorCache.ts @@ -11,7 +11,7 @@ export const getInteractionSelector = (relativeTimestamp: RelativeTime) => { return selector } -export const setInteractionSelector = (relativeTimestamp: RelativeTime, selector: string) => { +export const updateInteractionSelector = (relativeTimestamp: RelativeTime, selector: string) => { interactionSelectorCache.set(relativeTimestamp, selector) interactionSelectorCache.forEach((_, relativeTimestamp) => { if (elapsed(relativeTimestamp, relativeNow()) > CLICK_ACTION_MAX_DURATION) { diff --git a/packages/rum-core/src/domain/action/trackClickActions.ts b/packages/rum-core/src/domain/action/trackClickActions.ts index 297b34419b..fa4a10bc2e 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.ts @@ -26,7 +26,7 @@ import { getActionNameFromElement } from './getActionNameFromElement' import type { MouseEventOnElement, UserActivity } from './listenActionEvents' import { listenActionEvents } from './listenActionEvents' import { computeFrustration } from './computeFrustration' -import { CLICK_ACTION_MAX_DURATION, setInteractionSelector } from './interactionSelectorCache' +import { CLICK_ACTION_MAX_DURATION, updateInteractionSelector } from './interactionSelectorCache' interface ActionCounts { errorCount: number @@ -176,7 +176,7 @@ function startClickAction( const selector = clickActionBase?.target?.selector if (selector) { - setInteractionSelector(startEvent.timeStamp, selector) + updateInteractionSelector(startEvent.timeStamp, selector) } const { stop: stopWaitPageActivityEnd } = waitPageActivityEnd( @@ -229,7 +229,7 @@ function computeClickActionBase( const rect = event.target.getBoundingClientRect() const selector = getSelectorFromElement(event.target, configuration.actionNameAttribute) if (selector) { - setInteractionSelector(event.timeStamp, selector) + updateInteractionSelector(event.timeStamp, selector) } return { diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts index 30fca57ca7..5011af025e 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts @@ -16,7 +16,7 @@ import type { RumPerformanceEventTiming, } from '../../../browser/performanceObservable' import { ViewLoadingType } from '../../../rawRumEvent.types' -import { getInteractionSelector, setInteractionSelector } from '../../action/interactionSelectorCache' +import { getInteractionSelector, updateInteractionSelector } from '../../action/interactionSelectorCache' import { trackInteractionToNextPaint, trackViewInteractionCount, @@ -251,7 +251,7 @@ describe('trackInteractionToNextPaint', () => { it('should check interactionSelectorCache for entries', () => { startINPTracking() - setInteractionSelector(1 as RelativeTime, '#foo') + updateInteractionSelector(1 as RelativeTime, '#foo') newInteraction({ interactionId: 1, From 986bfe064f7822edeb7bdb2f5fcacd263df358df Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 7 Oct 2024 14:03:27 +0200 Subject: [PATCH 33/37] Fix tests with relative now timestamp --- .../domain/action/trackClickActions.spec.ts | 25 +++++++++++++------ .../trackInteractionToNextPaint.spec.ts | 9 ++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index cb28c94b56..9dfa5b61ef 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -428,24 +428,35 @@ describe('trackClickActions', () => { describe('interactionSelectorCache', () => { it('should add pointer down to the map', () => { startClickActionsTracking() - emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 0 } }) - expect(getInteractionSelector(0 as RelativeTime)).toBe('#button') + const timeStamp = relativeNow() + + emulateClick({ + activity: { on: 'pointerdown' }, + eventProperty: { timeStamp }, + }) + expect(getInteractionSelector(timeStamp)).toBe('#button') }) it('should add pointerup to the map', () => { startClickActionsTracking() - emulateClick({ activity: { on: 'pointerup' }, eventProperty: { timeStamp: 0 } }) - expect(getInteractionSelector(0 as RelativeTime)).toBe('#button') + const timeStamp = relativeNow() + + emulateClick({ + activity: { on: 'pointerup' }, + eventProperty: { timeStamp }, + }) + expect(getInteractionSelector(timeStamp)).toBe('#button') }) it('should clear outdated entries when pointer up', () => { startClickActionsTracking() + const timeStamp = relativeNow() - emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 0 } }) + emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp } }) clock.tick(EXPIRE_DELAY) - emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp: 10 } }) + emulateClick({ activity: { on: 'pointerup' }, eventProperty: { timeStamp: relativeNow() } }) - expect(getInteractionSelector(0 as RelativeTime)).toBeUndefined() + expect(getInteractionSelector(timeStamp)).toBeUndefined() }) }) diff --git a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts index 5011af025e..d657a95c34 100644 --- a/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts +++ b/packages/rum-core/src/domain/view/viewMetrics/trackInteractionToNextPaint.spec.ts @@ -1,5 +1,5 @@ import type { Duration, RelativeTime } from '@datadog/browser-core' -import { elapsed, resetExperimentalFeatures } from '@datadog/browser-core' +import { elapsed, relativeNow, resetExperimentalFeatures } from '@datadog/browser-core' import { registerCleanupTask } from '@datadog/browser-core/test' import { appendElement, @@ -251,17 +251,18 @@ describe('trackInteractionToNextPaint', () => { it('should check interactionSelectorCache for entries', () => { startINPTracking() - updateInteractionSelector(1 as RelativeTime, '#foo') + const startTime = relativeNow() + updateInteractionSelector(startTime, '#foo') newInteraction({ interactionId: 1, duration: 1 as Duration, - startTime: 1 as RelativeTime, + startTime, target: undefined, }) expect(getInteractionToNextPaint()?.targetSelector).toEqual('#foo') - expect(getInteractionSelector(1 as RelativeTime)).toBeUndefined() + expect(getInteractionSelector(startTime)).toBeUndefined() }) }) }) From f029cd9c8787f2d08aaa217bfff96b02c8633f24 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Mon, 7 Oct 2024 15:29:30 +0200 Subject: [PATCH 34/37] avoid using emulateClick with delay --- .../domain/action/trackClickActions.spec.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index 9dfa5b61ef..f2896ed2ee 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -1,4 +1,4 @@ -import type { Context, Duration, RelativeTime } from '@datadog/browser-core' +import type { Context, Duration } from '@datadog/browser-core' import { addDuration, clocksNow, @@ -430,10 +430,7 @@ describe('trackClickActions', () => { startClickActionsTracking() const timeStamp = relativeNow() - emulateClick({ - activity: { on: 'pointerdown' }, - eventProperty: { timeStamp }, - }) + button.dispatchEvent(createNewEvent('pointerdown', { timeStamp })) expect(getInteractionSelector(timeStamp)).toBe('#button') }) @@ -441,20 +438,17 @@ describe('trackClickActions', () => { startClickActionsTracking() const timeStamp = relativeNow() - emulateClick({ - activity: { on: 'pointerup' }, - eventProperty: { timeStamp }, - }) + button.dispatchEvent(createNewEvent('pointerdown', { timeStamp })) expect(getInteractionSelector(timeStamp)).toBe('#button') }) - it('should clear outdated entries when pointer up', () => { + it('should clear outdated entries', () => { startClickActionsTracking() const timeStamp = relativeNow() - emulateClick({ activity: { on: 'pointerdown' }, eventProperty: { timeStamp } }) + emulateClick({ eventProperty: { timeStamp } }) clock.tick(EXPIRE_DELAY) - emulateClick({ activity: { on: 'pointerup' }, eventProperty: { timeStamp: relativeNow() } }) + emulateClick({ eventProperty: { timeStamp: relativeNow() } }) expect(getInteractionSelector(timeStamp)).toBeUndefined() }) From e4a24941aea209e95d26a43e12978770cdb84799 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Tue, 8 Oct 2024 10:10:49 +0200 Subject: [PATCH 35/37] Avoid using arrow functions --- .../rum-core/src/domain/action/interactionSelectorCache.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rum-core/src/domain/action/interactionSelectorCache.ts b/packages/rum-core/src/domain/action/interactionSelectorCache.ts index 1eb956be5e..24e153c8bc 100644 --- a/packages/rum-core/src/domain/action/interactionSelectorCache.ts +++ b/packages/rum-core/src/domain/action/interactionSelectorCache.ts @@ -5,13 +5,13 @@ import type { RelativeTime } from '@datadog/browser-core' export const CLICK_ACTION_MAX_DURATION = 10 * ONE_SECOND export const interactionSelectorCache = new Map() -export const getInteractionSelector = (relativeTimestamp: RelativeTime) => { +export function getInteractionSelector(relativeTimestamp: RelativeTime) { const selector = interactionSelectorCache.get(relativeTimestamp) interactionSelectorCache.delete(relativeTimestamp) return selector } -export const updateInteractionSelector = (relativeTimestamp: RelativeTime, selector: string) => { +export function updateInteractionSelector(relativeTimestamp: RelativeTime, selector: string) { interactionSelectorCache.set(relativeTimestamp, selector) interactionSelectorCache.forEach((_, relativeTimestamp) => { if (elapsed(relativeTimestamp, relativeNow()) > CLICK_ACTION_MAX_DURATION) { From 768e1a44c954f6c3d05a2712ab23bd032acfcf5b Mon Sep 17 00:00:00 2001 From: cy-moi Date: Wed, 9 Oct 2024 16:58:00 +0200 Subject: [PATCH 36/37] Test with ci unit test with emulateClick --- packages/rum-core/src/domain/action/trackClickActions.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index f2896ed2ee..176dde7464 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -430,7 +430,7 @@ describe('trackClickActions', () => { startClickActionsTracking() const timeStamp = relativeNow() - button.dispatchEvent(createNewEvent('pointerdown', { timeStamp })) + emulateClick({ eventProperty: { timeStamp } }) expect(getInteractionSelector(timeStamp)).toBe('#button') }) @@ -438,7 +438,7 @@ describe('trackClickActions', () => { startClickActionsTracking() const timeStamp = relativeNow() - button.dispatchEvent(createNewEvent('pointerdown', { timeStamp })) + emulateClick({ eventProperty: { timeStamp } }) expect(getInteractionSelector(timeStamp)).toBe('#button') }) From 6e862a66a4614c02b0b7769c15a3f52c79cef462 Mon Sep 17 00:00:00 2001 From: cy-moi Date: Thu, 10 Oct 2024 16:05:33 +0200 Subject: [PATCH 37/37] Move unit tests to standalone file --- .../action/interactionSelectorCache.spec.ts | 35 +++++++++++++++++++ .../domain/action/trackClickActions.spec.ts | 11 ------ 2 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 packages/rum-core/src/domain/action/interactionSelectorCache.spec.ts diff --git a/packages/rum-core/src/domain/action/interactionSelectorCache.spec.ts b/packages/rum-core/src/domain/action/interactionSelectorCache.spec.ts new file mode 100644 index 0000000000..e910fda51c --- /dev/null +++ b/packages/rum-core/src/domain/action/interactionSelectorCache.spec.ts @@ -0,0 +1,35 @@ +import { relativeNow } from '@datadog/browser-core' +import { mockClock } from '@datadog/browser-core/test' +import type { Clock } from '@datadog/browser-core/test' +import { + updateInteractionSelector, + getInteractionSelector, + interactionSelectorCache, + CLICK_ACTION_MAX_DURATION, +} from './interactionSelectorCache' + +describe('interactionSelectorCache', () => { + let clock: Clock + beforeEach(() => { + clock = mockClock() + }) + + afterEach(() => { + clock.cleanup() + }) + + it('should delete the selector after getting it', () => { + const timestamp = relativeNow() + updateInteractionSelector(timestamp, 'selector') + expect(getInteractionSelector(timestamp)).toBe('selector') + expect(interactionSelectorCache.get(timestamp)).toBeUndefined() + }) + + it('should delete outdated selectors', () => { + const timestamp = relativeNow() + updateInteractionSelector(timestamp, 'selector') + expect(getInteractionSelector(timestamp)).toBe('selector') + clock.tick(CLICK_ACTION_MAX_DURATION) + expect(interactionSelectorCache.get(timestamp)).toBeUndefined() + }) +}) diff --git a/packages/rum-core/src/domain/action/trackClickActions.spec.ts b/packages/rum-core/src/domain/action/trackClickActions.spec.ts index 176dde7464..838b359f64 100644 --- a/packages/rum-core/src/domain/action/trackClickActions.spec.ts +++ b/packages/rum-core/src/domain/action/trackClickActions.spec.ts @@ -441,17 +441,6 @@ describe('trackClickActions', () => { emulateClick({ eventProperty: { timeStamp } }) expect(getInteractionSelector(timeStamp)).toBe('#button') }) - - it('should clear outdated entries', () => { - startClickActionsTracking() - const timeStamp = relativeNow() - - emulateClick({ eventProperty: { timeStamp } }) - clock.tick(EXPIRE_DELAY) - emulateClick({ eventProperty: { timeStamp: relativeNow() } }) - - expect(getInteractionSelector(timeStamp)).toBeUndefined() - }) }) function emulateClick({