Skip to content

Commit cd7054e

Browse files
fix(transport): Fallback to fetch transport if native not available (#2695)
1 parent ad17b3e commit cd7054e

File tree

6 files changed

+68
-35
lines changed

6 files changed

+68
-35
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
- Message event current stack trace moved from exception to threads ([#2694](https://github.com/getsentry/sentry-react-native/pull/2694))
1010

11+
### Fixes
12+
13+
- Unreachable fallback to fetch transport if native is not available ([#2695](https://github.com/getsentry/sentry-react-native/pull/2695))
14+
1115
## 4.12.0
1216

1317
### Features

src/js/client.ts

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { eventFromException, eventFromMessage,makeFetchTransport } from '@sentry/browser';
2-
import { FetchImpl } from '@sentry/browser/types/transports/utils';
1+
import { eventFromException, eventFromMessage } from '@sentry/browser';
32
import { BaseClient } from '@sentry/core';
43
import {
54
ClientReportEnvelope,
@@ -11,18 +10,16 @@ import {
1110
Outcome,
1211
SeverityLevel,
1312
Thread,
14-
Transport,
1513
UserFeedback,
1614
} from '@sentry/types';
1715
import { dateTimestampInSeconds, logger, SentryError } from '@sentry/utils';
18-
// @ts-ignore LogBox introduced in RN 0.63
19-
import { Alert, LogBox, YellowBox } from 'react-native';
16+
import { Alert } from 'react-native';
2017

2118
import { Screenshot } from './integrations/screenshot';
2219
import { defaultSdkInfo } from './integrations/sdkinfo';
23-
import { ReactNativeClientOptions, ReactNativeTransportOptions } from './options';
24-
import { makeReactNativeTransport } from './transports/native';
20+
import { ReactNativeClientOptions } from './options';
2521
import { createUserFeedbackEnvelope, items } from './utils/envelope';
22+
import { ignoreRequireCycleLogs } from './utils/ignorerequirecyclelogs';
2623
import { mergeOutcomes } from './utils/outcome';
2724
import { NATIVE } from './wrapper';
2825

@@ -41,34 +38,15 @@ export class ReactNativeClient extends BaseClient<ReactNativeClientOptions> {
4138
* @param options Configuration options for this SDK.
4239
*/
4340
public constructor(options: ReactNativeClientOptions) {
44-
if (!options.transport) {
45-
options.transport = (options: ReactNativeTransportOptions, nativeFetch?: FetchImpl): Transport => {
46-
if (NATIVE.isNativeTransportAvailable()) {
47-
return makeReactNativeTransport(options);
48-
}
49-
return makeFetchTransport(options, nativeFetch);
50-
};
51-
}
41+
ignoreRequireCycleLogs();
5242
options._metadata = options._metadata || {};
5343
options._metadata.sdk = options._metadata.sdk || defaultSdkInfo;
5444
super(options);
5545

5646
this._outcomesBuffer = [];
57-
58-
// This is a workaround for now using fetch on RN, this is a known issue in react-native and only generates a warning
59-
// YellowBox deprecated and replaced with with LogBox in RN 0.63
60-
if (LogBox) {
61-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
62-
LogBox.ignoreLogs(['Require cycle:']);
63-
} else {
64-
// eslint-disable-next-line deprecation/deprecation
65-
YellowBox.ignoreWarnings(['Require cycle:']);
66-
}
67-
6847
void this._initNativeSdk();
6948
}
7049

71-
7250
/**
7351
* @inheritDoc
7452
*/

src/js/sdk.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
defaultIntegrations as reactDefaultIntegrations,
55
defaultStackParser,
66
getCurrentHub,
7+
makeFetchTransport,
78
} from '@sentry/react';
89
import { Integration, StackFrame, UserFeedback } from '@sentry/types';
910
import { logger, stackParserFromStackParserOptions } from '@sentry/utils';
@@ -25,7 +26,7 @@ import { ReactNativeClientOptions, ReactNativeOptions, ReactNativeWrapperOptions
2526
import { ReactNativeScope } from './scope';
2627
import { TouchEventBoundary } from './touchevents';
2728
import { ReactNativeProfiler, ReactNativeTracing } from './tracing';
28-
import { DEFAULT_BUFFER_SIZE, makeReactNativeTransport } from './transports/native';
29+
import { DEFAULT_BUFFER_SIZE, makeNativeTransportFactory } from './transports/native';
2930
import { makeUtf8TextEncoder } from './transports/TextEncoder';
3031
import { safeFactory, safeTracesSampler } from './utils/safe';
3132

@@ -64,7 +65,7 @@ export function init(passedOptions: ReactNativeOptions): void {
6465
...DEFAULT_OPTIONS,
6566
...passedOptions,
6667
// If custom transport factory fails the SDK won't initialize
67-
transport: passedOptions.transport || makeReactNativeTransport,
68+
transport: passedOptions.transport || makeNativeTransportFactory() || makeFetchTransport,
6869
transportOptions: {
6970
...DEFAULT_OPTIONS.transportOptions,
7071
...(passedOptions.transportOptions ?? {}),

src/js/transports/native.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ export class NativeTransport implements Transport {
4545
/**
4646
* Creates a Native Transport.
4747
*/
48-
export function makeReactNativeTransport(options: BaseNativeTransportOptions = {}): NativeTransport {
48+
export function makeNativeTransport(options: BaseNativeTransportOptions = {}): NativeTransport {
4949
return new NativeTransport(options);
5050
}
51+
52+
/**
53+
* Creates a Native Transport factory if the native transport is available.
54+
*/
55+
export function makeNativeTransportFactory(): typeof makeNativeTransport | null {
56+
if (NATIVE.isNativeTransportAvailable()) {
57+
return makeNativeTransport;
58+
}
59+
return null;
60+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* eslint-disable deprecation/deprecation */
2+
import { LogBox, YellowBox } from 'react-native';
3+
4+
/**
5+
* This is a workaround for now using fetch on RN, this is a known issue in react-native and only generates a warning
6+
* YellowBox deprecated and replaced with with LogBox in RN 0.63
7+
*/
8+
export function ignoreRequireCycleLogs(): void {
9+
if (LogBox) {
10+
LogBox.ignoreLogs(['Require cycle:']);
11+
} else {
12+
YellowBox.ignoreWarnings(['Require cycle:']);
13+
}
14+
}

test/sdk.test.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
import { logger } from '@sentry/utils';
55

6+
import { NATIVE } from '../src/js/wrapper';
7+
68
interface MockedClient {
79
flush: jest.Mock;
810
}
@@ -61,18 +63,24 @@ jest.mock('../src/js/client', () => {
6163
};
6264
});
6365

66+
jest.mock('../src/js/wrapper');
67+
6468
jest.spyOn(logger, 'error');
6569

6670
import { initAndBind } from '@sentry/core';
67-
import { getCurrentHub } from '@sentry/react';
71+
import { getCurrentHub, makeFetchTransport } from '@sentry/react';
6872
import { BaseTransportOptions,ClientOptions, Integration, Scope } from '@sentry/types';
6973

7074
import { ReactNativeClientOptions } from '../src/js/options';
7175
import { configureScope,flush, init, withScope } from '../src/js/sdk';
7276
import { ReactNativeTracing, ReactNavigationInstrumentation } from '../src/js/tracing';
77+
import { makeNativeTransport } from '../src/js/transports/native';
7378
import { firstArg, secondArg } from './testutils';
7479

7580
const mockedInitAndBind = initAndBind as jest.MockedFunction<typeof initAndBind>;
81+
const usedOptions = (): ClientOptions<BaseTransportOptions> | undefined => {
82+
return mockedInitAndBind.mock.calls[0]?.[1];
83+
}
7684

7785
afterEach(() => {
7886
jest.clearAllMocks();
@@ -184,10 +192,6 @@ describe('Tests the SDK functionality', () => {
184192
});
185193

186194
describe('transport options buffer size', () => {
187-
const usedOptions = (): ClientOptions<BaseTransportOptions> | undefined => {
188-
return mockedInitAndBind.mock.calls[0]?.[1];
189-
}
190-
191195
it('uses default transport options buffer size', () => {
192196
init({
193197
tracesSampleRate: 0.5,
@@ -214,6 +218,28 @@ describe('Tests the SDK functionality', () => {
214218
});
215219
});
216220

221+
describe('transport initialization', () => {
222+
it('uses transport from the options', () => {
223+
const mockTransport = jest.fn();
224+
init({
225+
transport: mockTransport,
226+
});
227+
expect(usedOptions()?.transport).toEqual(mockTransport);
228+
});
229+
230+
it('uses native transport', () => {
231+
(NATIVE.isNativeTransportAvailable as jest.Mock).mockImplementation(() => true);
232+
init({});
233+
expect(usedOptions()?.transport).toEqual(makeNativeTransport);
234+
});
235+
236+
it('uses fallback fetch transport', () => {
237+
(NATIVE.isNativeTransportAvailable as jest.Mock).mockImplementation(() => false);
238+
init({});
239+
expect(usedOptions()?.transport).toEqual(makeFetchTransport);
240+
});
241+
});
242+
217243
describe('initIsSafe', () => {
218244
test('initialScope callback is safe after init', () => {
219245
const mockInitialScope = jest.fn(() => { throw 'Test error' });

0 commit comments

Comments
 (0)