Skip to content
Merged
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/codepush/src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ const createCodepushPackageMock = label => ({
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', () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/DdSdkReactNative.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class DdSdkReactNative {
initializationModeForTelemetry: InitializationModeForTelemetry;
}
): Promise<void> => {
if (GlobalState.instance.isInitialized) {
if (GlobalState.isInitialized) {
InternalLog.log(
"Can't initialize Datadog, SDK was already initialized",
SdkVerbosity.WARN
Expand All @@ -106,7 +106,7 @@ export class DdSdkReactNative {
);

InternalLog.log('Datadog SDK was initialized', SdkVerbosity.INFO);
GlobalState.instance.isInitialized = true;
GlobalState.isInitialized = true;
BufferSingleton.onInitialization();
};

Expand Down Expand Up @@ -509,7 +509,7 @@ export class DdSdkReactNative {
useAccessibilityLabel: configuration.useAccessibilityLabel
};

DdBabelInteractionTracking.getInstance(DdRum);
DdBabelInteractionTracking.attachRumInstance(DdRum);
}

if (DdSdkReactNative.wasAutoInstrumented) {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/__tests__/DdSdkReactNative.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jest.mock('../rum/instrumentation/DdRumErrorTracking', () => {
});

beforeEach(async () => {
GlobalState.instance.isInitialized = false;
GlobalState.isInitialized = false;
DdSdkReactNative['wasAutoInstrumented'] = false;
NativeModules.DdSdk.initialize.mockClear();
NativeModules.DdSdk.addAttributes.mockClear();
Expand Down Expand Up @@ -174,7 +174,7 @@ describe('DdSdkReactNative', () => {
'_dd.sdk_version': sdkVersion
});

expect(GlobalState.instance.isInitialized).toBe(false);
expect(GlobalState.isInitialized).toBe(false);
expect(
DdRumUserInteractionTracking.startTracking
).toHaveBeenCalledTimes(0);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/rum/DdRum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ class DdRumWrapper implements DdRumType {
};

async getCurrentSessionId(): Promise<string | undefined> {
if (!GlobalState.instance.isInitialized) {
if (!GlobalState.isInitialized) {
return undefined;
}
const sessionId = await this.nativeRum.getCurrentSessionId();
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/rum/__tests__/DdRum.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1816,7 +1816,7 @@ describe('DdRum', () => {

describe('DdRum.getCurrentSessionId', () => {
it('calls the native API if SDK is initialized', async () => {
GlobalState.instance.isInitialized = true;
GlobalState.isInitialized = true;
const sessionId = await DdRum.getCurrentSessionId();
expect(NativeModules.DdRum.getCurrentSessionId).toHaveBeenCalled();
expect(sessionId).toBe('test-session-id');
Expand All @@ -1825,7 +1825,7 @@ describe('DdRum', () => {

describe('DdRum.getCurrentSessionId', () => {
it('returns undefined if SDK is not initialized', async () => {
GlobalState.instance.isInitialized = false;
GlobalState.isInitialized = false;
const sessionId = await DdRum.getCurrentSessionId();
expect(
NativeModules.DdRum.getCurrentSessionId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@
*/

import DdSdk from '../../../specs/NativeDdSdk';
import { getGlobalInstance } from '../../../utils/singletonUtils';
import { DefaultTimeProvider } from '../../../utils/time-provider/DefaultTimeProvider';
import type { TimeProvider } from '../../../utils/time-provider/TimeProvider';
import type { DdRum } from '../../DdRum';
import { BABEL_PLUGIN_TELEMETRY } from '../../constants';
import type { RumActionType } from '../../types';
import { ActionSource } from '../../types';

const StateErrors = {
ALREADY_INITIALIZED:
'Interaction Tracking singleton already initialized, please use `getInstance`.'
} as const;
const BABEL_INTERACTION_TRACKING_MODULE =
'com.datadog.reactnative.rum.babel_interaction_tracking';

type BabelConfig = {
trackInteractions: boolean;
Expand All @@ -32,10 +31,8 @@ type TargetObject = {
[key: string]: any;
};

export class DdBabelInteractionTracking {
private static instance: DdBabelInteractionTracking | null = null;

static config: BabelConfig = {
class BabelInteractionTracking {
config: BabelConfig = {
trackInteractions: false,
useAccessibilityLabel: true
};
Expand All @@ -48,34 +45,20 @@ export class DdBabelInteractionTracking {

isInitialized: boolean = false;

private constructor(ddRum?: typeof DdRum) {
if (DdBabelInteractionTracking.instance) {
throw new Error(StateErrors.ALREADY_INITIALIZED);
}

if (ddRum) {
this.ddRum = ddRum;
}

DdBabelInteractionTracking.instance = this;
getInstance() {
return DdBabelInteractionTracking;
}

static getInstance(ddRum?: typeof DdRum) {
if (!DdBabelInteractionTracking.instance) {
DdBabelInteractionTracking.instance = new DdBabelInteractionTracking(
ddRum
);
}

return DdBabelInteractionTracking.instance;
attachRumInstance(ddRum: typeof DdRum) {
this.ddRum = ddRum;
this.isInitialized = true;
}

static getTelemetryConfig() {
getTelemetryConfig() {
return {
babel_plugin: {
enabled: !!globalThis.__DD_RN_BABEL_PLUGIN_ENABLED__,
track_interactions: !!DdBabelInteractionTracking.config
.trackInteractions
track_interactions: !!this.config.trackInteractions
}
};
}
Expand All @@ -91,7 +74,7 @@ export class DdBabelInteractionTracking {
...attrs
} = targetObject;

const { useAccessibilityLabel } = DdBabelInteractionTracking.config;
const { useAccessibilityLabel } = this.config;

const tryContent = () => {
const content = getContent?.();
Expand Down Expand Up @@ -144,7 +127,7 @@ export class DdBabelInteractionTracking {
if (!this.telemetrySent) {
DdSdk?.sendTelemetryLog(
BABEL_PLUGIN_TELEMETRY,
DdBabelInteractionTracking.getTelemetryConfig(),
this.getTelemetryConfig(),
{ onlyOnce: true }
);

Expand All @@ -153,7 +136,7 @@ export class DdBabelInteractionTracking {

const targetName = this.getTargetName(targetObject);

const { trackInteractions } = DdBabelInteractionTracking.config;
const { trackInteractions } = this.config;

if (trackInteractions) {
this.ddRum
Expand All @@ -178,3 +161,8 @@ export class DdBabelInteractionTracking {
};
}
}

export const DdBabelInteractionTracking = getGlobalInstance(
BABEL_INTERACTION_TRACKING_MODULE,
() => new BabelInteractionTracking()
);
8 changes: 4 additions & 4 deletions packages/core/src/sdk/DatadogProvider/DatadogProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { InternalLog } from '../../InternalLog';
import { SdkVerbosity } from '../../SdkVerbosity';
import type { FileBasedConfiguration } from '../FileBasedConfiguration/FileBasedConfiguration';

let isInitialized = false;
import { DatadogProviderState } from './DatadogProviderState';

type Props = PropsWithChildren<{
/**
Expand Down Expand Up @@ -87,7 +87,7 @@ export const DatadogProvider: React.FC<Props> & StaticProperties = ({
configuration,
onInitialization
}) => {
if (!isInitialized) {
if (!DatadogProviderState.isInitialized) {
// Here we cannot use a useEffect hook since it would be called after
// the first render. Thus, we wouldn't enable auto-instrumentation on
// the elements rendered in this first render and what happens during
Expand All @@ -98,7 +98,7 @@ export const DatadogProvider: React.FC<Props> & StaticProperties = ({
} else {
initializeDatadog(configuration, onInitialization);
}
isInitialized = true;
DatadogProviderState.setInitialized();
}

return <>{children}</>;
Expand All @@ -120,5 +120,5 @@ DatadogProvider.initialize = async (
};

export const __internalResetIsInitializedForTesting = () => {
isInitialized = false;
DatadogProviderState._reset();
};
30 changes: 30 additions & 0 deletions packages/core/src/sdk/DatadogProvider/DatadogProviderState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 { getGlobalInstance } from '../../utils/singletonUtils';

const DATADOG_PROVIDER_STATE_MODULE =
'com.datadog.reactnative.rum.datadog_provider_state';

class _DatadogProviderState {
private _isInitialized: boolean = false;

get isInitialized(): boolean {
return this._isInitialized;
}

setInitialized() {
this._isInitialized = true;
}

_reset() {
this._isInitialized = false;
}
}

export const DatadogProviderState = getGlobalInstance(
DATADOG_PROVIDER_STATE_MODULE,
() => new _DatadogProviderState()
);
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const flushPromises = () =>
describe('DatadogProvider', () => {
afterEach(() => {
jest.clearAllMocks();
GlobalState.instance.isInitialized = false;
GlobalState.isInitialized = false;
__internalResetIsInitializedForTesting();
BufferSingleton.reset();
(nowMock as any).mockReturnValue('timestamp_not_specified');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const flushPromises = () =>
describe('DatadogProvider', () => {
beforeEach(() => {
jest.clearAllMocks();
GlobalState.instance.isInitialized = false;
GlobalState.isInitialized = false;
DdSdkReactNative['wasAutoInstrumented'] = false;
__internalResetIsInitializedForTesting();
BufferSingleton.reset();
Expand Down
21 changes: 10 additions & 11 deletions packages/core/src/sdk/GlobalState/GlobalState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@
* Copyright 2016-Present Datadog, Inc.
*/

import { getGlobalInstance } from '../../utils/singletonUtils';

const GLOBAL_STATE_MODULE = 'com.datadog.reactnative.sdk.global_state';

/**
* A singleton container for attributes that are shared internally across all
* the SDK classes.
*/
export class GlobalState {
class _GlobalState {
/**
* `true` if the SDK is initialized, `false` otherwise.
*/
public isInitialized = false;

// Singleton implementation
private static _instance: GlobalState | undefined = undefined;
public static get instance(): GlobalState {
if (this._instance === undefined) {
this._instance = new GlobalState();
}

return this._instance;
}
}

export const GlobalState = getGlobalInstance(
GLOBAL_STATE_MODULE,
() => new _GlobalState()
);
5 changes: 5 additions & 0 deletions packages/core/src/utils/singletonUtils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* 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.
*/
export const getGlobalInstance = <T>(
key: string,
objectConstructor: () => T
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ beforeEach(() => {
mocked(BackHandler.exitApp).mockClear();

// @ts-ignore
DdRumReactNavigationTracking.registeredContainer = null;
// @ts-ignore
DdRumReactNavigationTracking.navigationStateChangeListener = null;
DdRumReactNavigationTracking._resetInternalStateForTesting();
});

// Unit tests
Expand Down Expand Up @@ -357,7 +355,7 @@ describe.each([
expect(DdRum.startView).toHaveBeenCalledTimes(2);
});

it('does nothing when startTrackingViews { undefined any ', async () => {
it('does nothing when startTrackingViews { undefined any }', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Woops. Thanks 🙇

// WHEN
DdRumReactNavigationTracking.startTrackingViews(null);

Expand Down
Loading