@@ -26,6 +26,15 @@ jest.mock('../../src/js/tracing/utils', () => {
2626 } ;
2727} ) ;
2828
29+ jest . mock ( '@sentry/utils' , ( ) => {
30+ const originalUtils = jest . requireActual ( '@sentry/utils' ) ;
31+
32+ return {
33+ ...originalUtils ,
34+ timestampInSeconds : jest . fn ( originalUtils . timestampInSeconds ) ,
35+ } ;
36+ } ) ;
37+
2938type MockAppState = {
3039 setState : ( state : AppStateStatus ) => void ;
3140 listener : ( newState : AppStateStatus ) => void ;
@@ -51,6 +60,7 @@ jest.mock('react-native/Libraries/AppState/AppState', () => mockedAppState);
5160
5261import { getActiveSpan , startSpanManual } from '@sentry/browser' ;
5362import { addGlobalEventProcessor , getCurrentHub , getCurrentScope , spanToJSON , startInactiveSpan } from '@sentry/core' ;
63+ import { timestampInSeconds } from '@sentry/utils' ;
5464import type { AppState , AppStateStatus } from 'react-native' ;
5565
5666import { APP_START_COLD , APP_START_WARM } from '../../src/js/measurements' ;
@@ -70,6 +80,8 @@ import { mockFunction } from '../testutils';
7080import type { MockedRoutingInstrumentation } from './mockedrountinginstrumention' ;
7181import { createMockedRoutingInstrumentation } from './mockedrountinginstrumention' ;
7282
83+ const originalTimestampInSeconds = mockFunction ( timestampInSeconds ) . getMockImplementation ( ) ;
84+
7385const DEFAULT_IDLE_TIMEOUT = 1000 ;
7486
7587describe ( 'ReactNativeTracing' , ( ) => {
@@ -317,6 +329,65 @@ describe('ReactNativeTracing', () => {
317329 expect ( transaction ?. start_timestamp ) . toBeGreaterThanOrEqual ( timeOriginMilliseconds / 1000 ) ;
318330 } ) ;
319331
332+ describe ( 'old app starts' , ( ) => {
333+ let integration : ReactNativeTracing ;
334+ let timeOriginMilliseconds : number ;
335+
336+ beforeEach ( ( ) => {
337+ integration = new ReactNativeTracing ( ) ;
338+
339+ timeOriginMilliseconds = Date . now ( ) ;
340+ const appStartTimeMilliseconds = timeOriginMilliseconds - 65000 ;
341+ const mockAppStartResponse : NativeAppStartResponse = {
342+ type : 'warm' ,
343+ app_start_timestamp_ms : appStartTimeMilliseconds ,
344+ has_fetched : false ,
345+ spans : [ ] ,
346+ } ;
347+
348+ // App start finish timestamp
349+ mockFunction ( getTimeOriginMilliseconds ) . mockReturnValue ( timeOriginMilliseconds - 64000 ) ;
350+ mockFunction ( NATIVE . fetchNativeAppStart ) . mockResolvedValue ( mockAppStartResponse ) ;
351+ // Transaction start timestamp
352+ mockFunction ( timestampInSeconds ) . mockReturnValue ( timeOriginMilliseconds / 1000 + 65 ) ;
353+ } ) ;
354+
355+ afterEach ( ( ) => {
356+ mockFunction ( timestampInSeconds ) . mockReset ( ) . mockImplementation ( originalTimestampInSeconds ) ;
357+ set__DEV__ ( true ) ;
358+ } ) ;
359+
360+ it ( 'Does not add app start span older than than 60s in production' , async ( ) => {
361+ set__DEV__ ( false ) ;
362+
363+ setup ( integration ) ;
364+
365+ await jest . advanceTimersByTimeAsync ( 500 ) ;
366+ await jest . runOnlyPendingTimersAsync ( ) ;
367+
368+ const transaction = client . event ;
369+
370+ expect ( transaction ) . toBeDefined ( ) ;
371+ expect ( transaction ?. spans ?. some ( span => span . op == APP_SPAN_START_WARM ) ) . toBeFalse ( ) ;
372+ expect ( transaction ?. start_timestamp ) . toBeGreaterThanOrEqual ( timeOriginMilliseconds / 1000 ) ;
373+ } ) ;
374+
375+ it ( 'Does add app start span older than than 60s in development builds' , async ( ) => {
376+ set__DEV__ ( true ) ;
377+
378+ setup ( integration ) ;
379+
380+ await jest . advanceTimersByTimeAsync ( 500 ) ;
381+ await jest . runOnlyPendingTimersAsync ( ) ;
382+
383+ const transaction = client . event ;
384+
385+ expect ( transaction ) . toBeDefined ( ) ;
386+ expect ( transaction ?. spans ?. some ( span => span . op == APP_SPAN_START_WARM ) ) . toBeTrue ( ) ;
387+ expect ( transaction ?. start_timestamp ) . toBeGreaterThanOrEqual ( ( timeOriginMilliseconds - 65000 ) / 1000 ) ;
388+ } ) ;
389+ } ) ;
390+
320391 it ( 'Does not create app start transaction if has_fetched == true' , async ( ) => {
321392 const integration = new ReactNativeTracing ( ) ;
322393
@@ -1195,3 +1266,10 @@ function clearReactNativeBundleExecutionStartTimestamp() {
11951266 delete RN_GLOBAL_OBJ . nativePerformanceNow ;
11961267 delete RN_GLOBAL_OBJ . __BUNDLE_START_TIME__ ;
11971268}
1269+
1270+ function set__DEV__ ( value : boolean ) {
1271+ Object . defineProperty ( globalThis , '__DEV__' , {
1272+ value,
1273+ writable : true ,
1274+ } ) ;
1275+ }
0 commit comments