Skip to content

Commit b6da94a

Browse files
fix(ttd): Equalize TTID and TTFD duration when TTFD manual API is called and resolved before auto TTID (#4680)
1 parent 7dca19f commit b6da94a

File tree

4 files changed

+45
-10
lines changed

4 files changed

+45
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
- Handle non-string category in getCurrentScreen on iOS ([#4629](https://github.com/getsentry/sentry-react-native/pull/4629))
4444
- Use route name instead of route key for current route tracking ([#4650](https://github.com/getsentry/sentry-react-native/pull/4650))
4545
- Using key caused user interaction transaction names to contain route hash in the name.
46+
- Equalize TTID and TTFD duration when TTFD manual API is called and resolved before auto TTID ([#4680](https://github.com/getsentry/sentry-react-native/pull/4680))
4647

4748
### Dependencies
4849

packages/core/src/js/tracing/reactnavigation.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ import {
3232
getDefaultIdleNavigationSpanOptions,
3333
startIdleNavigationSpan as startGenericIdleNavigationSpan,
3434
} from './span';
35-
import { manualInitialDisplaySpans, startTimeToInitialDisplaySpan } from './timetodisplay';
36-
import { setSpanDurationAsMeasurementOnSpan } from './utils';
35+
import { manualInitialDisplaySpans, startTimeToInitialDisplaySpan, updateInitialDisplaySpan } from './timetodisplay';
3736
export const INTEGRATION_NAME = 'ReactNavigation';
3837

3938
const NAVIGATION_HISTORY_MAX_SIZE = 200;
@@ -297,9 +296,10 @@ export const reactNavigationIntegration = ({
297296
return;
298297
}
299298

300-
latestTtidSpan.setStatus({ code: SPAN_STATUS_OK });
301-
latestTtidSpan.end(newFrameTimestampInSeconds);
302-
setSpanDurationAsMeasurementOnSpan('time_to_initial_display', latestTtidSpan, navigationSpanWithTtid);
299+
updateInitialDisplaySpan(newFrameTimestampInSeconds, {
300+
activeSpan: navigationSpanWithTtid,
301+
span: latestTtidSpan,
302+
});
303303
});
304304
}
305305

packages/core/src/js/tracing/timetodisplay.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { isTurboModuleEnabled } from '../utils/environment';
66
import { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from './origin';
77
import { getRNSentryOnDrawReporter, nativeComponentExists } from './timetodisplaynative';
88
import type {RNSentryOnDrawNextFrameEvent } from './timetodisplaynative.types';
9-
import { setSpanDurationAsMeasurement } from './utils';
9+
import { setSpanDurationAsMeasurement, setSpanDurationAsMeasurementOnSpan } from './utils';
1010

1111
let nativeComponentMissingLogged = false;
1212

@@ -206,14 +206,26 @@ function onDrawNextFrame(event: { nativeEvent: RNSentryOnDrawNextFrameEvent }):
206206
}
207207
}
208208

209-
function updateInitialDisplaySpan(frameTimestampSeconds: number): void {
210-
const span = startTimeToInitialDisplaySpan();
209+
/**
210+
*
211+
*/
212+
export function updateInitialDisplaySpan(
213+
frameTimestampSeconds: number,
214+
{
215+
activeSpan = getActiveSpan(),
216+
span = startTimeToInitialDisplaySpan(),
217+
}: {
218+
activeSpan?: Span;
219+
/**
220+
* Time to initial display span to update.
221+
*/
222+
span?: Span;
223+
} = {}): void {
211224
if (!span) {
212225
logger.warn(`[TimeToDisplay] No span found or created, possibly performance is disabled.`);
213226
return;
214227
}
215228

216-
const activeSpan = getActiveSpan();
217229
if (!activeSpan) {
218230
logger.warn(`[TimeToDisplay] No active span found to attach ui.load.initial_display to.`);
219231
return;
@@ -239,7 +251,7 @@ function updateInitialDisplaySpan(frameTimestampSeconds: number): void {
239251
updateFullDisplaySpan(frameTimestampSeconds, span);
240252
}
241253

242-
setSpanDurationAsMeasurement('time_to_initial_display', span);
254+
setSpanDurationAsMeasurementOnSpan('time_to_initial_display', span, activeSpan);
243255
}
244256

245257
function updateFullDisplaySpan(frameTimestampSeconds: number, passedInitialDisplaySpan?: Span): void {

packages/core/test/tracing/reactnavigation.ttid.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,28 @@ describe('React Navigation - TTID', () => {
351351
expect(getSpanDurationMs(transaction, 'ui.load.initial_display')).toEqual(transaction.measurements?.time_to_initial_display?.value);
352352
});
353353

354+
test('ttfd span duration and measurement should equal ttid from ttfd is called earlier than ttid', () => {
355+
jest.runOnlyPendingTimers(); // Flush app start transaction
356+
357+
mockedNavigation.navigateToNewScreen();
358+
TestRenderer.render(<TimeToFullDisplay record />);
359+
emitNativeFullDisplayEvent();
360+
mockedEventEmitter.emitNewFrameEvent();
361+
362+
jest.runOnlyPendingTimers(); // Flush navigation transaction
363+
364+
const transaction = getLastTransaction(transportSendMock);
365+
const ttfdSpanDuration = getSpanDurationMs(transaction, 'ui.load.full_display');
366+
const ttidSpanDuration = getSpanDurationMs(transaction, 'ui.load.initial_display');
367+
expect(ttfdSpanDuration).toBeDefined();
368+
expect(ttidSpanDuration).toBeDefined();
369+
expect(ttfdSpanDuration).toEqual(ttidSpanDuration);
370+
371+
expect(transaction.measurements?.time_to_full_display?.value).toBeDefined();
372+
expect(transaction.measurements?.time_to_initial_display?.value).toBeDefined();
373+
expect(transaction.measurements?.time_to_full_display?.value).toEqual(transaction.measurements?.time_to_initial_display?.value);
374+
});
375+
354376
test('ttfd span duration and measurement should equal for application start up', () => {
355377
mockedNavigation.finishAppStartNavigation();
356378
mockedEventEmitter.emitNewFrameEvent();

0 commit comments

Comments
 (0)