Skip to content

Commit e99b333

Browse files
authored
[MOB-10128] Increase JavaScript Test Coverage (#799)
* Test the `Trace` model * Test native `IBGAPM.startExecutionTrace` returns ID * Test uncovered `BugReporting` code * Test uncovered `NetworkLogger` code * Test uncovered `Instabug` code * Increase `APM` branch test coverage * Increase `Surveys` branch test coverage * Increase `Replies` branch test coverage * Increase `Instabug` branch test coverage * Test `Interceptor` stringifies request header values * Test `getActiveRoute` util * Test `getFullRoute` and `setOnReportHandler` util * Fix `xhr2` warning about GET request body * Increase `InstabugUtils` test coverage * Increase `XhrNetworkInterceptor` test coverage * Update test module CI Node version to 16.17 * Increase coverage target to 90%
1 parent b1590f9 commit e99b333

15 files changed

+632
-29
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
test_module:
1313
working_directory: ~/project
1414
docker:
15-
- image: circleci/node:10
15+
- image: cimg/node:16.17.1
1616
steps:
1717
- checkout:
1818
path: ~/project

codecov.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ coverage:
1010
status:
1111
patch:
1212
default:
13-
target: 75%
13+
target: 90%
1414
project:
1515
default:
16-
target: 75%
16+
target: 90%

tests/mocks/fakeNetworkRequest.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ export default {
1616
setResponseType(type) {
1717
xhr.responseType = type;
1818
},
19-
mockStatus(request, status) {
20-
request.setStatus(status);
19+
mockHasError() {
20+
xhr._hasError = true;
21+
},
22+
mockXHRStatus(status) {
23+
xhr.status = status;
2124
},
2225
mockResponse(request, status = 200, body = 'ok', headers) {
2326
request.once().reply(status, body, headers);

tests/mocks/mockInstabugUtils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ jest.mock('../../src/utils/InstabugUtils', () => {
77
getActiveRouteName: jest.fn(),
88
stringifyIfNotString: jest.fn(),
99
getStackTrace: jest.fn().mockReturnValue('javascriptStackTrace'),
10+
getFullRoute: jest.fn().mockImplementation(() => 'ScreenName'),
1011
};
1112
});

tests/mocks/mockParseErrorStackLib.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
jest.mock('react-native/Libraries/Core/Devtools/parseErrorStack', () => {
2+
const { Platform } = jest.requireActual('react-native');
3+
4+
// This mock's goal is to provide a parseErrorStack function that adapts to the mock React Native version
5+
// This mock should work as long as the tests run with React Native version < 0.64
6+
return jest.fn(error => {
7+
const originalParseErrorStack = jest.requireActual(
8+
'react-native/Libraries/Core/Devtools/parseErrorStack',
9+
);
10+
11+
if (!Platform.hasOwnProperty('constants') || Platform.constants.reactNativeVersion.minor < 64) {
12+
return originalParseErrorStack(error);
13+
}
14+
15+
const wrapperError = new Error();
16+
wrapperError.stack = error;
17+
18+
return originalParseErrorStack(wrapperError);
19+
});
20+
});

tests/models/Trace.spec.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { NativeModules } from 'react-native';
2+
import Trace from '../../src/models/Trace';
3+
4+
const { IBGAPM: NativeAPM } = NativeModules;
5+
6+
describe('Trace Model', () => {
7+
it('should set the id, name and attributes if passed', () => {
8+
const id = 'trace-id';
9+
const name = 'my-trace';
10+
const attributes = { screen: 'login' };
11+
const trace = new Trace(id, name, attributes);
12+
13+
expect(trace.id).toBe(id);
14+
expect(trace.name).toBe(name);
15+
expect(trace.attributes).toBe(attributes);
16+
});
17+
18+
it('should set execution trace attributes', () => {
19+
const attribute = { key: 'isAuthenticated', value: true };
20+
21+
const trace = new Trace('trace-id');
22+
trace.setAttribute(attribute.key, attribute.value);
23+
24+
expect(trace.attributes[attribute.key]).toBe(attribute.value);
25+
expect(NativeAPM.setExecutionTraceAttribute).toBeCalledTimes(1);
26+
expect(NativeAPM.setExecutionTraceAttribute).toBeCalledWith(
27+
trace.id,
28+
attribute.key,
29+
attribute.value,
30+
);
31+
});
32+
33+
it('should end execution trace', () => {
34+
const trace = new Trace('trace-id');
35+
36+
trace.end();
37+
38+
expect(NativeAPM.endExecutionTrace).toBeCalledTimes(1);
39+
expect(NativeAPM.endExecutionTrace).toBeCalledWith(trace.id);
40+
});
41+
});

tests/modules/APM.spec.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { NativeModules, Platform } from 'react-native';
2+
import Trace from '../../src/models/Trace';
23
import APM from '../../src/modules/APM';
3-
import IBGEventEmitter from '../../src/utils/IBGEventEmitter';
44

55
const { Instabug: NativeInstabug, IBGAPM: NativeAPM } = NativeModules;
66

@@ -27,6 +27,13 @@ describe('APM Module', () => {
2727
expect(NativeInstabug.setNetworkLoggingEnabled).toBeCalledWith(true);
2828
});
2929

30+
it('should not call the native method setNetworkEnabledIOS if platform is android', () => {
31+
Platform.OS = 'android';
32+
APM.setNetworkEnabledIOS(true);
33+
34+
expect(NativeInstabug.setNetworkLoggingEnabled).not.toBeCalled();
35+
});
36+
3037
it('should call the native method endAppLaunch', () => {
3138
APM.endAppLaunch();
3239

@@ -59,6 +66,23 @@ describe('APM Module', () => {
5966
);
6067
});
6168

69+
it("should throw an error if native startExecutionTrace didn't return an ID", async () => {
70+
NativeAPM.startExecutionTrace.mockImplementationOnce((_, __, callback) => callback());
71+
72+
const promise = APM.startExecutionTrace('trace');
73+
74+
await expect(promise).rejects.toThrowError(/trace "trace" wasn't created/i);
75+
});
76+
77+
it('should resolve with an Trace object if native startExecutionTrace returned an ID', async () => {
78+
NativeAPM.startExecutionTrace.mockImplementationOnce((_, __, callback) => callback('trace-id'));
79+
80+
const promise = APM.startExecutionTrace('trace');
81+
82+
await expect(promise).resolves.toBeInstanceOf(Trace);
83+
await expect(promise).resolves.toHaveProperty('name', 'trace');
84+
});
85+
6286
it('should call the native method setExecutionTraceAttribute', () => {
6387
const trace = APM.startExecutionTrace('trace').then(() => {
6488
trace.setAttribute('key', 'value');

tests/modules/BugReporting.spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,15 @@ describe('Testing BugReporting Module', () => {
105105
expect(NativeBugReporting.show).toBeCalledWith(reportType, arrayOfOptions);
106106
});
107107

108+
it('should call the native method show with a reportType and default options to an empty array', () => {
109+
const reportType = BugReporting.reportType.bug;
110+
BugReporting.show(reportType);
111+
112+
expect(NativeBugReporting.show).toBeCalledTimes(1);
113+
114+
expect(NativeBugReporting.show).toBeCalledWith(reportType, []);
115+
});
116+
108117
it('should call the native method setOnInvokeHandler with a function', () => {
109118
const callback = jest.fn();
110119
BugReporting.onInvokeHandler(callback);
@@ -160,6 +169,12 @@ describe('Testing BugReporting Module', () => {
160169
expect(NativeBugReporting.setAutoScreenRecordingDuration).toBeCalledWith(30);
161170
});
162171

172+
it('should not call the native method setAutoScreenRecordingDuration on Android', () => {
173+
Platform.OS = 'android';
174+
BugReporting.setAutoScreenRecordingDurationIOS(30);
175+
expect(NativeBugReporting.setAutoScreenRecordingDuration).not.toBeCalled();
176+
});
177+
163178
it('should call the native method setViewHierarchyEnabled', () => {
164179
BugReporting.setViewHierarchyEnabled(true);
165180

@@ -179,6 +194,20 @@ describe('Testing BugReporting Module', () => {
179194
).toEqual(0);
180195
});
181196

197+
it('should call setDidSelectPromptOptionHandler event listener when platform is iOS', () => {
198+
Platform.OS = 'ios';
199+
const callback = jest.fn();
200+
const payload = { promptOption: 'bug' };
201+
202+
BugReporting.setDidSelectPromptOptionHandler(callback);
203+
IBGEventEmitter.emit(IBGConstants.DID_SELECT_PROMPT_OPTION_HANDLER, payload);
204+
205+
const listeners = IBGEventEmitter.getListeners(IBGConstants.DID_SELECT_PROMPT_OPTION_HANDLER);
206+
expect(listeners.length).toBe(1);
207+
expect(callback).toBeCalledTimes(1);
208+
expect(callback).toBeCalledWith(payload.promptOption);
209+
});
210+
182211
it('should call the native method setDidSelectPromptOptionHandler with a function', () => {
183212
Platform.OS = 'ios';
184213
const callback = jest.fn();

0 commit comments

Comments
 (0)