Skip to content
Open
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
12 changes: 12 additions & 0 deletions packages/core/__mocks__/react-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ actualRN.NativeModules.DdRum = {
addTiming: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['addTiming']>,
addViewAttribute: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['addViewAttribute']>,
removeViewAttribute: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['removeViewAttribute']>,
addViewAttributes: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['addViewAttributes']>,
removeViewAttributes: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['removeViewAttributes']>,
addViewLoadingTime: jest.fn().mockImplementation(
() => new Promise<void>(resolve => resolve())
) as jest.MockedFunction<DdRumType['addViewLoadingTime']>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.datadog.android.rum.RumErrorSource
import com.datadog.android.rum.RumResourceKind
import com.datadog.android.rum.RumResourceMethod
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap
import java.util.Locale

Expand Down Expand Up @@ -248,6 +249,49 @@ class DdRumImplementation(private val datadog: DatadogWrapper = DatadogSDKWrappe
promise.resolve(null)
}

/**
* Adds a custom attribute to the active RUM View. It will be propagated to all future RUM events associated with the active View.
* @param key: key for this view attribute.
* @param value: value for this attribute.
*/
fun addViewAttribute(key: String, value: ReadableMap, promise: Promise) {
val attributeValue = value.toMap()["value"]
val attributes = mutableMapOf<String, Any?>()
attributes[key] = attributeValue
datadog.getRumMonitor().addViewAttributes(attributes)
promise.resolve(null)
}

/**
* Removes an attribute from the active RUM View.
* @param key: key for the attribute to be removed from the view.
*/
fun removeViewAttribute(key: String, promise: Promise) {
val keysToDelete: Collection<String> = listOf(key)
datadog.getRumMonitor().removeViewAttributes(keysToDelete)
promise.resolve(null)
}

/**
* Adds multiple attributes to the active RUM View. They will be propagated to all future RUM events associated with the active View.
* @param attributes: key/value object containing all attributes to be added to the view.
*/
fun addViewAttributes(attributes: ReadableMap, promise: Promise) {
datadog.getRumMonitor().addViewAttributes(attributes.toMap())
promise.resolve(null)
}

/**
* Removes multiple attributes from the active RUM View.
* @param keys: keys for the attributes to be removed from the view.
*/
fun removeViewAttributes(keys: ReadableArray, promise: Promise) {
val keysToDelete = (0 until keys.size())
.mapNotNull { keys.getString(it) }
datadog.getRumMonitor().removeViewAttributes(keysToDelete)
promise.resolve(null)
}

/**
* Adds the loading time of the view to the active view.
* It is calculated as the difference between the current time and the start time of the view.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ class DdSdkImplementation(

if (id != null) {
datadog.setUserInfo(id, name, email, extraInfo)
} else {
// TO DO - Log warning?
}

promise.resolve(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.datadog.reactnative
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap

/**
Expand Down Expand Up @@ -201,6 +202,43 @@ class DdRum(
implementation.addTiming(name, promise)
}

/**
* Adds a custom attribute to the active RUM View. It will be propagated to all future RUM events associated with the active View.
* @param key: key for this view attribute.
* @param value: value for this attribute.
*/
@ReactMethod
override fun addViewAttribute(key: String, value: ReadableMap, promise: Promise) {
implementation.addViewAttribute(key, value, promise)
}

/**
* Removes an attribute from the active RUM View.
* @param key: key for the attribute to be removed from the view.
*/
@ReactMethod
override fun removeViewAttribute(key: String, promise: Promise) {
implementation.removeViewAttribute(key, promise)
}

/**
* Adds multiple attributes to the active RUM View. They will be propagated to all future RUM events associated with the active View.
* @param attributes: key/value object containing all attributes to be added to the view.
*/
@ReactMethod
override fun addViewAttributes(attributes: ReadableMap, promise: Promise) {
implementation.addViewAttributes(attributes, promise)
}

/**
* Removes multiple attributes from the active RUM View.
* @param keys: keys for the attributes to be removed from the view.
*/
@ReactMethod
override fun removeViewAttributes(keys: ReadableArray, promise: Promise) {
implementation.removeViewAttributes(keys, promise)
}

/**
* Adds the loading time of the view to the active view.
* It is calculated as the difference between the current time and the start time of the view.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
/** The entry point to initialize Datadog's features. */
class DdSdk(
reactContext: ReactApplicationContext,
datadogWrapper: DatadogWrapper = DatadogSDKWrapper()
datadogWrapper: DatadogWrapper = DatadogSDKWrapper(),
ddTelemetry: DdTelemetry = DdTelemetry()
) : NativeDdSdkSpec(reactContext) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap

/**
Expand Down Expand Up @@ -192,6 +193,43 @@ class DdRum(
implementation.addTiming(name, promise)
}

/**
* Adds a custom attribute to the active RUM View. It will be propagated to all future RUM events associated with the active View.
* @param key: key for this view attribute.
* @param value: value for this attribute.
*/
@ReactMethod
fun addViewAttribute(key: String, value: ReadableMap, promise: Promise) {
implementation.addViewAttribute(key, value, promise)
}

/**
* Removes an attribute from the active RUM View.
* @param key: key for the attribute to be removed from the view.
*/
@ReactMethod
fun removeViewAttribute(key: String, promise: Promise) {
implementation.removeViewAttribute(key, promise)
}

/**
* Adds multiple attributes to the active RUM View. They will be propagated to all future RUM events associated with the active View.
* @param attributes: key/value object containing all attributes to be added to the view.
*/
@ReactMethod
fun addViewAttributes(attributes: ReadableMap, promise: Promise) {
implementation.addViewAttributes(attributes, promise)
}

/**
* Removes multiple attributes from the active RUM View.
* @param keys: keys for the attributes to be removed from the view.
*/
@ReactMethod
fun removeViewAttributes(keys: ReadableArray, promise: Promise) {
implementation.removeViewAttributes(keys, promise)
}

/**
* Adds the loading time of the view to the active view.
* It is calculated as the difference between the current time and the start time of the view.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import com.datadog.android.rum.RumMonitor
import com.datadog.android.rum.RumResourceKind
import com.datadog.android.rum.RumResourceMethod
import com.datadog.tools.unit.forge.BaseConfigurator
import com.datadog.tools.unit.toReadableArray
import com.datadog.tools.unit.toReadableMap
import com.facebook.react.bridge.Promise
import fr.xgouchet.elmyr.Forge
import fr.xgouchet.elmyr.annotation.AdvancedForgery
import fr.xgouchet.elmyr.annotation.BoolForgery
import fr.xgouchet.elmyr.annotation.DoubleForgery
import fr.xgouchet.elmyr.annotation.Forgery
import fr.xgouchet.elmyr.annotation.IntForgery
import fr.xgouchet.elmyr.annotation.MapForgery
import fr.xgouchet.elmyr.annotation.StringForgery
import fr.xgouchet.elmyr.annotation.StringForgeryType
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
Expand Down Expand Up @@ -456,6 +459,61 @@ internal class DdRumTest {
verify(mockRumMonitor).addTiming(timing)
}

@Test
fun `M call addViewAttribute W addViewAttribute()`(
@StringForgery key: String,
@StringForgery value: String
) {
var attributeMap = mutableMapOf<String, Any?>()
attributeMap.put("value", value)

var attributes = mutableMapOf<String, Any?>()
attributes.put(key, value)

// When
testedDdRum.addViewAttribute(key, attributeMap.toReadableMap(), mockPromise)

// Then
verify(mockRumMonitor).addViewAttributes(attributes)
}

@Test
fun `M call removeViewAttribute W removeViewAttribute()`(@StringForgery key: String) {
// When
testedDdRum.removeViewAttribute(key, mockPromise)

// Then
verify(mockRumMonitor).removeViewAttributes(listOf(key))
}

@Test
fun `M call addViewAttributes W addViewAttributes()`(
@MapForgery(
key = AdvancedForgery(string = [StringForgery(StringForgeryType.NUMERICAL)]),
value = AdvancedForgery(string = [StringForgery(StringForgeryType.ASCII)])
) customAttributes: Map<String, String>
) {
// When
testedDdRum.addViewAttributes(customAttributes.toReadableMap(), mockPromise)

// Then
verify(mockRumMonitor).addViewAttributes(customAttributes)
}

@Test
fun `𝕄 call removeViewAttributes 𝕎 removeViewAttributes`(
@MapForgery(
key = AdvancedForgery(string = [StringForgery(StringForgeryType.NUMERICAL)]),
value = AdvancedForgery(string = [StringForgery(StringForgeryType.ASCII)])
) customAttributes: Map<String, String>
) {
// When
testedDdRum.removeViewAttributes(customAttributes.keys.toReadableArray(), mockPromise)

// Then
verify(mockRumMonitor).removeViewAttributes(customAttributes.keys.toList())
}

@Test
fun `M call addViewLoadingTime w addViewLoadingTime()`(@BoolForgery overwrite: Boolean) {
// When
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ class MockRumMonitor : RumMonitor {

override fun addAttribute(key: String, value: Any?) {}

override fun addViewAttributes(attributes: Map<String, Any?>) {}
override fun removeAttribute(key: String) {}

override fun clearAttributes() {}

override fun getAttributes(): Map<String, Any?> {
return mapOf()
}

override fun addError(
message: String,
Expand All @@ -55,15 +61,10 @@ class MockRumMonitor : RumMonitor {
@ExperimentalRumApi
override fun addViewLoadingTime(overwrite: Boolean) {}

override fun clearAttributes() {}

override fun getAttributes(): Map<String, Any?> {
return mapOf()
}

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

override fun removeAttribute(key: String) {}
override fun addViewAttributes(attributes: Map<String, Any?>) {}

override fun removeViewAttributes(attributes: Collection<String>) {}

override fun startAction(
Expand Down
21 changes: 14 additions & 7 deletions packages/core/ios/Sources/AnyEncodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ internal func castAttributesToSwift(_ attributes: [String: Any]) -> [String: Enc
var casted: [String: Encodable] = [:]

attributes.forEach { key, value in
if let castedValue = castByPreservingTypeInformation(attributeValue: value) {
// If possible, cast attribute by preserving its type information
casted[key] = castedValue
} else {
// Otherwise, cast by preserving its encoded value (and loosing type information)
casted[key] = castByPreservingEncodedValue(attributeValue: value)
}
casted[key] = castValueToSwift(value)
}

return casted
}

internal func castValueToSwift(_ value: Any) -> Encodable {
var casted: Encodable
if let castedValue = castByPreservingTypeInformation(attributeValue: value) {
// If possible, cast attribute by preserving its type information
casted = castedValue
} else {
// Otherwise, cast by preserving its encoded value (and loosing type information)
casted = castByPreservingEncodedValue(attributeValue: value)
}

return casted
Expand Down
Loading