diff --git a/packages/codepush/package.json b/packages/codepush/package.json
index c46cdd5c0..11baa544e 100644
--- a/packages/codepush/package.json
+++ b/packages/codepush/package.json
@@ -38,7 +38,7 @@
"prepare": "rm -rf lib && yarn bob build"
},
"devDependencies": {
- "@datadog/mobile-react-native": "^2.8.0",
+ "@datadog/mobile-react-native": "workspace:packages/core",
"@testing-library/react-native": "7.0.2",
"react-native-builder-bob": "0.26.0",
"react-native-code-push": "7.1.0"
diff --git a/packages/codepush/src/__tests__/index.test.tsx b/packages/codepush/src/__tests__/index.test.tsx
index c6172bf5f..5c94c16ef 100644
--- a/packages/codepush/src/__tests__/index.test.tsx
+++ b/packages/codepush/src/__tests__/index.test.tsx
@@ -1,14 +1,8 @@
-import {
- DdSdkReactNative,
- DdSdkReactNativeConfiguration,
- DatadogProviderConfiguration
-} from '@datadog/mobile-react-native';
-import { render } from '@testing-library/react-native';
-import codePush from 'react-native-code-push';
+/* eslint-disable @typescript-eslint/no-var-requires */
+/* eslint-disable global-require */
+import { render, waitFor } from '@testing-library/react-native';
import React from 'react';
-import { DatadogCodepush, DatadogCodepushProvider } from '..';
-
jest.mock('react-native-code-push', () => ({
getUpdateMetadata: jest.fn()
}));
@@ -16,7 +10,10 @@ jest.mock('react-native-code-push', () => ({
jest.mock('@datadog/mobile-react-native', () => {
const actualPackage = jest.requireActual('@datadog/mobile-react-native');
actualPackage.DdSdkReactNative.initialize = jest.fn();
+ actualPackage.DdSdkReactNative._enableFeaturesFromDatadogProvider = jest.fn();
+ actualPackage.DdSdkReactNative._enableFeaturesFromDatadogProviderAsync = jest.fn();
actualPackage.DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync = jest.fn();
+ actualPackage.DdSdkReactNative._initializeFromDatadogProvider = jest.fn();
return actualPackage;
});
@@ -41,8 +38,16 @@ describe('AppCenter Codepush integration', () => {
beforeEach(() => {
jest.clearAllMocks();
});
+
describe('initialize', () => {
it('initializes the SDK with the correct version when using a CodePush bundle', async () => {
+ const codePush = require('react-native-code-push');
+ const { DatadogCodepush } = require('..');
+ const {
+ DdSdkReactNativeConfiguration,
+ DdSdkReactNative
+ } = require('@datadog/mobile-react-native');
+
(codePush.getUpdateMetadata as jest.MockedFunction<
typeof codePush.getUpdateMetadata
>).mockResolvedValueOnce(createCodepushPackageMock('v3'));
@@ -65,6 +70,13 @@ describe('AppCenter Codepush integration', () => {
});
it('initializes the SDK with the correct version when not using a CodePush bundle', async () => {
+ const codePush = require('react-native-code-push');
+ const { DatadogCodepush } = require('..');
+ const {
+ DdSdkReactNativeConfiguration,
+ DdSdkReactNative
+ } = require('@datadog/mobile-react-native');
+
(codePush.getUpdateMetadata as jest.MockedFunction<
typeof codePush.getUpdateMetadata
>).mockResolvedValueOnce(null);
@@ -92,7 +104,19 @@ describe('AppCenter Codepush integration', () => {
});
describe('DatadogCodepushProvider', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ jest.resetModules();
+ });
+
it('initializes the sdk with the right codepush version when using DatadogProviderConfiguration', async () => {
+ const codePush = require('react-native-code-push');
+ const { DatadogCodepushProvider } = require('..');
+ const {
+ DatadogProviderConfiguration,
+ DdSdkReactNative
+ } = require('@datadog/mobile-react-native');
+
(codePush.getUpdateMetadata as jest.MockedFunction<
typeof codePush.getUpdateMetadata
>).mockResolvedValueOnce(createCodepushPackageMock('v4'));
@@ -118,6 +142,12 @@ describe('AppCenter Codepush integration', () => {
);
});
it('initializes the sdk with the right codepush version when using partial configuration', async () => {
+ const codePush = require('react-native-code-push');
+ const { DatadogCodepushProvider } = require('..');
+ const {
+ DdSdkReactNative
+ } = require('@datadog/mobile-react-native');
+
(codePush.getUpdateMetadata as jest.MockedFunction<
typeof codePush.getUpdateMetadata
>).mockResolvedValueOnce(createCodepushPackageMock('v5'));
@@ -149,7 +179,15 @@ describe('AppCenter Codepush integration', () => {
expect.objectContaining({ versionSuffix: 'codepush.v5' })
);
});
+
it('initializes the sdk with commercial version when using DatadogProviderConfiguration', async () => {
+ const codePush = require('react-native-code-push');
+ const { DatadogCodepushProvider } = require('..');
+ const {
+ DatadogProviderConfiguration,
+ DdSdkReactNative
+ } = require('@datadog/mobile-react-native');
+
(codePush.getUpdateMetadata as jest.MockedFunction<
typeof codePush.getUpdateMetadata
>).mockResolvedValueOnce(createCodepushPackageMock(null));
@@ -177,6 +215,12 @@ describe('AppCenter Codepush integration', () => {
).not.toContain('versionSuffix');
});
it('initializes the sdk with commercial version when using partial configuration', async () => {
+ const codePush = require('react-native-code-push');
+ const { DatadogCodepushProvider } = require('..');
+ const {
+ DdSdkReactNative
+ } = require('@datadog/mobile-react-native');
+
(codePush.getUpdateMetadata as jest.MockedFunction<
typeof codePush.getUpdateMetadata
>).mockResolvedValueOnce(createCodepushPackageMock(null));
@@ -210,5 +254,139 @@ describe('AppCenter Codepush integration', () => {
)
).not.toContain('versionSuffix');
});
+
+ it('initializes the DatadogProvider with FileBasedConfiguration & all parameters', async () => {
+ const { DatadogCodepushProvider } = require('..');
+ const {
+ DdSdkReactNative,
+ PropagatorType,
+ FileBasedConfiguration
+ } = require('@datadog/mobile-react-native');
+
+ const autoInstrumentationConfig = {
+ trackErrors: true,
+ trackResources: true,
+ trackInteractions: true,
+ firstPartyHosts: [
+ {
+ match: 'example.com',
+ propagatorTypes: [PropagatorType.DATADOG]
+ }
+ ],
+ useAccessibilityLabel: true,
+ actionNameAttribute: 'test-action-name-attr',
+ resourceTracingSamplingRate: 100
+ };
+
+ const configuration = new FileBasedConfiguration({
+ configuration: { configuration: autoInstrumentationConfig }
+ });
+
+ render();
+
+ await flushPromises();
+ await waitFor(() => {
+ expect(
+ DdSdkReactNative._enableFeaturesFromDatadogProvider
+ ).toHaveBeenCalledTimes(1);
+ });
+ expect(
+ DdSdkReactNative._enableFeaturesFromDatadogProvider
+ ).toHaveBeenCalledWith({
+ actionEventMapper: null,
+ logEventMapper: null,
+ resourceEventMapper: null,
+ errorEventMapper: null,
+ trackErrors: true,
+ trackResources: true,
+ trackInteractions: true,
+ firstPartyHosts: [
+ {
+ match: 'example.com',
+ propagatorTypes: [PropagatorType.DATADOG]
+ }
+ ],
+ useAccessibilityLabel: true,
+ actionNameAttribute: 'test-action-name-attr',
+ resourceTracingSamplingRate: 100
+ });
+
+ expect(
+ DdSdkReactNative._enableFeaturesFromDatadogProvider
+ ).not.toHaveBeenCalledWith(
+ expect.objectContaining({
+ clientToken: expect.anything(),
+ env: expect.anything(),
+ applicationId: expect.anything()
+ })
+ );
+ });
+
+ it('initializes the DatadogProvider with FileBasedConfiguration & undefined parameters', async () => {
+ const { DatadogCodepushProvider } = require('..');
+ const {
+ DdSdkReactNative,
+ PropagatorType,
+ FileBasedConfiguration
+ } = require('@datadog/mobile-react-native');
+
+ const autoInstrumentationConfig = {
+ trackErrors: true,
+ trackResources: true,
+ trackInteractions: true,
+ firstPartyHosts: [
+ {
+ match: 'example.com',
+ propagatorTypes: [PropagatorType.DATADOG]
+ }
+ ],
+ // useAccessibilityLabel: true,
+ // actionNameAttribute: 'test-action-name-attr',
+ resourceTracingSamplingRate: 100
+ };
+
+ const configuration = new FileBasedConfiguration({
+ configuration: { configuration: autoInstrumentationConfig }
+ });
+
+ render();
+
+ await flushPromises();
+ await waitFor(() => {
+ expect(
+ DdSdkReactNative._enableFeaturesFromDatadogProvider
+ ).toHaveBeenCalledTimes(1);
+ });
+ expect(
+ DdSdkReactNative._enableFeaturesFromDatadogProvider
+ ).toHaveBeenCalledWith({
+ actionEventMapper: null,
+ logEventMapper: null,
+ resourceEventMapper: null,
+ errorEventMapper: null,
+ trackErrors: true,
+ trackResources: true,
+ trackInteractions: true,
+ firstPartyHosts: [
+ {
+ match: 'example.com',
+ propagatorTypes: [PropagatorType.DATADOG]
+ }
+ ],
+ resourceTracingSamplingRate: 100,
+ actionNameAttribute: undefined,
+ useAccessibilityLabel: true
+ });
+
+ expect(
+ DdSdkReactNative._enableFeaturesFromDatadogProvider
+ ).not.toHaveBeenCalledWith(
+ expect.objectContaining({
+ clientToken: expect.anything(),
+ env: expect.anything(),
+ applicationId: expect.anything()
+ })
+ );
+ });
});
});
diff --git a/packages/codepush/src/index.ts b/packages/codepush/src/index.ts
index dce7b7842..ca7024ebf 100644
--- a/packages/codepush/src/index.ts
+++ b/packages/codepush/src/index.ts
@@ -1,11 +1,22 @@
+/*
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
+ * Copyright 2016-Present Datadog, Inc.
+ */
import {
DatadogProvider,
DatadogProviderConfiguration,
DdSdkReactNative
} from '@datadog/mobile-react-native';
-import type { DdSdkReactNativeConfiguration } from '@datadog/mobile-react-native';
+import type {
+ AutoInstrumentationConfiguration,
+ DdSdkReactNativeConfiguration
+} from '@datadog/mobile-react-native';
import codePush from 'react-native-code-push';
+import { DISCARD_PROPERTY, removeDiscardProperties } from './utils';
+import type { RequiredOrDiscard } from './utils';
+
/**
* Use this class instead of DdSdkReactNative to initialize the Datadog SDK when using AppCenter CodePush.
*/
@@ -31,6 +42,29 @@ const initializeWithCodepushVersion = async (
DatadogProvider.initialize(configuration);
};
+const buildPartialConfiguration = (
+ configuration: DatadogProviderConfiguration
+): AutoInstrumentationConfiguration => {
+ const partialConfiguration: RequiredOrDiscard = {
+ trackErrors: configuration.trackErrors,
+ trackResources: configuration.trackResources,
+ trackInteractions: configuration.trackInteractions,
+ firstPartyHosts: configuration.firstPartyHosts,
+ logEventMapper: configuration.logEventMapper,
+ errorEventMapper: configuration.errorEventMapper,
+ resourceEventMapper: configuration.resourceEventMapper,
+ actionEventMapper: configuration.actionEventMapper,
+ useAccessibilityLabel: configuration.useAccessibilityLabel,
+ resourceTracingSamplingRate: configuration.resourceTracingSamplingRate,
+ actionNameAttribute:
+ configuration.actionNameAttribute ?? DISCARD_PROPERTY
+ };
+
+ return removeDiscardProperties(
+ partialConfiguration
+ ) as AutoInstrumentationConfiguration;
+};
+
export const DatadogCodepushProvider: typeof DatadogProvider = ({
configuration,
...rest
@@ -39,16 +73,8 @@ export const DatadogCodepushProvider: typeof DatadogProvider = ({
// We turn it to partial initialization, while in parallel we get the CodePush version and initialize the SDK.
if (configuration instanceof DatadogProviderConfiguration) {
initializeWithCodepushVersion(configuration);
- const partialConfiguration = {
- trackErrors: configuration.trackErrors,
- trackResources: configuration.trackResources,
- trackInteractions: configuration.trackInteractions,
- firstPartyHosts: configuration.firstPartyHosts,
- resourceTracingSamplingRate:
- configuration.resourceTracingSamplingRate
- };
return DatadogProvider({
- configuration: partialConfiguration,
+ configuration: buildPartialConfiguration(configuration),
...rest
});
} else {
diff --git a/packages/codepush/src/utils.ts b/packages/codepush/src/utils.ts
new file mode 100644
index 000000000..2a1f321c5
--- /dev/null
+++ b/packages/codepush/src/utils.ts
@@ -0,0 +1,37 @@
+/*
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
+ * Copyright 2016-Present Datadog, Inc.
+ */
+
+/**
+ * A constant used to define a property that should be discarded from a {@link RequiredOrDiscard} object.
+ */
+export const DISCARD_PROPERTY = { _dd_meta_: 'DISCARD' };
+
+/**
+ * Used to change the type of every property of an object to be either required or {@link DISCARD_PROPERTY}.
+ */
+export type RequiredOrDiscard = {
+ [K in keyof T]-?: T[K] | typeof DISCARD_PROPERTY;
+};
+
+/**
+ * Removes all entries of value {@link DISCARD_PROPERTY} from the given object
+ * @param obj The object to remove the {@link DISCARD_PROPERTY} entries from.
+ * @returns The object without the {@link DISCARD_PROPERTY} entries.
+ */
+export const removeDiscardProperties = >(
+ obj: T
+): {
+ [K in keyof T]: T[K] extends null ? undefined : T[K];
+} => {
+ const result = {} as any;
+
+ Object.keys(obj).forEach(key => {
+ const value = obj[key];
+ result[key] = value === DISCARD_PROPERTY ? undefined : value;
+ });
+
+ return result;
+};
diff --git a/packages/core/src/DdSdkReactNative.tsx b/packages/core/src/DdSdkReactNative.tsx
index fce0e17ef..6969d2c5c 100644
--- a/packages/core/src/DdSdkReactNative.tsx
+++ b/packages/core/src/DdSdkReactNative.tsx
@@ -106,9 +106,9 @@ export class DdSdkReactNative {
/**
* FOR INTERNAL USE ONLY.
*/
- static async _initializeFromDatadogProvider(
+ static _initializeFromDatadogProvider = async (
configuration: DatadogProviderConfiguration
- ): Promise {
+ ): Promise => {
DdSdkReactNative.enableFeatures(configuration);
if (configuration instanceof FileBasedConfiguration) {
return DdSdkReactNative.initializeNativeSDK(configuration, {
@@ -133,20 +133,25 @@ export class DdSdkReactNative {
initializationModeForTelemetry: 'SYNC'
});
}
- }
+ };
/**
* FOR INTERNAL USE ONLY.
*/
- static async _enableFeaturesFromDatadogProvider(
+ static _enableFeaturesFromDatadogProvider = (
+ features: AutoInstrumentationConfiguration
+ ): void => {
+ DdSdkReactNative._enableFeaturesFromDatadogProviderAsync(features);
+ };
+
+ static _enableFeaturesFromDatadogProviderAsync = async (
features: AutoInstrumentationConfiguration
- ): Promise {
+ ): Promise => {
DdSdkReactNative.features = features;
DdSdkReactNative.enableFeatures(
addDefaultValuesToAutoInstrumentationConfiguration(features)
);
- }
-
+ };
/**
* FOR INTERNAL USE ONLY.
*/
diff --git a/packages/core/src/__tests__/mock.test.ts b/packages/core/src/__tests__/mock.test.ts
index 99eb43035..722998f10 100644
--- a/packages/core/src/__tests__/mock.test.ts
+++ b/packages/core/src/__tests__/mock.test.ts
@@ -50,6 +50,9 @@ const privateProperties = {
'wasAutoInstrumented',
'initializeNativeSDK',
'_initializeFromDatadogProviderWithConfigurationAsync',
+ '_enableFeaturesFromDatadogProvider',
+ '_enableFeaturesFromDatadogProviderAsync',
+ '_initializeFromDatadogProvider',
'buildConfiguration'
]
};
diff --git a/packages/core/src/index.tsx b/packages/core/src/index.tsx
index 515cfd1f8..9a0d1cead 100644
--- a/packages/core/src/index.tsx
+++ b/packages/core/src/index.tsx
@@ -12,6 +12,7 @@ import {
BatchSize,
BatchProcessingLevel
} from './DdSdkReactNativeConfiguration';
+import type { AutoInstrumentationConfiguration } from './DdSdkReactNativeConfiguration';
import { DdSdkReactNative } from './DdSdkReactNative';
import { InternalLog } from './InternalLog';
import { ProxyConfiguration, ProxyType } from './ProxyConfiguration';
@@ -74,4 +75,4 @@ export {
DatadogTracingContext
};
-export type { Timestamp, FirstPartyHost };
+export type { Timestamp, FirstPartyHost, AutoInstrumentationConfiguration };
diff --git a/yarn.lock b/yarn.lock
index 379b5bb42..eb0ef8088 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2381,7 +2381,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@datadog/mobile-react-native-code-push@workspace:packages/codepush"
dependencies:
- "@datadog/mobile-react-native": ^2.8.0
+ "@datadog/mobile-react-native": "workspace:packages/core"
"@testing-library/react-native": 7.0.2
react-native-builder-bob: 0.26.0
react-native-code-push: 7.1.0