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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [15.0.2](https://github.com/Instabug/Instabug-React-Native/compare/v15.0.1...v15.0.2)

- Rollout support for network spans. ([#1427](https://github.com/Instabug/Instabug-React-Native/pull/1427))

## [15.0.1](https://github.com/Instabug/Instabug-React-Native/compare/v14.3.0...v15.0.1)

### Added
Expand Down
27 changes: 8 additions & 19 deletions examples/default/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { ActivityIndicator, StyleSheet } from 'react-native';
import React, { useEffect } from 'react';
import { StyleSheet } from 'react-native';

import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
Expand Down Expand Up @@ -40,13 +40,11 @@ export const App: React.FC = () => {

const navigationRef = useNavigationContainerRef();

const [isInstabugInitialized, setIsInstabugInitialized] = useState(false);

const initializeInstabug = async () => {
const initializeInstabug = () => {
try {
SessionReplay.setSyncCallback((data) => shouldSyncSession(data));

await Instabug.init({
Instabug.init({
token: 'deb1910a7342814af4e4c9210c786f35',
invocationEvents: [InvocationEvent.floatingButton],
debugLogsLevel: LogLevel.verbose,
Expand All @@ -55,21 +53,16 @@ export const App: React.FC = () => {

CrashReporting.setNDKCrashesEnabled(true);
Instabug.setReproStepsConfig({ all: ReproStepsMode.enabled });

setIsInstabugInitialized(true); // Set to true after initialization
} catch (error) {
console.error('Instabug initialization failed:', error);
setIsInstabugInitialized(true); // Proceed even if initialization fails
}
};

useEffect(() => {
initializeInstabug().then(() => {
NetworkLogger.setNetworkDataObfuscationHandler(async (networkData) => {
networkData.url = `${networkData.url}/JS/Obfuscated`;
return networkData;
});
// NetworkLogger.setRequestFilterExpression('false');
initializeInstabug();
NetworkLogger.setNetworkDataObfuscationHandler(async (networkData) => {
networkData.url = `${networkData.url}/JS/Obfuscated`;
return networkData;
});
});

Expand All @@ -80,10 +73,6 @@ export const App: React.FC = () => {
return unregisterListener;
}, [navigationRef]);

if (!isInstabugInitialized) {
return <ActivityIndicator size="large" color="#0000ff" style={styles.loading} />;
}

return (
<GestureHandlerRootView style={styles.root}>
<NativeBaseProvider theme={nativeBaseTheme}>
Expand Down
2 changes: 1 addition & 1 deletion ios/RNInstabug/InstabugNetworkLoggerBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ typedef NS_ENUM(NSInteger, NetworkListenerType) {
+------------------------------------------------------------------------+
*/

- (void)isNativeInterceptionEnabled:(RCTPromiseResolveBlock _Nullable )resolve :(RCTPromiseRejectBlock _Nullable )reject;
- (BOOL)isNativeInterceptionEnabled;

- (void) registerNetworkLogsListener:(NetworkListenerType)listenerType;

Expand Down
8 changes: 5 additions & 3 deletions ios/RNInstabug/InstabugNetworkLoggerBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ -(void)stopObserving {
// Remove upstream listeners, stop unnecessary background tasks
}

RCT_EXPORT_METHOD(isNativeInterceptionEnabled:(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject) {
resolve(@(IBGNetworkLogger.isNativeNetworkInterceptionFeatureEnabled));
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isNativeInterceptionEnabled) {
return @(IBGNetworkLogger.isNativeNetworkInterceptionFeatureEnabled);
}



RCT_EXPORT_METHOD(registerNetworkLogsListener: (NetworkListenerType) listenerType) {
switch (listenerType) {
Expand Down
8 changes: 3 additions & 5 deletions src/modules/Instabug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ function reportCurrentViewForAndroid(screenName: string | null) {
* Should be called in constructor of the AppRegistry component
* @param config SDK configurations. See {@link InstabugConfig} for more info.
*/
export const init = async (config: InstabugConfig) => {
export const init = (config: InstabugConfig) => {
if (Platform.OS === 'android') {
// Add android feature flags listener for android
registerFeatureFlagsListener();
addOnFeatureUpdatedListener(config);
} else {
isNativeInterceptionFeatureEnabled = await NativeNetworkLogger.isNativeInterceptionEnabled();
isNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled();

// Add app state listener to handle background/foreground transitions
addAppStateListener(async (nextAppState) => handleAppStateChange(nextAppState, config));
Expand Down Expand Up @@ -133,7 +133,6 @@ const handleAppStateChange = async (nextAppState: AppStateStatus, config: Instab
// Checks if the app has come to the foreground
if (['inactive', 'background'].includes(_currentAppState) && nextAppState === 'active') {
const isUpdated = await fetchApmNetworkFlags();

if (isUpdated) {
refreshAPMNetworkConfigs(config);
}
Expand All @@ -147,8 +146,7 @@ const handleAppStateChange = async (nextAppState: AppStateStatus, config: Instab
*/
const fetchApmNetworkFlags = async () => {
let isUpdated = false;
const newNativeInterceptionFeatureEnabled =
await NativeNetworkLogger.isNativeInterceptionEnabled();
const newNativeInterceptionFeatureEnabled = NativeNetworkLogger.isNativeInterceptionEnabled();
if (isNativeInterceptionFeatureEnabled !== newNativeInterceptionFeatureEnabled) {
isNativeInterceptionFeatureEnabled = newNativeInterceptionFeatureEnabled;
isUpdated = true;
Expand Down
2 changes: 1 addition & 1 deletion src/native/NativeNetworkLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export enum NetworkListenerType {
}

export interface NetworkLoggerNativeModule extends NativeModule {
isNativeInterceptionEnabled(): Promise<boolean>;
isNativeInterceptionEnabled(): boolean;

registerNetworkLogsListener(type?: NetworkListenerType): void;

Expand Down
91 changes: 40 additions & 51 deletions test/modules/Instabug.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ describe('Instabug Module', () => {
expect(NativeInstabug.reportScreenChange).toBeCalledWith(screenName);
});

it("componentDidAppearListener shouldn't call the native method reportScreenChange if first screen", async () => {
await Instabug.init({
it("componentDidAppearListener shouldn't call the native method reportScreenChange if first screen", () => {
Instabug.init({
token: 'some-token',
invocationEvents: [InvocationEvent.none],
});
Expand All @@ -81,14 +81,19 @@ describe('Instabug Module', () => {
componentType: 'Component',
});

await waitForExpect(() => {
waitForExpect(() => {
// Only first screen should be reported
expect(NativeInstabug.reportScreenChange).toBeCalledTimes(1);
expect(NativeInstabug.reportScreenChange).toBeCalledWith('Initial Screen');
});
});

it("componentDidAppearListener shouldn't call the native method reportScreenChange twice if same screen", (done) => {
Instabug.init({
token: 'some-token',
invocationEvents: [InvocationEvent.none],
});

Array(5).forEach(() => {
Instabug.componentDidAppearListener({
componentId: '1',
Expand All @@ -107,7 +112,7 @@ describe('Instabug Module', () => {
// 2. Second+ calls:
// The screen name is the same as _lastScreen (stored in 1st call)
// so it doesn't report a screen change
expect(NativeInstabug.reportScreenChange).not.toBeCalled();
expect(NativeInstabug.reportScreenChange).toBeCalledTimes(1);
done();
}, 1500);
});
Expand Down Expand Up @@ -283,7 +288,7 @@ describe('Instabug Module', () => {
expect(onStateChangeMock).toHaveBeenCalledWith(mockNavigationContainerRef.getRootState());
});

it('should call the native method init', async () => {
it('should call the native method init', () => {
const instabugConfig = {
token: 'some-token',
invocationEvents: [InvocationEvent.floatingButton, InvocationEvent.shake],
Expand All @@ -292,7 +297,7 @@ describe('Instabug Module', () => {
};
const usesNativeNetworkInterception = false;

await Instabug.init(instabugConfig);
Instabug.init(instabugConfig);

expect(NetworkLogger.setEnabled).toBeCalledWith(true);
expect(NativeInstabug.init).toBeCalledTimes(1);
Expand All @@ -314,7 +319,7 @@ describe('Instabug Module', () => {
expect(NativeInstabug.setCodePushVersion).toBeCalledWith(codePushVersion);
});

it('init should disable JavaScript interceptor when using native interception mode', async () => {
it('init should disable JavaScript interceptor when using native interception mode', () => {
const instabugConfig = {
token: 'some-token',
invocationEvents: [InvocationEvent.floatingButton, InvocationEvent.shake],
Expand All @@ -324,12 +329,10 @@ describe('Instabug Module', () => {
};

// Stubbing Network feature flags
jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(true));
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true);
jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true));

await Instabug.init(instabugConfig);
Instabug.init(instabugConfig);

if (Platform.OS === 'android') {
expect(NetworkLogger.setEnabled).not.toBeCalled();
Expand Down Expand Up @@ -900,7 +903,7 @@ describe('Instabug Module', () => {
expect(NativeInstabug.willRedirectToStore).toBeCalledTimes(1);
});

it('should register feature flag listener', async () => {
it('should register feature flag listener', () => {
const callback = jest.fn();
Instabug._registerFeatureFlagsChangeListener(callback);

Expand Down Expand Up @@ -939,10 +942,10 @@ describe('Instabug iOS initialization tests', () => {
jest.advanceTimersByTime(1000);
});

it('should initialize correctly with javascript interception mode', async () => {
it('should initialize correctly with javascript interception mode', () => {
config.networkInterceptionMode = NetworkInterceptionMode.javascript;

await Instabug.init(config);
Instabug.init(config);

expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled();
expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(true);
Expand All @@ -955,12 +958,10 @@ describe('Instabug iOS initialization tests', () => {
);
});

it('should initialize correctly with native interception mode when [isNativeInterceptionEnabled] == ture', async () => {
jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(true));
it('should initialize correctly with native interception mode when [isNativeInterceptionEnabled] == ture', () => {
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true);

await Instabug.init(config);
Instabug.init(config);

expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled();
expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(false);
Expand All @@ -973,12 +974,10 @@ describe('Instabug iOS initialization tests', () => {
);
});

it('should disable native interception mode when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', async () => {
jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(false));
it('should disable native interception mode when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', () => {
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false);

await Instabug.init(config);
Instabug.init(config);

expect(NativeNetworkLogger.isNativeInterceptionEnabled).toHaveBeenCalled();
expect(NetworkLogger.setEnabled).toHaveBeenCalled();
Expand All @@ -991,13 +990,11 @@ describe('Instabug iOS initialization tests', () => {
);
});

it('should display error message when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', async () => {
jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(false));
it('should display error message when user sets networkInterceptionMode to native and [isNativeInterceptionEnabled] == false', () => {
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false);
const logSpy = jest.spyOn(global.console, 'error');

await Instabug.init(config);
Instabug.init(config);

expect(logSpy).toBeCalledTimes(1);
expect(logSpy).toBeCalledWith(
Expand All @@ -1020,9 +1017,9 @@ describe('Instabug Android initialization tests', () => {
};
});

it('should initialize correctly with native interception enabled', async () => {
it('should initialize correctly with native interception enabled', () => {
config.networkInterceptionMode = NetworkInterceptionMode.native;
await Instabug.init(config);
Instabug.init(config);
fakeTimer(() => {
expect(NativeInstabug.setOnFeaturesUpdatedListener).toHaveBeenCalled();
expect(NetworkLogger.setEnabled).toHaveBeenCalledWith(true);
Expand All @@ -1036,14 +1033,12 @@ describe('Instabug Android initialization tests', () => {
});
});

it('should show warning message when networkInterceptionMode == javascript and user added APM plugin', async () => {
jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(true));
it('should show warning message when networkInterceptionMode == javascript and user added APM plugin', () => {
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true);
jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true));
const logSpy = jest.spyOn(global.console, 'warn');

await Instabug.init(config);
Instabug.init(config);
fakeTimer(() => {
expect(logSpy).toBeCalledTimes(1);
expect(logSpy).toBeCalledWith(
Expand All @@ -1052,16 +1047,14 @@ describe('Instabug Android initialization tests', () => {
});
});

it('should show error message when networkInterceptionMode == native and user did not add APM plugin', async () => {
it('should show error message when networkInterceptionMode == native and user did not add APM plugin', () => {
config.networkInterceptionMode = NetworkInterceptionMode.native;

jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(true));
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(true);
jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false));
const logSpy = jest.spyOn(global.console, 'error');

await Instabug.init(config);
Instabug.init(config);

fakeTimer(() => {
expect(logSpy).toBeCalledTimes(1);
Expand All @@ -1071,16 +1064,14 @@ describe('Instabug Android initialization tests', () => {
});
});

it('should show error message when networkInterceptionMode == native and user did not add APM plugin and the isNativeInterceptionEnabled is disabled', async () => {
it('should show error message when networkInterceptionMode == native and user did not add APM plugin and the isNativeInterceptionEnabled is disabled', () => {
config.networkInterceptionMode = NetworkInterceptionMode.native;

jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(false));
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false);
jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false));
const logSpy = jest.spyOn(global.console, 'error');

await Instabug.init(config);
Instabug.init(config);

fakeTimer(() => {
expect(logSpy).toBeCalledTimes(1);
Expand All @@ -1090,15 +1081,13 @@ describe('Instabug Android initialization tests', () => {
});
});

it('should show error message when networkInterceptionMode == native and the isNativeInterceptionEnabled is disabled', async () => {
it('should show error message when networkInterceptionMode == native and the isNativeInterceptionEnabled is disabled', () => {
config.networkInterceptionMode = NetworkInterceptionMode.native;
jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(false));
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false);
jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(true));
const logSpy = jest.spyOn(global.console, 'error');

await Instabug.init(config);
Instabug.init(config);

fakeTimer(() => {
expect(logSpy).toBeCalledTimes(1);
Expand Down
6 changes: 2 additions & 4 deletions test/utils/InstabugUtils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,9 @@ describe('reportNetworkLog', () => {

it('reportNetworkLog should send network logs to native with the correct parameters on Android', async () => {
Platform.OS = 'android';
jest
.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled')
.mockReturnValue(Promise.resolve(false));
jest.spyOn(NativeNetworkLogger, 'isNativeInterceptionEnabled').mockReturnValue(false);
jest.spyOn(NativeNetworkLogger, 'hasAPMNetworkPlugin').mockReturnValue(Promise.resolve(false));
await Instabug.init({ token: '', invocationEvents: [InvocationEvent.none] });
Instabug.init({ token: '', invocationEvents: [InvocationEvent.none] });

const requestHeaders = JSON.stringify(network.requestHeaders);
const responseHeaders = JSON.stringify(network.responseHeaders);
Expand Down