-
Notifications
You must be signed in to change notification settings - Fork 142
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
🐛 Fix replay visual viewport resize support #2891
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -3,14 +3,19 @@ import type { RumConfiguration, ViewCreatedEvent } from '@datadog/browser-rum-co | |||
import { LifeCycle, LifeCycleEventType } from '@datadog/browser-rum-core' | ||||
import type { Clock } from '@datadog/browser-core/test' | ||||
import { createNewEvent, collectAsyncCalls, registerCleanupTask } from '@datadog/browser-core/test' | ||||
import { findElement, findFullSnapshot, findNode, recordsPerFullSnapshot } from '../../../test' | ||||
import { | ||||
findElement, | ||||
findFullSnapshot, | ||||
findNode, | ||||
recordsPerFullSnapshot, | ||||
createRumFrustrationEvent, | ||||
} from '../../../test' | ||||
import type { | ||||
BrowserIncrementalSnapshotRecord, | ||||
BrowserMutationData, | ||||
BrowserRecord, | ||||
DocumentFragmentNode, | ||||
ElementNode, | ||||
FocusRecord, | ||||
ScrollData, | ||||
} from '../../types' | ||||
import { NodeType, RecordType, IncrementalSource } from '../../types' | ||||
|
@@ -146,64 +151,6 @@ describe('record', () => { | |||
}) | ||||
}) | ||||
|
||||
describe('Focus records', () => { | ||||
let hasFocus: boolean | ||||
|
||||
beforeEach(() => { | ||||
hasFocus = true | ||||
spyOn(Document.prototype, 'hasFocus').and.callFake(() => hasFocus) | ||||
}) | ||||
|
||||
it('adds an initial Focus record when starting to record', () => { | ||||
startRecording() | ||||
expect(getEmittedRecords()[1]).toEqual({ | ||||
type: RecordType.Focus, | ||||
timestamp: jasmine.any(Number), | ||||
data: { | ||||
has_focus: true, | ||||
}, | ||||
}) | ||||
}) | ||||
|
||||
it('adds a Focus record on focus', () => { | ||||
startRecording() | ||||
emitSpy.calls.reset() | ||||
|
||||
window.dispatchEvent(createNewEvent('focus')) | ||||
expect(getEmittedRecords()[0].type).toBe(RecordType.Focus) | ||||
}) | ||||
|
||||
it('adds a Focus record on blur', () => { | ||||
startRecording() | ||||
emitSpy.calls.reset() | ||||
|
||||
window.dispatchEvent(createNewEvent('blur')) | ||||
expect(getEmittedRecords()[0].type).toBe(RecordType.Focus) | ||||
}) | ||||
|
||||
it('adds a Focus record on when taking a full snapshot', () => { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now covered here:
|
||||
startRecording() | ||||
emitSpy.calls.reset() | ||||
|
||||
// trigger full snapshot by starting a new view | ||||
newView() | ||||
|
||||
expect(getEmittedRecords()[1].type).toBe(RecordType.Focus) | ||||
}) | ||||
|
||||
it('set has_focus to true if the document has the focus', () => { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already covered here:
|
||||
hasFocus = true | ||||
startRecording() | ||||
expect((getEmittedRecords()[1] as FocusRecord).data.has_focus).toBe(true) | ||||
}) | ||||
|
||||
it("set has_focus to false if the document doesn't have the focus", () => { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already covered here:
|
||||
hasFocus = false | ||||
startRecording() | ||||
expect((getEmittedRecords()[1] as FocusRecord).data.has_focus).toBe(false) | ||||
}) | ||||
}) | ||||
|
||||
describe('Shadow dom', () => { | ||||
it('should record a simple mutation inside a shadow root', () => { | ||||
const element = appendElement('<hr class="toto" />', createShadow()) | ||||
|
@@ -422,6 +369,95 @@ describe('record', () => { | |||
}) | ||||
}) | ||||
|
||||
describe('should collect records', () => { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👏 praise: looks great |
||||
let div: HTMLDivElement | ||||
let input: HTMLInputElement | ||||
let audio: HTMLAudioElement | ||||
beforeEach(() => { | ||||
div = appendElement('<div target></div>') as HTMLDivElement | ||||
input = appendElement('<input target />') as HTMLInputElement | ||||
audio = appendElement('<audio controls autoplay target></audio>') as HTMLAudioElement | ||||
startRecording() | ||||
emitSpy.calls.reset() | ||||
}) | ||||
|
||||
it('move', () => { | ||||
document.body.dispatchEvent(createNewEvent('mousemove', { clientX: 1, clientY: 2 })) | ||||
expect(getEmittedRecords()[0].type).toBe(RecordType.IncrementalSnapshot) | ||||
expect((getEmittedRecords()[0] as BrowserIncrementalSnapshotRecord).data.source).toBe(IncrementalSource.MouseMove) | ||||
}) | ||||
|
||||
it('interaction', () => { | ||||
document.body.dispatchEvent(createNewEvent('click', { clientX: 1, clientY: 2 })) | ||||
expect((getEmittedRecords()[0] as BrowserIncrementalSnapshotRecord).data.source).toBe( | ||||
IncrementalSource.MouseInteraction | ||||
) | ||||
}) | ||||
|
||||
it('scroll', () => { | ||||
div.dispatchEvent(createNewEvent('scroll', { target: div })) | ||||
|
||||
expect(getEmittedRecords()[0].type).toBe(RecordType.IncrementalSnapshot) | ||||
expect((getEmittedRecords()[0] as BrowserIncrementalSnapshotRecord).data.source).toBe(IncrementalSource.Scroll) | ||||
}) | ||||
|
||||
it('viewport resize', () => { | ||||
window.dispatchEvent(createNewEvent('resize')) | ||||
|
||||
expect(getEmittedRecords()[0].type).toBe(RecordType.IncrementalSnapshot) | ||||
expect((getEmittedRecords()[0] as BrowserIncrementalSnapshotRecord).data.source).toBe( | ||||
IncrementalSource.ViewportResize | ||||
) | ||||
}) | ||||
|
||||
it('input', () => { | ||||
input.value = 'newValue' | ||||
input.dispatchEvent(createNewEvent('input', { target: input })) | ||||
|
||||
expect(getEmittedRecords()[0].type).toBe(RecordType.IncrementalSnapshot) | ||||
expect((getEmittedRecords()[0] as BrowserIncrementalSnapshotRecord).data.source).toBe(IncrementalSource.Input) | ||||
}) | ||||
|
||||
it('media interaction', () => { | ||||
audio.dispatchEvent(createNewEvent('play', { target: audio })) | ||||
|
||||
expect(getEmittedRecords()[0].type).toBe(RecordType.IncrementalSnapshot) | ||||
expect((getEmittedRecords()[0] as BrowserIncrementalSnapshotRecord).data.source).toBe( | ||||
IncrementalSource.MediaInteraction | ||||
) | ||||
}) | ||||
|
||||
it('focus', () => { | ||||
window.dispatchEvent(createNewEvent('blur')) | ||||
|
||||
expect(getEmittedRecords()[0].type).toBe(RecordType.Focus) | ||||
}) | ||||
|
||||
it('visual viewport resize', () => { | ||||
if (!window.visualViewport) { | ||||
pending('visualViewport not supported') | ||||
} | ||||
|
||||
visualViewport!.dispatchEvent(createNewEvent('resize')) | ||||
expect(getEmittedRecords()[0].type).toBe(RecordType.VisualViewport) | ||||
}) | ||||
|
||||
it('frustration', () => { | ||||
lifeCycle.notify( | ||||
LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, | ||||
createRumFrustrationEvent(new MouseEvent('pointerup')) | ||||
) | ||||
|
||||
expect(getEmittedRecords()[0].type).toBe(RecordType.FrustrationRecord) | ||||
}) | ||||
|
||||
it('view end event', () => { | ||||
lifeCycle.notify(LifeCycleEventType.VIEW_ENDED, {} as any) | ||||
|
||||
expect(getEmittedRecords()[0].type).toBe(RecordType.ViewEnd) | ||||
}) | ||||
}) | ||||
|
||||
function startRecording() { | ||||
lifeCycle = new LifeCycle() | ||||
recordApi = record({ | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { relativeNow, timeStampNow } from '@datadog/browser-core' | ||
import type { RawRumActionEvent } from '@datadog/browser-rum-core' | ||
import { ActionType, FrustrationType, RumEventType } from '@datadog/browser-rum-core' | ||
import type { RawRumEventCollectedData } from 'packages/rum-core/src/domain/lifeCycle' | ||
|
||
export function createRumFrustrationEvent(mouseEvent: MouseEvent): RawRumEventCollectedData<RawRumActionEvent> { | ||
return { | ||
startTime: relativeNow(), | ||
rawRumEvent: { | ||
date: timeStampNow(), | ||
type: RumEventType.ACTION, | ||
action: { | ||
id: '123e4567-e89b-12d3-a456-426614174000', | ||
type: ActionType.CLICK, | ||
frustration: { | ||
type: [FrustrationType.DEAD_CLICK], | ||
}, | ||
target: { | ||
name: '123e4567-e89b-12d3-a456-426614174000', | ||
}, | ||
}, | ||
}, | ||
domainContext: { events: [mouseEvent] }, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically covered here:
browser-sdk/packages/rum/src/domain/record/startFullSnapshots.spec.ts
Line 55 in 9fb112d