Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[REPLAY] Add public function to get the link to current Replay #2047

Merged
merged 25 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5419e98
[REPLAY] Add function to get the URL to the current replay
ThibautGeriz Mar 1, 2023
0346742
[REPLAY] Add replay link in slim package
ThibautGeriz Apr 3, 2023
ee0d030
[REPLAY] Add error code when browser is not supported
ThibautGeriz Apr 3, 2023
ab1c25e
[REPLAY] Fix tests for IE
ThibautGeriz Apr 4, 2023
c9f32ce
[REPLAY] Simplify unit tests
ThibautGeriz Apr 4, 2023
3e197d7
[REPLAY] Refactor of get replay link function
ThibautGeriz Apr 4, 2023
2ee287d
[REPLAY] Rename functions
ThibautGeriz Apr 5, 2023
34c4f73
[REPLAY] Refactor subdomain logic
ThibautGeriz Apr 5, 2023
06ffd5c
[REPLAY] Simplify tests
ThibautGeriz Apr 5, 2023
31edb21
[REPLAY] Use more explicit session id when no session is recorded
ThibautGeriz Apr 5, 2023
daf32b6
[REPLAY] Fix tests for IE on BS
ThibautGeriz Apr 5, 2023
274d88b
[REPLAY] Add missing case in unit tests
ThibautGeriz Apr 5, 2023
837c3dd
[REPLAY] Use internal stats instead of replay start to find out if re…
ThibautGeriz Apr 5, 2023
6b5d4ac
[REPLAY] Fix tests for IE on BS bis
ThibautGeriz Apr 5, 2023
4d5e6cd
[REPLAY] Extract logic in helper to avoid duplication
ThibautGeriz Apr 6, 2023
4f0704d
Merge remote-tracking branch 'origin/main' into thibaut.gery/add-repl…
ThibautGeriz Apr 6, 2023
4aa65e9
[REPLAY] Remove unused export
ThibautGeriz Apr 6, 2023
78975b3
[REPLAY] Refactor 'getSessionReplayUrl'
ThibautGeriz Apr 6, 2023
58c4d9d
[REPLAY] Move file to match with function name
ThibautGeriz Apr 6, 2023
bd634b3
Merge remote-tracking branch 'origin/main' into thibaut.gery/add-repl…
ThibautGeriz Apr 6, 2023
c6cb2dc
[REPLAY] Fix formatter
ThibautGeriz Apr 6, 2023
0ff7004
[REPLAY] Remove superfluous space
ThibautGeriz Apr 7, 2023
77e94c4
[REPLAY] Remove un-used type
ThibautGeriz Apr 7, 2023
caac7ad
[REPLAY] Improve unit test clarity
ThibautGeriz Apr 7, 2023
0333598
[REPLAY] Fix timer in unit tests
ThibautGeriz Apr 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion packages/rum-core/src/boot/rumPublicApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export interface RecorderApi {
) => void
isRecording: () => boolean
getReplayStats: (viewId: string) => ReplayStats | undefined
getSessionReplayLink: (
configuration: RumConfiguration,
sessionManager: RumSessionManager,
viewContexts: ViewContexts
) => string | undefined
}
interface RumPublicApiOptions {
ignoreInitIfSyntheticsWillInjectRum?: boolean
Expand All @@ -69,6 +74,7 @@ export function makeRumPublicApi(
let getInternalContextStrategy: StartRumResult['getInternalContext'] = () => undefined
let getInitConfigurationStrategy = (): InitConfiguration | undefined => undefined
let stopSessionStrategy: () => void = noop
let getSessionReplayLinkStrategy: () => string | undefined = () => undefined

let bufferApiCalls = new BoundedBuffer()
let addTimingStrategy: StartRumResult['addTiming'] = (name, time = timeStampNow()) => {
Expand Down Expand Up @@ -152,7 +158,8 @@ export function makeRumPublicApi(
userContextManager,
initialViewOptions
)

getSessionReplayLinkStrategy = () =>
recorderApi.getSessionReplayLink(configuration, startRumResults.session, startRumResults.viewContexts)
;({
startView: startViewStrategy,
addAction: addActionStrategy,
Expand Down Expand Up @@ -273,6 +280,7 @@ export function makeRumPublicApi(
isExperimentalFeatureEnabled(ExperimentalFeature.SANITIZE_INPUTS) ? sanitize(value) : value
)
}),
getSessionReplayLink: monitor(() => getSessionReplayLinkStrategy()),
})

return rumPublicApi
Expand Down
5 changes: 3 additions & 2 deletions packages/rum-core/src/domain/assembly.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RelativeTime } from '@datadog/browser-core'
import type { ClocksState, RelativeTime } from '@datadog/browser-core'
import { ErrorSource, ONE_MINUTE, display } from '@datadog/browser-core'
import {
initEventBridgeStub,
Expand Down Expand Up @@ -37,6 +37,7 @@ describe('rum assembly', () => {
findView = () => ({
id: '7890',
name: 'view name',
startClocks: {} as ClocksState,
})
reportErrorSpy = jasmine.createSpy('reportError')
commonContext = {
Expand Down Expand Up @@ -484,7 +485,7 @@ describe('rum assembly', () => {

it('should be overridden by the view context', () => {
const { lifeCycle } = setupBuilder.build()
findView = () => ({ service: 'new service', version: 'new version', id: '1234' })
findView = () => ({ service: 'new service', version: 'new version', id: '1234', startClocks: {} as ClocksState })
notifyRawRumEvent(lifeCycle, {
rawRumEvent: createRawRumEvent(RumEventType.ACTION),
})
Expand Down
3 changes: 3 additions & 0 deletions packages/rum-core/src/domain/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface RumInitConfiguration extends InitConfiguration {

// replay options
defaultPrivacyLevel?: DefaultPrivacyLevel | undefined
subdomain?: string
/**
* @deprecated use sessionReplaySampleRate instead
*/
Expand Down Expand Up @@ -80,6 +81,7 @@ export interface RumConfiguration extends Configuration {
trackResources: boolean | undefined
trackLongTasks: boolean | undefined
version?: string
subdomain?: string
customerDataTelemetrySampleRate: number
}

Expand Down Expand Up @@ -150,6 +152,7 @@ export function validateAndBuildRumConfiguration(
trackViewsManually: !!initConfiguration.trackViewsManually,
trackResources: initConfiguration.trackResources,
trackLongTasks: initConfiguration.trackLongTasks,
subdomain: initConfiguration.subdomain,
defaultPrivacyLevel: objectHasValue(DefaultPrivacyLevel, initConfiguration.defaultPrivacyLevel)
? initConfiguration.defaultPrivacyLevel
: DefaultPrivacyLevel.MASK_USER_INPUT,
Expand Down
4 changes: 3 additions & 1 deletion packages/rum-core/src/domain/contexts/viewContexts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RelativeTime } from '@datadog/browser-core'
import type { ClocksState, RelativeTime } from '@datadog/browser-core'
import { SESSION_TIME_OUT_DELAY, ContextHistory } from '@datadog/browser-core'
import type { LifeCycle } from '../lifeCycle'
import { LifeCycleEventType } from '../lifeCycle'
Expand All @@ -11,6 +11,7 @@ export interface ViewContext {
version?: string
id: string
name?: string
startClocks: ClocksState
}

export interface ViewContexts {
Expand Down Expand Up @@ -39,6 +40,7 @@ export function startViewContexts(lifeCycle: LifeCycle): ViewContexts {
version: view.version,
id: view.id,
name: view.name,
startClocks: view.startClocks,
}
}

Expand Down
29 changes: 29 additions & 0 deletions packages/rum-core/src/domain/getDatadogOrigin.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { RumConfiguration } from '@datadog/browser-rum-core'
import { getDatadogOrigin } from './getDatadogOrigin'

const DEFAULT_CONFIGURATION = {
site: 'datad0g.com',
} as RumConfiguration

describe('getDatadogOrigin', () => {
const parameters: Array<[string, string | undefined, string]> = [
['datadoghq.com', undefined, 'app.datadoghq.com'],
['datadoghq.com', 'toto', 'toto.datadoghq.com'],
['datad0g.com', undefined, 'dd.datad0g.com'],
['datad0g.com', 'toto', 'toto.datad0g.com'],
['us3.datadoghq.com', undefined, 'us3.datadoghq.com'],
['us3.datadoghq.com', 'toto', 'toto.us3.datadoghq.com'],
['us5.datadoghq.com', undefined, 'us5.datadoghq.com'],
['us5.datadoghq.com', 'toto', 'toto.us5.datadoghq.com'],
]

parameters.forEach(([site, subdomain, host]) => {
it(`should return ${host} for subdomain "${
subdomain ?? 'undefined'
}" on "${site}" with query params if view is found`, () => {
const link = getDatadogOrigin({ ...DEFAULT_CONFIGURATION, site, subdomain })
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 suggestion:DEFAULT_CONFIGURATION does not seem to be used

Suggested change
const link = getDatadogOrigin({ ...DEFAULT_CONFIGURATION, site, subdomain })
const link = getDatadogOrigin({ site, subdomain } as RumConfiguration)


expect(link).toBe(`https://${host}`)
})
})
})
20 changes: 20 additions & 0 deletions packages/rum-core/src/domain/getDatadogOrigin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { RumConfiguration } from './configuration'

export function getDatadogOrigin(rumConfiguration: RumConfiguration) {
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 suggestion: ‏to be consistent with public docs naming

Suggested change
export function getDatadogOrigin(rumConfiguration: RumConfiguration) {
export function getDatadogSiteUrl(rumConfiguration: RumConfiguration) {

const site = rumConfiguration.site
const subdomain = rumConfiguration.subdomain || getDefaultSubdomain(rumConfiguration)
return `https://${subdomain ? `${subdomain}.` : ''}${site}`
}

function getDefaultSubdomain(configuration: RumConfiguration): string | undefined {
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 suggestion: for clarity + no need to pass the whole configuration‏

Suggested change
function getDefaultSubdomain(configuration: RumConfiguration): string | undefined {
function getSiteDefaultSubdomain(site: string): string | undefined {

switch (configuration.site) {
case 'datadoghq.com':
return 'app'
case 'datadoghq.eu':
return 'app'
Copy link
Contributor

Choose a reason for hiding this comment

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

🥜 nitpick:

Suggested change
case 'datadoghq.com':
return 'app'
case 'datadoghq.eu':
return 'app'
case 'datadoghq.com':
case 'datadoghq.eu':
return 'app'

case 'datad0g.com':
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 suggestion: ‏we could use/add constants from intakeSites

export const INTAKE_SITE_STAGING = 'datad0g.com'
export const INTAKE_SITE_US1 = 'datadoghq.com'
export const INTAKE_SITE_AP1 = 'ap1.datadoghq.com'
export const INTAKE_SITE_US1_FED = 'ddog-gov.com'

return 'dd'
default:
return undefined
}
}
1 change: 1 addition & 0 deletions packages/rum-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ export { RumInitConfiguration, RumConfiguration } from './domain/configuration'
export { DEFAULT_PROGRAMMATIC_ACTION_NAME_ATTRIBUTE } from './domain/rumEventsCollection/action/getActionNameFromElement'
export { STABLE_ATTRIBUTES } from './domain/rumEventsCollection/action/getSelectorFromElement'
export * from './browser/htmlDomUtils'
export { getDatadogOrigin } from './domain/getDatadogOrigin'
1 change: 1 addition & 0 deletions packages/rum-core/test/noopRecorderApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export const noopRecorderApi: RecorderApi = {
isRecording: () => false,
onRumStart: noop,
getReplayStats: () => undefined,
getSessionReplayLink: () => undefined,
}
29 changes: 29 additions & 0 deletions packages/rum-slim/src/domain/getSessionReplayLink.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { RumConfiguration } from '@datadog/browser-rum-core'
import { getSessionReplayLink } from './getSessionReplayLink'

const DEFAULT_CONFIGURATION = {
site: 'datad0g.com',
} as RumConfiguration

describe('getReplayLink (slim package)', () => {
const parameters: Array<[string, string | undefined, string]> = [
['datadoghq.com', undefined, 'app.datadoghq.com'],
['datadoghq.com', 'toto', 'toto.datadoghq.com'],
['datad0g.com', undefined, 'dd.datad0g.com'],
['datad0g.com', 'toto', 'toto.datad0g.com'],
['us3.datadoghq.com', undefined, 'us3.datadoghq.com'],
['us3.datadoghq.com', 'toto', 'toto.us3.datadoghq.com'],
['us5.datadoghq.com', undefined, 'us5.datadoghq.com'],
['us5.datadoghq.com', 'toto', 'toto.us5.datadoghq.com'],
]

parameters.forEach(([site, subdomain, host]) => {
it(`should return ${host} for subdomain "${
subdomain ?? 'undefined'
}" on "${site}" with query params if view is found`, () => {
const link = getSessionReplayLink({ ...DEFAULT_CONFIGURATION, site, subdomain })

expect(link).toBe(`https://${host}/rum/replay/sessions/session-id?error-type=slim-package`)
})
})
})
ThibautGeriz marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 7 additions & 0 deletions packages/rum-slim/src/domain/getSessionReplayLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { RumConfiguration } from '@datadog/browser-rum-core'
import { getDatadogOrigin } from '@datadog/browser-rum-core'

export function getSessionReplayLink(configuration: RumConfiguration): string | undefined {
const origin = getDatadogOrigin(configuration)
return `${origin}/rum/replay/sessions/session-id?error-type=slim-package`
Copy link
Contributor

Choose a reason for hiding this comment

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

💭 thought: ‏it could be interesting to mutualise the building logic of the url with the rum one to avoid to forget to apply future changes here

Copy link
Contributor Author

@ThibautGeriz ThibautGeriz Apr 5, 2023

Choose a reason for hiding this comment

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

something like that? Where should that go? packages/rum-core/src/domain?

type QueryParams =  { errorType?: string; seed?: string; ts?: number }
function getSessionReplayUrl(configuration: RumConfiguration, { errorType, seed, ts }: QueryParams): string {
  // impl
}

we could even remove the seed & ts params and pass down the arg: ViewContexts

Copy link
Contributor

Choose a reason for hiding this comment

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

packages/rum-core/src/domain?

LGTM, you could probably have a single file for that and getDatadogOrigin

}
2 changes: 2 additions & 0 deletions packages/rum-slim/src/entries/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { defineGlobal, getGlobalObject, noop } from '@datadog/browser-core'
import type { RumPublicApi } from '@datadog/browser-rum-core'
import { makeRumPublicApi, startRum } from '@datadog/browser-rum-core'
import { getSessionReplayLink } from '../domain/getSessionReplayLink'

export {
CommonProperties,
Expand Down Expand Up @@ -32,6 +33,7 @@ export const datadogRum = makeRumPublicApi(startRum, {
onRumStart: noop,
isRecording: () => false,
getReplayStats: () => undefined,
getSessionReplayLink,
})

interface BrowserWindow extends Window {
Expand Down
11 changes: 11 additions & 0 deletions packages/rum/src/boot/isBrowserSupported.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Test for Browser features used while recording
*/
export function isBrowserSupported() {
return (
// Array.from is a bit less supported by browsers than CSSSupportsRule, but has higher chances
// to be polyfilled. Test for both to be more confident. We could add more things if we find out
// this test is not sufficient.
typeof Array.from === 'function' && typeof CSSSupportsRule === 'function' && 'forEach' in NodeList.prototype
)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

note: extracted from recorderApi.ts to avoid a circular dep

17 changes: 4 additions & 13 deletions packages/rum/src/boot/recorderApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import type {
} from '@datadog/browser-rum-core'
import { LifeCycleEventType } from '@datadog/browser-rum-core'
import { getReplayStats } from '../domain/replayStats'
import { getSessionReplayLink } from '../domain/getSessionReplayLink'
import { startDeflateWorker } from '../domain/segmentCollection'

import type { startRecording } from './startRecording'
import { isBrowserSupported } from './isBrowserSupported'

export type StartRecording = typeof startRecording

Expand Down Expand Up @@ -51,6 +53,7 @@ export function makeRecorderApi(
getReplayStats: () => undefined,
onRumStart: noop,
isRecording: () => false,
getSessionReplayLink: () => undefined,
}
}

Expand All @@ -68,7 +71,7 @@ export function makeRecorderApi(
start: () => startStrategy(),
stop: () => stopStrategy(),
getReplayStats,

getSessionReplayLink,
onRumStart: (
lifeCycle: LifeCycle,
configuration: RumConfiguration,
Expand Down Expand Up @@ -155,15 +158,3 @@ export function makeRecorderApi(
isRecording: () => state.status === RecorderStatus.Started,
}
}

/**
* Test for Browser features used while recording
*/
function isBrowserSupported() {
return (
// Array.from is a bit less supported by browsers than CSSSupportsRule, but has higher chances
// to be polyfilled. Test for both to be more confident. We could add more things if we find out
// this test is not sufficient.
typeof Array.from === 'function' && typeof CSSSupportsRule === 'function' && 'forEach' in NodeList.prototype
)
}
4 changes: 2 additions & 2 deletions packages/rum/src/boot/startRecording.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TimeStamp, HttpRequest } from '@datadog/browser-core'
import type { TimeStamp, HttpRequest, ClocksState } from '@datadog/browser-core'
import { PageExitReason, DefaultPrivacyLevel, noop, isIE, timeStampNow } from '@datadog/browser-core'
import type { LifeCycle, ViewCreatedEvent } from '@datadog/browser-rum-core'
import { LifeCycleEventType } from '@datadog/browser-rum-core'
Expand Down Expand Up @@ -43,7 +43,7 @@ describe('startRecording', () => {
setupBuilder = setup()
.withViewContexts({
findView() {
return { id: viewId }
return { id: viewId, startClocks: {} as ClocksState }
},
})
.withSessionManager(sessionManager)
Expand Down
83 changes: 83 additions & 0 deletions packages/rum/src/domain/getSessionReplayLink.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { RumConfiguration, ViewContexts } from '@datadog/browser-rum-core'
import { createRumSessionManagerMock } from '../../../rum-core/test'
import { getSessionReplayLink } from './getSessionReplayLink'
import { addRecord, resetReplayStats } from './replayStats'

const DEFAULT_CONFIGURATION = {
site: 'datad0g.com',
} as RumConfiguration

describe('getReplayLink', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

💬 suggestion: ‏Could you add a test for replay-not-started?

afterEach(() => {
resetReplayStats()
})
it('should return url without query param if no view', () => {
const sessionManager = createRumSessionManagerMock().setId('session-id-1')
const viewContexts = { findView: () => undefined } as ViewContexts

const link = getSessionReplayLink(DEFAULT_CONFIGURATION, sessionManager, viewContexts)

expect(link).toBe('https://dd.datad0g.com/rum/replay/sessions/session-id-1')
})

const parameters: Array<[string, string | undefined, string]> = [
['datadoghq.com', undefined, 'app.datadoghq.com'],
['datadoghq.com', 'toto', 'toto.datadoghq.com'],
['datad0g.com', undefined, 'dd.datad0g.com'],
['datad0g.com', 'toto', 'toto.datad0g.com'],
['us3.datadoghq.com', undefined, 'us3.datadoghq.com'],
['us3.datadoghq.com', 'toto', 'toto.us3.datadoghq.com'],
['us5.datadoghq.com', undefined, 'us5.datadoghq.com'],
['us5.datadoghq.com', 'toto', 'toto.us5.datadoghq.com'],
]

ThibautGeriz marked this conversation as resolved.
Show resolved Hide resolved
parameters.forEach(([site, subdomain, host]) => {
it(`should return ${host} for subdomain "${
subdomain ?? 'undefined'
}" on "${site}" with query params if view is found`, () => {
const sessionManager = createRumSessionManagerMock().setId('session-id-1')
const viewContexts = {
findView: () => ({
id: 'view-id-1',
startClocks: {
timeStamp: 123456,
},
}),
} as ViewContexts
addRecord('view-id-1')

const link = getSessionReplayLink({ ...DEFAULT_CONFIGURATION, site, subdomain }, sessionManager, viewContexts)

expect(link).toBe(`https://${host}/rum/replay/sessions/session-id-1?seed=view-id-1&from=123456`)
Copy link
Contributor Author

@ThibautGeriz ThibautGeriz Apr 4, 2023

Choose a reason for hiding this comment

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

question: this one fails on the browser stack with IE because error-type=browser-not-supported gets rightfully added. Should I disable the test on IE11? Should I re-use the helper isBrowserSupported in the unit tests here? Should I mock isBrowserSupported to force it disabled on every browser?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe change the expectation on IE?

Suggested change
expect(link).toBe(`https://${host}/rum/replay/sessions/session-id-1?seed=view-id-1&from=123456`)
expect(link).toBe(isIE() ? ... : `https://${host}/rum/replay/sessions/session-id-1?seed=view-id-1&from=123456`)

Copy link
Contributor Author

@ThibautGeriz ThibautGeriz Apr 4, 2023

Choose a reason for hiding this comment

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

🤔 still breaking on chrome/android, should I use isBrowserSupported instead of isIE?
https://gitlab.ddbuild.io/DataDog/browser-sdk/-/jobs/249222844

Copy link
Member

Choose a reason for hiding this comment

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

@ThibautGeriz the job is failing on IE11 no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it seems I cannot read apparently

})
})

it('return a param if replay is sampled out', () => {
const sessionManager = createRumSessionManagerMock().setId('session-id-1').setPlanWithoutSessionReplay()
const viewContexts = {
findView: () => ({
id: 'view-id-1',
startClocks: {
timeStamp: 123456,
},
}),
} as ViewContexts

const link = getSessionReplayLink({ ...DEFAULT_CONFIGURATION, site: 'datadoghq.com' }, sessionManager, viewContexts)

expect(link).toBe(
'https://app.datadoghq.com/rum/replay/sessions/session-id-1?error-type=incorrect-session-plan&seed=view-id-1&from=123456'
)
})

it('return a param if rum is sampled out', () => {
const sessionManager = createRumSessionManagerMock().setNotTracked()
const viewContexts = {
findView: () => undefined,
} as ViewContexts

const link = getSessionReplayLink({ ...DEFAULT_CONFIGURATION, site: 'datadoghq.com' }, sessionManager, viewContexts)

expect(link).toBe('https://app.datadoghq.com/rum/replay/sessions/session-id?error-type=rum-not-tracked')
})
})
Loading