/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable global-require */ import { render, waitFor } from '@testing-library/react-native'; import React from 'react'; jest.mock('react-native-code-push', () => ({ getUpdateMetadata: jest.fn() })); 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; }); const flushPromises = () => new Promise(jest.requireActual('timers').setImmediate); const createCodepushPackageMock = (label: string | null) => ({ label, isMandatory: false, install: jest.fn(), appVersion: '1.0.0', deploymentKey: '1', description: '1', failedInstall: false, isFirstRun: false, isPending: false, packageHash: '1', packageSize: 42 }); describe('AppCenter Codepush integration', () => { beforeEach(() => { jest.clearAllMocks(); const _globalThis = (globalThis as unknown) as Record< PropertyKey, unknown >; const providerState = _globalThis[ Symbol.for('com.datadog.reactnative.rum.datadog_provider_state') ] as | { _reset: () => void; } | undefined; providerState?._reset(); }); 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 { CoreConfiguration, RumConfiguration, DdSdkReactNative } = require('@datadog/mobile-react-native'); (codePush.getUpdateMetadata as jest.MockedFunction< typeof codePush.getUpdateMetadata >).mockResolvedValueOnce(createCodepushPackageMock('v3')); const configuration = new CoreConfiguration('token', 'env'); configuration.rumConfiguration = new RumConfiguration( 'appId', true, true, true ); await DatadogCodepush.initialize(configuration); expect(DdSdkReactNative.initialize).toHaveBeenCalledTimes(1); expect(DdSdkReactNative.initialize).toHaveBeenCalledWith( expect.objectContaining({ versionSuffix: 'codepush.v3' }) ); }); 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 { CoreConfiguration, RumConfiguration, DdSdkReactNative } = require('@datadog/mobile-react-native'); (codePush.getUpdateMetadata as jest.MockedFunction< typeof codePush.getUpdateMetadata >).mockResolvedValueOnce(null); const configuration = new CoreConfiguration('token', 'env'); configuration.rumConfiguration = new RumConfiguration( 'appId', true, true, true ); await DatadogCodepush.initialize(configuration); expect(DdSdkReactNative.initialize).toHaveBeenCalledTimes(1); expect( Object.keys( (DdSdkReactNative.initialize as jest.MockedFunction< typeof DdSdkReactNative.initialize >).mock.calls[0] ) ).not.toContain('versionSuffix'); }); }); 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, RumConfiguration, DdSdkReactNative } = require('@datadog/mobile-react-native'); (codePush.getUpdateMetadata as jest.MockedFunction< typeof codePush.getUpdateMetadata >).mockResolvedValueOnce(createCodepushPackageMock('v4')); const configuration = new DatadogProviderConfiguration( 'token', 'env' ); configuration.rumConfiguration = new RumConfiguration( 'appId', true, true, true ); render(); await flushPromises(); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).toHaveBeenCalledTimes(1); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).toHaveBeenCalledWith( expect.objectContaining({ versionSuffix: 'codepush.v4' }) ); }); 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')); const configuration = { trackErrors: true, trackInteractions: true, trackResources: true }; render(); await flushPromises(); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).not.toHaveBeenCalled(); DatadogCodepushProvider.initialize({ applicationId: 'fake-application-id', clientToken: 'fake-client-token', env: 'fake-env' }); await flushPromises(); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).toHaveBeenCalledTimes(1); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).toHaveBeenCalledWith( 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, RumConfiguration, DdSdkReactNative } = require('@datadog/mobile-react-native'); (codePush.getUpdateMetadata as jest.MockedFunction< typeof codePush.getUpdateMetadata >).mockResolvedValueOnce(createCodepushPackageMock(null)); const configuration = new DatadogProviderConfiguration( 'token', 'env' ); configuration.rumConfiguration = new RumConfiguration( 'appId', true, true, true ); render(); await flushPromises(); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).toHaveBeenCalledTimes(1); expect( Object.keys( (DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync as jest.MockedFunction< typeof DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync >).mock.calls[0] ) ).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)); const configuration = { trackErrors: true, trackInteractions: true, trackResources: true }; render(); await flushPromises(); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).not.toHaveBeenCalled(); DatadogCodepushProvider.initialize({ clientToken: 'fake-client-token', env: 'fake-env', rumConfiguration: { applicationId: 'fake-application-id' } }); await flushPromises(); expect( DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync ).toHaveBeenCalledTimes(1); expect( Object.keys( (DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync as jest.MockedFunction< typeof DdSdkReactNative._initializeFromDatadogProviderWithConfigurationAsync >).mock.calls[0] ) ).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 = { clientToken: 'fake-client-token', env: 'fake-env', rumConfiguration: { applicationId: 'fake-app-id', useAccessibilityLabel: true, actionNameAttribute: 'test-action-name-attr', trackErrors: true, trackResources: true, trackInteractions: true, resourceTraceSampleRate: 100, nativeCrashReportEnabled: true, nativeLongTaskThresholdMs: false, nativeViewTracking: true, firstPartyHosts: [ { match: 'example.com', propagatorTypes: [PropagatorType.DATADOG] } ] }, logsConfiguration: {}, traceConfiguration: {} }; const configuration = new FileBasedConfiguration({ configuration: autoInstrumentationConfig }); render(); await flushPromises(); await waitFor(() => { expect( DdSdkReactNative._enableFeaturesFromDatadogProvider ).toHaveBeenCalledTimes(1); }); expect( DdSdkReactNative._enableFeaturesFromDatadogProvider ).toHaveBeenCalledWith({ rumConfiguration: { useAccessibilityLabel: true, actionNameAttribute: 'test-action-name-attr', actionEventMapper: null, nativeCrashReportEnabled: true, nativeLongTaskThresholdMs: false, nativeViewTracking: true, resourceEventMapper: null, errorEventMapper: null, trackErrors: true, trackResources: true, trackInteractions: true, resourceTraceSampleRate: 100, firstPartyHosts: [ { match: 'example.com', propagatorTypes: [PropagatorType.DATADOG] } ] }, logsConfiguration: { logEventMapper: null } }); 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, FileBasedConfiguration } = require('@datadog/mobile-react-native'); const autoInstrumentationConfig = { clientToken: 'fake-client-token', env: 'fake-env', rumConfiguration: { applicationId: 'fake-app-id' } }; const configuration = new FileBasedConfiguration({ configuration: autoInstrumentationConfig }); render(); await flushPromises(); await waitFor(() => { expect( DdSdkReactNative._enableFeaturesFromDatadogProvider ).toHaveBeenCalledTimes(1); }); expect( DdSdkReactNative._enableFeaturesFromDatadogProvider ).toHaveBeenCalledWith( expect.objectContaining({ rumConfiguration: expect.objectContaining({ useAccessibilityLabel: true, actionNameAttribute: undefined, trackErrors: false, trackResources: false, trackInteractions: false, actionEventMapper: null, resourceEventMapper: null, errorEventMapper: null, resourceTraceSampleRate: 100, firstPartyHosts: [] }), logsConfiguration: expect.objectContaining({ logEventMapper: null }) }) ); expect( DdSdkReactNative._enableFeaturesFromDatadogProvider ).not.toHaveBeenCalledWith( expect.objectContaining({ clientToken: expect.anything(), env: expect.anything(), applicationId: expect.anything() }) ); }); }); });