import type { RumConfiguration, ViewCreatedEvent } from '@datadog/browser-rum-core' import { LifeCycle, LifeCycleEventType } from '@datadog/browser-rum-core' import type { TimeStamp } from '@datadog/browser-core' import { noop } from '@datadog/browser-core' import { RecordType, type BrowserRecord } from '../../types' import { appendElement } from '../../../../rum-core/test' import { startFullSnapshots } from './startFullSnapshots' import { createElementsScrollPositions } from './elementsScrollPositions' import type { ShadowRootsController } from './shadowRootsController' import { createSerializationScope, type SerializationStats } from './serialization' import { createNodeIds } from './nodeIds' describe('startFullSnapshots', () => { const viewStartClock = { relative: 1, timeStamp: 1 as TimeStamp } let lifeCycle: LifeCycle let emitCallback: jasmine.Spy<(record: BrowserRecord, stats?: SerializationStats) => void> beforeEach(() => { lifeCycle = new LifeCycle() emitCallback = jasmine.createSpy() appendElement('', document.head) startFullSnapshots( createElementsScrollPositions(), {} as ShadowRootsController, lifeCycle, {} as RumConfiguration, createSerializationScope(createNodeIds()), noop, emitCallback ) }) it('takes a full snapshot when startFullSnapshots is called', () => { expect(emitCallback).toHaveBeenCalled() }) it('takes a full snapshot when the view changes', () => { emitCallback.calls.reset() lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, { startClocks: viewStartClock, } as Partial as any) expect(emitCallback).toHaveBeenCalled() }) it('full snapshot related records should have the view change date', () => { emitCallback.calls.reset() lifeCycle.notify(LifeCycleEventType.VIEW_CREATED, { startClocks: viewStartClock, } as Partial as any) const records = emitCallback.calls.allArgs().map((args) => args[0]) expect(records[0].timestamp).toEqual(1) expect(records[1].timestamp).toEqual(1) expect(records[2].timestamp).toEqual(1) }) it('full snapshot records should contain Meta, Focus, FullSnapshot', () => { const records = emitCallback.calls.allArgs().map((args) => args[0]) expect(records).toEqual( jasmine.arrayContaining([ { data: { height: jasmine.any(Number), href: window.location.href, width: jasmine.any(Number), }, type: RecordType.Meta, timestamp: jasmine.any(Number), }, { data: { has_focus: document.hasFocus(), }, type: RecordType.Focus, timestamp: jasmine.any(Number), }, { data: { node: jasmine.any(Object), initialOffset: { left: jasmine.any(Number), top: jasmine.any(Number), }, }, type: RecordType.FullSnapshot, timestamp: jasmine.any(Number), }, ]) ) }) it('full snapshot records should contain visualViewport when supported', () => { if (!window.visualViewport) { pending('visualViewport not supported') } const record = emitCallback.calls.mostRecent().args[0] expect(record).toEqual({ data: jasmine.any(Object), type: RecordType.VisualViewport, timestamp: jasmine.any(Number), }) }) it('full snapshot records should be emitted with serialization stats', () => { const fullSnapshotEmits = emitCallback.calls.allArgs().filter((args) => args[0].type === RecordType.FullSnapshot) expect(fullSnapshotEmits[0][1]).toEqual({ cssText: { count: 1, max: 21, sum: 21 }, serializationDuration: jasmine.anything(), }) }) })