1- import type { ViewHistoryEntry } from '@datadog/browser-rum-core'
1+ import type { LongTaskContext , ViewHistoryEntry } from '@datadog/browser-rum-core'
22import { LifeCycle , LifeCycleEventType , RumPerformanceEntryType , createHooks } from '@datadog/browser-rum-core'
3- import type { Duration , RelativeTime , TimeStamp } from '@datadog/browser-core'
4- import { clocksOrigin , createIdentityEncoder , deepClone , relativeNow , timeStampNow } from '@datadog/browser-core'
3+ import type { Duration , RelativeTime } from '@datadog/browser-core'
4+ import {
5+ addDuration ,
6+ clocksNow ,
7+ clocksOrigin ,
8+ createIdentityEncoder ,
9+ createValueHistory ,
10+ deepClone ,
11+ relativeNow ,
12+ timeStampNow ,
13+ } from '@datadog/browser-core'
514import {
615 setPageVisibility ,
716 restorePageVisibility ,
817 createNewEvent ,
918 interceptRequests ,
1019 DEFAULT_FETCH_MOCK ,
1120 readFormDataRequest ,
21+ mockClock ,
1222} from '@datadog/browser-core/test'
13- import type { RumPerformanceEntry } from 'packages/rum-core/src/browser/performanceObservable'
14- import {
15- createPerformanceEntry ,
16- createRumSessionManagerMock ,
17- mockPerformanceObserver ,
18- mockRumConfiguration ,
19- mockViewHistory ,
20- } from '../../../../rum-core/test'
23+ import { LONG_TASK_ID_HISTORY_TIME_OUT_DELAY } from 'packages/rum-core/src/domain/longTask/longTaskCollection'
24+ import { createRumSessionManagerMock , mockRumConfiguration , mockViewHistory } from '../../../../rum-core/test'
2125import { mockProfiler } from '../../../test'
2226import { mockedTrace } from './test-utils/mockedTrace'
2327import { createRumProfiler } from './profiler'
24- import type { ProfilerTrace , RUMProfiler , RumProfilerTrace } from './types'
28+ import type { ProfilerTrace , RumProfilerTrace } from './types'
2529import type { ProfilingContextManager } from './profilingContext'
2630import { startProfilingContext } from './profilingContext'
2731import type { ProfileEventPayload } from './transport/assembly'
@@ -44,18 +48,11 @@ describe('profiler', () => {
4448
4549 let lifeCycle = new LifeCycle ( )
4650
47- function setupProfiler ( currentView ?: ViewHistoryEntry ) : {
48- profiler : RUMProfiler
49- notifyPerformanceEntries : ( entries : RumPerformanceEntry [ ] ) => void
50- profilingContextManager : ProfilingContextManager
51- mockedRumProfilerTrace : RumProfilerTrace
52- longTaskContexts : { findLongTasks : jasmine . Spy }
53- } {
51+ function setupProfiler ( currentView ?: ViewHistoryEntry ) {
5452 const sessionManager = createRumSessionManagerMock ( ) . setId ( 'session-id-1' )
5553 lifeCycle = new LifeCycle ( )
5654 const hooks = createHooks ( )
5755 const profilingContextManager : ProfilingContextManager = startProfilingContext ( hooks )
58- const { notifyPerformanceEntries } = mockPerformanceObserver ( )
5956
6057 const mockProfilerTrace : ProfilerTrace = deepClone ( mockedTrace )
6158
@@ -89,9 +86,21 @@ describe('profiler', () => {
8986 mockProfiler ( mockProfilerTrace )
9087
9188 // Mock longTaskContexts
92- const longTaskContexts = {
93- findLongTasks : jasmine . createSpy ( 'findLongTasks' ) . and . returnValue ( [ ] ) ,
89+ function mockLongTaskContexts ( ) {
90+ const longTaskContexts = createValueHistory < LongTaskContext > ( {
91+ expireDelay : LONG_TASK_ID_HISTORY_TIME_OUT_DELAY ,
92+ } )
93+
94+ return {
95+ findLongTasks : ( startTime : RelativeTime , duration : Duration ) : LongTaskContext [ ] =>
96+ longTaskContexts . findAll ( startTime , duration ) ,
97+ addLongTask : ( longTask : LongTaskContext ) =>
98+ longTaskContexts
99+ . add ( longTask , longTask . startClocks . relative )
100+ . close ( addDuration ( longTask . startClocks . relative , longTask . duration ) ) ,
101+ }
94102 }
103+ const longTaskContexts = mockLongTaskContexts ( )
95104
96105 // Start collection of profile.
97106 const profiler = createRumProfiler (
@@ -110,7 +119,7 @@ describe('profiler', () => {
110119 minProfileDurationMs : 0 ,
111120 }
112121 )
113- return { profiler, notifyPerformanceEntries , profilingContextManager, mockedRumProfilerTrace, longTaskContexts }
122+ return { profiler, profilingContextManager, mockedRumProfilerTrace, longTaskContexts }
114123 }
115124
116125 it ( 'should start profiling collection and collect data on stop' , async ( ) => {
@@ -185,44 +194,86 @@ describe('profiler', () => {
185194 expect ( request [ 'wall-time.json' ] ) . toEqual ( mockedRumProfilerTrace )
186195 } )
187196
188- it ( 'should collect long task from core and then attach long task id to the Profiler trace' , async ( ) => {
189- const { profiler, notifyPerformanceEntries, profilingContextManager, longTaskContexts } = setupProfiler ( )
190- longTaskContexts . findLongTasks . and . returnValue ( [
191- {
192- id : 'long-task-id-1' ,
193- startClocks : { relative : 12345 as RelativeTime , timeStamp : 12345 as TimeStamp } ,
194- duration : 1000 as Duration ,
195- } ,
196- ] )
197+ it ( 'should collect long task happening during a profiling session' , async ( ) => {
198+ const clock = mockClock ( )
199+ const { profiler, profilingContextManager, longTaskContexts } = setupProfiler ( )
197200
201+ // Start collection of profile.
198202 profiler . start ( )
199-
200203 await waitForBoolean ( ( ) => profiler . isRunning ( ) )
201204
202205 expect ( profilingContextManager . get ( ) ?. status ) . toBe ( 'running' )
206+ longTaskContexts . addLongTask ( {
207+ id : 'long-task-id-1' ,
208+ startClocks : clocksNow ( ) ,
209+ duration : 50 as Duration ,
210+ entryType : RumPerformanceEntryType . LONG_ANIMATION_FRAME ,
211+ } )
212+ clock . tick ( 50 )
203213
204- // Notify Profiler that some long tasks have been collected (via its PerformanceObserver)
205- notifyPerformanceEntries ( [
206- createPerformanceEntry ( RumPerformanceEntryType . LONG_ANIMATION_FRAME , {
207- startTime : 12345 as RelativeTime ,
208- entryType : RumPerformanceEntryType . LONG_ANIMATION_FRAME ,
209- } ) ,
210- ] )
214+ longTaskContexts . addLongTask ( {
215+ id : 'long-task-id-2' ,
216+ startClocks : clocksNow ( ) ,
217+ duration : 100 as Duration ,
218+ entryType : RumPerformanceEntryType . LONG_ANIMATION_FRAME ,
219+ } )
211220
212- // Stop collection of profile.
221+ // Stop first profiling session.
222+ clock . tick ( 105 )
213223 await profiler . stop ( )
224+ await waitForBoolean ( ( ) => profiler . isStopped ( ) )
214225
215- // Wait for stop of collection.
226+ // start a new profiling session
227+ profiler . start ( )
228+ await waitForBoolean ( ( ) => profiler . isRunning ( ) )
229+
230+ longTaskContexts . addLongTask ( {
231+ id : 'long-task-id-3' ,
232+ startClocks : clocksNow ( ) ,
233+ duration : 100 as Duration ,
234+ entryType : RumPerformanceEntryType . LONG_ANIMATION_FRAME ,
235+ } )
236+
237+ clock . tick ( 500 )
238+
239+ // stop the second profiling session
240+ await profiler . stop ( )
216241 await waitForBoolean ( ( ) => profiler . isStopped ( ) )
217242
243+ expect ( interceptor . requests . length ) . toBe ( 2 )
218244 expect ( profilingContextManager . get ( ) ?. status ) . toBe ( 'stopped' )
219245
220- const request = await readFormDataRequest < ProfileEventPayload > ( interceptor . requests [ 0 ] )
221- const trace = request [ 'wall-time.json' ]
246+ const requestOne = await readFormDataRequest < ProfileEventPayload > ( interceptor . requests [ 0 ] )
247+ const requestTwo = await readFormDataRequest < ProfileEventPayload > ( interceptor . requests [ 1 ] )
222248
223- expect ( request . event . long_task ?. id . length ) . toBe ( 1 )
224- expect ( trace . longTasks [ 0 ] . id ) . toBeDefined ( )
225- expect ( trace . longTasks [ 0 ] . startClocks . relative ) . toBe ( 12345 as RelativeTime )
249+ const traceOne = requestOne [ 'wall-time.json' ]
250+ const traceTwo = requestTwo [ 'wall-time.json' ]
251+
252+ expect ( requestOne . event . long_task ?. id . length ) . toBe ( 2 )
253+ expect ( traceOne . longTasks ) . toEqual ( [
254+ {
255+ id : 'long-task-id-2' ,
256+ startClocks : jasmine . any ( Object ) ,
257+ duration : 100 as Duration ,
258+ entryType : RumPerformanceEntryType . LONG_ANIMATION_FRAME ,
259+ } ,
260+ {
261+ id : 'long-task-id-1' ,
262+ startClocks : jasmine . any ( Object ) ,
263+ duration : 50 as Duration ,
264+ entryType : RumPerformanceEntryType . LONG_ANIMATION_FRAME ,
265+ } ,
266+ ] )
267+
268+ expect ( requestTwo . event . long_task ?. id . length ) . toBe ( 1 )
269+ expect ( traceTwo . longTasks ) . toEqual ( [
270+ {
271+ id : 'long-task-id-3' ,
272+ startClocks : jasmine . any ( Object ) ,
273+ duration : 100 as Duration ,
274+ entryType : RumPerformanceEntryType . LONG_ANIMATION_FRAME ,
275+ } ,
276+ ] )
226277 } )
227278
228279 it ( 'should collect views and set default view name in the Profile' , async ( ) => {
0 commit comments