Skip to content

Commit

Permalink
[MOB-10128] Increase JavaScript Test Coverage (#799)
Browse files Browse the repository at this point in the history
* 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%
  • Loading branch information
a7medev authored Oct 10, 2022
1 parent b1590f9 commit e99b333
Show file tree
Hide file tree
Showing 15 changed files with 632 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
test_module:
working_directory: ~/project
docker:
- image: circleci/node:10
- image: cimg/node:16.17.1
steps:
- checkout:
path: ~/project
Expand Down
4 changes: 2 additions & 2 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ coverage:
status:
patch:
default:
target: 75%
target: 90%
project:
default:
target: 75%
target: 90%
7 changes: 5 additions & 2 deletions tests/mocks/fakeNetworkRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ export default {
setResponseType(type) {
xhr.responseType = type;
},
mockStatus(request, status) {
request.setStatus(status);
mockHasError() {
xhr._hasError = true;
},
mockXHRStatus(status) {
xhr.status = status;
},
mockResponse(request, status = 200, body = 'ok', headers) {
request.once().reply(status, body, headers);
Expand Down
1 change: 1 addition & 0 deletions tests/mocks/mockInstabugUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ jest.mock('../../src/utils/InstabugUtils', () => {
getActiveRouteName: jest.fn(),
stringifyIfNotString: jest.fn(),
getStackTrace: jest.fn().mockReturnValue('javascriptStackTrace'),
getFullRoute: jest.fn().mockImplementation(() => 'ScreenName'),
};
});
20 changes: 20 additions & 0 deletions tests/mocks/mockParseErrorStackLib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
jest.mock('react-native/Libraries/Core/Devtools/parseErrorStack', () => {
const { Platform } = jest.requireActual('react-native');

// This mock's goal is to provide a parseErrorStack function that adapts to the mock React Native version
// This mock should work as long as the tests run with React Native version < 0.64
return jest.fn(error => {
const originalParseErrorStack = jest.requireActual(
'react-native/Libraries/Core/Devtools/parseErrorStack',
);

if (!Platform.hasOwnProperty('constants') || Platform.constants.reactNativeVersion.minor < 64) {
return originalParseErrorStack(error);
}

const wrapperError = new Error();
wrapperError.stack = error;

return originalParseErrorStack(wrapperError);
});
});
41 changes: 41 additions & 0 deletions tests/models/Trace.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { NativeModules } from 'react-native';
import Trace from '../../src/models/Trace';

const { IBGAPM: NativeAPM } = NativeModules;

describe('Trace Model', () => {
it('should set the id, name and attributes if passed', () => {
const id = 'trace-id';
const name = 'my-trace';
const attributes = { screen: 'login' };
const trace = new Trace(id, name, attributes);

expect(trace.id).toBe(id);
expect(trace.name).toBe(name);
expect(trace.attributes).toBe(attributes);
});

it('should set execution trace attributes', () => {
const attribute = { key: 'isAuthenticated', value: true };

const trace = new Trace('trace-id');
trace.setAttribute(attribute.key, attribute.value);

expect(trace.attributes[attribute.key]).toBe(attribute.value);
expect(NativeAPM.setExecutionTraceAttribute).toBeCalledTimes(1);
expect(NativeAPM.setExecutionTraceAttribute).toBeCalledWith(
trace.id,
attribute.key,
attribute.value,
);
});

it('should end execution trace', () => {
const trace = new Trace('trace-id');

trace.end();

expect(NativeAPM.endExecutionTrace).toBeCalledTimes(1);
expect(NativeAPM.endExecutionTrace).toBeCalledWith(trace.id);
});
});
26 changes: 25 additions & 1 deletion tests/modules/APM.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NativeModules, Platform } from 'react-native';
import Trace from '../../src/models/Trace';
import APM from '../../src/modules/APM';
import IBGEventEmitter from '../../src/utils/IBGEventEmitter';

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

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

it('should not call the native method setNetworkEnabledIOS if platform is android', () => {
Platform.OS = 'android';
APM.setNetworkEnabledIOS(true);

expect(NativeInstabug.setNetworkLoggingEnabled).not.toBeCalled();
});

it('should call the native method endAppLaunch', () => {
APM.endAppLaunch();

Expand Down Expand Up @@ -59,6 +66,23 @@ describe('APM Module', () => {
);
});

it("should throw an error if native startExecutionTrace didn't return an ID", async () => {
NativeAPM.startExecutionTrace.mockImplementationOnce((_, __, callback) => callback());

const promise = APM.startExecutionTrace('trace');

await expect(promise).rejects.toThrowError(/trace "trace" wasn't created/i);
});

it('should resolve with an Trace object if native startExecutionTrace returned an ID', async () => {
NativeAPM.startExecutionTrace.mockImplementationOnce((_, __, callback) => callback('trace-id'));

const promise = APM.startExecutionTrace('trace');

await expect(promise).resolves.toBeInstanceOf(Trace);
await expect(promise).resolves.toHaveProperty('name', 'trace');
});

it('should call the native method setExecutionTraceAttribute', () => {
const trace = APM.startExecutionTrace('trace').then(() => {
trace.setAttribute('key', 'value');
Expand Down
29 changes: 29 additions & 0 deletions tests/modules/BugReporting.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ describe('Testing BugReporting Module', () => {
expect(NativeBugReporting.show).toBeCalledWith(reportType, arrayOfOptions);
});

it('should call the native method show with a reportType and default options to an empty array', () => {
const reportType = BugReporting.reportType.bug;
BugReporting.show(reportType);

expect(NativeBugReporting.show).toBeCalledTimes(1);

expect(NativeBugReporting.show).toBeCalledWith(reportType, []);
});

it('should call the native method setOnInvokeHandler with a function', () => {
const callback = jest.fn();
BugReporting.onInvokeHandler(callback);
Expand Down Expand Up @@ -160,6 +169,12 @@ describe('Testing BugReporting Module', () => {
expect(NativeBugReporting.setAutoScreenRecordingDuration).toBeCalledWith(30);
});

it('should not call the native method setAutoScreenRecordingDuration on Android', () => {
Platform.OS = 'android';
BugReporting.setAutoScreenRecordingDurationIOS(30);
expect(NativeBugReporting.setAutoScreenRecordingDuration).not.toBeCalled();
});

it('should call the native method setViewHierarchyEnabled', () => {
BugReporting.setViewHierarchyEnabled(true);

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

it('should call setDidSelectPromptOptionHandler event listener when platform is iOS', () => {
Platform.OS = 'ios';
const callback = jest.fn();
const payload = { promptOption: 'bug' };

BugReporting.setDidSelectPromptOptionHandler(callback);
IBGEventEmitter.emit(IBGConstants.DID_SELECT_PROMPT_OPTION_HANDLER, payload);

const listeners = IBGEventEmitter.getListeners(IBGConstants.DID_SELECT_PROMPT_OPTION_HANDLER);
expect(listeners.length).toBe(1);
expect(callback).toBeCalledTimes(1);
expect(callback).toBeCalledWith(payload.promptOption);
});

it('should call the native method setDidSelectPromptOptionHandler with a function', () => {
Platform.OS = 'ios';
const callback = jest.fn();
Expand Down
Loading

0 comments on commit e99b333

Please sign in to comment.