Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions example-new-architecture/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ import {APPLICATION_ID, CLIENT_TOKEN, ENVIRONMENT} from './ddCredentials';

const spanId = await DdTrace.startSpan('test span');
await DdTrace.finishSpan(spanId);

setTimeout(async () => {
await DdRum.reportAppFullyDisplayed();
}, 5000);
})();

function AppWithProviders() {
Expand Down
9 changes: 9 additions & 0 deletions example/src/ddUtils.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
DatadogProviderConfiguration,
DdLogs,
DdRum,
DdSdkReactNative,
CoreConfiguration,
SdkVerbosity,
Expand Down Expand Up @@ -61,6 +62,10 @@ export function getDatadogConfig(trackingConsent: TrackingConsent) {
DdLogs.info('The RN Sdk was properly initialized')
DdSdkReactNative.setUserInfo({id: "1337", name: "Xavier", email: "xg@example.com", extraInfo: { type: "premium" } })
DdSdkReactNative.addAttributes({campaign: "ad-network"})

setTimeout(async () => {
await DdRum.reportAppFullyDisplayed();
}, 5000);
}

// Legacy SDK Setup
Expand Down Expand Up @@ -93,6 +98,10 @@ export function initializeDatadog(trackingConsent: TrackingConsent) {
DdLogs.info('The RN Sdk was properly initialized')
DdSdkReactNative.setUserInfo({id: "1337", name: "Xavier", email: "xg@example.com", extraInfo: { type: "premium" } })
DdSdkReactNative.addAttributes({campaign: "ad-network"})

setTimeout(async () => {
await DdRum.reportAppFullyDisplayed();
}, 5000);
});

// Enable the Flags feature.
Expand Down
3 changes: 3 additions & 0 deletions packages/core/__mocks__/react-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ actualRN.NativeModules.DdRum = {
addViewLoadingTime: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['addViewLoadingTime']>,
reportAppFullyDisplayed: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['reportAppFullyDisplayed']>,
stopSession: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['stopSession']>,
Expand Down
1 change: 1 addition & 0 deletions packages/core/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ dependencies {
implementation "com.datadoghq:dd-sdk-android-webview:3.10.0"
implementation "com.datadoghq:dd-sdk-android-ndk:3.10.0"
implementation "com.datadoghq:dd-sdk-android-flags:3.10.0"
// implementation "com.datadoghq:dd-sdk-android-rum-prelaunch:3.10.0" // TO DO - Add module when bumping dd-sdk-android

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be uncommented once the android SDK is updated with a version that includes the prelaunch module.

implementation "com.google.code.gson:gson:2.11.0"
testImplementation "org.junit.platform:junit-platform-launcher:1.6.2"
testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,16 @@ class DdRumImplementation(private val datadog: DatadogWrapper = DatadogSDKWrappe
promise.resolve(null)
}

/**
* This method can be used to mark the moment in time when the UI of the app is considered fully displayed.
* The duration between the application launch and this moment of time will be shown as TTFD (time to full display)
* in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session.
*/
fun reportAppFullyDisplayed(promise: Promise) {
datadog.getRumMonitor().reportAppFullyDisplayed()
promise.resolve(null)
}

/**
* Stops the current RUM Session.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,16 @@ class DdRum(
implementation.addViewLoadingTime(overwrite, promise)
}

/**
* This method can be used to mark the moment in time when the UI of the app is considered fully displayed.
* The duration between the application launch and this moment of time will be shown as TTFD (time to full display)
* in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session.
*/
@ReactMethod
override fun reportAppFullyDisplayed(promise: Promise) {
implementation.reportAppFullyDisplayed(promise)
}

/**
* Stops the current RUM Session.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,16 @@ class DdRum(
implementation.addViewLoadingTime(overwrite, promise)
}

/**
* This method can be used to mark the moment in time when the UI of the app is considered fully displayed.
* The duration between the application launch and this moment of time will be shown as TTFD (time to full display)
* in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session.
*/
@ReactMethod
fun reportAppFullyDisplayed(promise: Promise) {
implementation.reportAppFullyDisplayed(promise)
}

/**
* Stops the current RUM Session.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,15 @@ internal class DdRumTest {
verify(mockRumMonitor).addViewLoadingTime(overwrite)
}

@Test
fun `M call reportAppFullyDisplayed w reportAppFullyDisplayed()`() {
// When
testedDdRum.reportAppFullyDisplayed(mockPromise)

// Then
verify(mockRumMonitor).reportAppFullyDisplayed()
}

@Test
fun `M call stopSession W stopSession()`() {
// When
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class MockRumMonitor : RumMonitor {
@ExperimentalRumApi
override fun addViewLoadingTime(overwrite: Boolean) {}

@ExperimentalRumApi
override fun reportAppFullyDisplayed() {}

override fun getCurrentSessionId(callback: (String?) -> Unit) {}

override fun addViewAttributes(attributes: Map<String, Any?>) {}
Expand Down Expand Up @@ -172,7 +175,4 @@ class MockRumMonitor : RumMonitor {
failureReason: OperationFailureReason,
attributes: Map<String, Any?>
) {}

@ExperimentalRumApi
override fun reportAppFullyDisplayed() {}
}
14 changes: 13 additions & 1 deletion packages/core/ios/Sources/DdRum.mm
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,15 @@ @implementation DdRum
[self addViewLoadingTime:overwrite resolve:resolve reject:reject];
}

RCT_REMAP_METHOD(stopSession, withResolve:(RCTPromiseResolveBlock)resolve
RCT_EXPORT_METHOD(reportAppFullyDisplayed:
(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
{
[self reportAppFullyDisplayed: resolve reject:reject];
}

RCT_EXPORT_METHOD(stopSession:
(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
{
[self stopSession:resolve reject:reject];
Expand Down Expand Up @@ -262,6 +270,10 @@ - (void)addViewLoadingTime:(BOOL)overwrite resolve:(RCTPromiseResolveBlock)resol
[self.ddRumImplementation addViewLoadingTimeWithOverwrite:overwrite resolve:resolve reject:reject];
}

- (void)reportAppFullyDisplayed:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[self.ddRumImplementation reportAppFullyDisplayedWithResolve:resolve reject: reject];
}

- (void)startAction:(NSString *)type name:(NSString *)name context:(NSDictionary *)context timestampMs:(double)timestampMs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
[self.ddRumImplementation startActionWithType:type name:name context:context timestampMs:timestampMs resolve:resolve reject:reject];
}
Expand Down
6 changes: 6 additions & 0 deletions packages/core/ios/Sources/DdRumImplementation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ public class DdRumImplementation: NSObject {
resolve(nil)
}

@objc
public func reportAppFullyDisplayed(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
nativeRUM.reportAppFullyDisplayed()
resolve(nil)
}

@objc
public func stopSession(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
nativeRUM.stopSession()
Expand Down
8 changes: 8 additions & 0 deletions packages/core/ios/Tests/DdRumTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,14 @@ internal class DdRumTests: XCTestCase {
XCTAssertEqual(mockNativeRUM.receivedAttributes.count, 0)
}

func testReportAppFullyDisplayed() throws {
rum.reportAppFullyDisplayed(resolve: mockResolve, reject: mockReject)

XCTAssertEqual(mockNativeRUM.calledMethods.count, 1)
XCTAssertEqual(mockNativeRUM.calledMethods.last, .reportAppFullyDisplayed())
XCTAssertEqual(mockNativeRUM.receivedAttributes.count, 0)
}

func testStopSession() throws {
rum.stopSession(resolve: mockResolve, reject: mockReject)

Expand Down
8 changes: 4 additions & 4 deletions packages/core/ios/Tests/MockRUMMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
@testable import DatadogSDKReactNative

internal class MockRUMMonitor: RUMMonitorProtocol {
func reportAppFullyDisplayed() {
// not implemented
}

func currentSessionID(completion: @escaping (String?) -> Void) {
// not implemented
}
Expand Down Expand Up @@ -69,6 +65,7 @@ internal class MockRUMMonitor: RUMMonitorProtocol {
case addViewAttributes(_: Int? = nil) // We need an attribute for the case to be Equatable
case removeViewAttributes(keys: [String])
case addViewLoadingTime(overwrite: Bool)
case reportAppFullyDisplayed(_: Int? = nil) // We need an attribute for the case to be Equatable
case stopSession(_: Int? = nil) // We need an attribute for the case to be Equatable
case addResourceMetrics(resourceKey: String,
fetch: Interval,
Expand Down Expand Up @@ -151,6 +148,9 @@ internal class MockRUMMonitor: RUMMonitorProtocol {
func addViewLoadingTime(overwrite: Bool) {
calledMethods.append(.addViewLoadingTime(overwrite: overwrite))
}
func reportAppFullyDisplayed() {
calledMethods.append(.reportAppFullyDisplayed())
}
func stopSession() {
calledMethods.append(.stopSession())
}
Expand Down
3 changes: 3 additions & 0 deletions packages/core/jest/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ module.exports = {
addViewLoadingTime: jest
.fn()
.mockImplementation(() => new Promise(resolve => resolve())),
reportAppFullyDisplayed: jest
.fn()
.mockImplementation(() => new Promise(resolve => resolve())),
addFeatureFlagEvaluation: jest
.fn()
.mockImplementation(() => new Promise(resolve => resolve())),
Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/rum/DdRum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,16 @@ class DdRumWrapper implements DdRumType {
);
};

reportAppFullyDisplayed = (): Promise<void> => {
InternalLog.log(
'Reporting App Fully Displayed (TTFD)',
SdkVerbosity.DEBUG
);
return bufferVoidNativeCall(() =>
this.nativeRum.reportAppFullyDisplayed()
);
};

stopSession = (): Promise<void> => {
InternalLog.log('Stopping RUM Session', SdkVerbosity.DEBUG);
clearCachedSessionId();
Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/rum/__tests__/DdRum.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,16 @@ describe('DdRum', () => {
});
});

describe('DdRum.reportAppFullyDisplayed', () => {
it('calls the native API', async () => {
await DdRum.reportAppFullyDisplayed();

expect(
NativeModules.DdRum.reportAppFullyDisplayed
).toHaveBeenCalledTimes(1);
});
});

describe('PropagatorTypes', () => {
it('matches with the native name of propagators', () => {
/**
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/rum/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ export type DdRumType = {
*/
addViewLoadingTime(overwrite: boolean): Promise<void>;

/**
* This method can be used to mark the moment in time when the UI of the app is considered fully displayed.
* The duration between the application launch and this moment of time will be shown as TTFD (time to full display)
* in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session.
*/
reportAppFullyDisplayed(): Promise<void>;

/**
* Stops the current RUM Session.
*/
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/specs/NativeDdRum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ export interface Spec extends TurboModule {
*/
addViewLoadingTime(overwrite: boolean): Promise<void>;

/**
* This method can be used to mark the moment in time when the UI of the app is considered fully displayed.
* The duration between the application launch and this moment of time will be shown as TTFD (time to full display)
* in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session.
*/
reportAppFullyDisplayed(): Promise<void>;

/**
* Stops the current RUM Session.
*/
Expand Down