UNPKG

newrelic-react-native-agent

Version:
520 lines (420 loc) 21.1 kB
/* * Copyright (c) 2022-present New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ import { Platform } from 'react-native'; import NewRelic from '../../index'; import MockNRM from '../../__mocks__/nrm-modular-agent'; import NRMAModularAgentWrapper from '../nrma-modular-agent-wrapper'; let testHandler = []; let tracker =[]; global.ErrorUtils = { setGlobalHandler: nrHandler => testHandler.push(nrHandler), getGlobalHandler: error => error, }; describe('New Relic', () => { beforeEach(() => { jest.clearAllMocks(); MockNRM.getReactNativeVersion = "0.66.3"; // mock that the native agents are started NRMAModularAgentWrapper.isAgentStarted = true; NewRelic.state.didAddErrorHandler = false; NewRelic.state.didAddPromiseRejection = false; NewRelic.state.didOverrideConsole = false; NewRelic.LOG.verbose = false; testHandler = []; }); it('should have sane default state', () => { expect(NewRelic.JSAppVersion).toBeFalsy(); expect(NewRelic.state.didAddPromiseRejection).toBe(false); expect(NewRelic.state.didAddErrorHandler).toBe(false); expect(NewRelic.state.didOverrideConsole).toBe(false); expect(NewRelic.LOG.verbose).toBe(false); }); it('should start and add our js error handler if the native agent isnt already running', () => { NRMAModularAgentWrapper.isAgentStarted = false; NewRelic.startAgent("12345"); expect(NewRelic.state.didAddErrorHandler).toBe(true); expect(NewRelic.state.didAddPromiseRejection).toBe(true); expect(NewRelic.state.didOverrideConsole).toBe(true); expect(NewRelic.LOG.verbose).toBe(true); expect(testHandler.length).toBe(1); }); it('should not call start multiple times if we are already running', () => { NewRelic.startAgent("12345"); NewRelic.startAgent("12345"); NewRelic.startAgent("12345"); NewRelic.startAgent("12345"); NewRelic.startAgent("12345"); NewRelic.startAgent("12345"); expect(NewRelic.state.didAddErrorHandler).toBe(true); expect(NewRelic.state.didAddPromiseRejection).toBe(true); expect(NewRelic.state.didOverrideConsole).toBe(true); expect(NewRelic.LOG.verbose).toBe(true); expect(testHandler.length).toBe(1); // native calls to the agent should not happen if we are already started expect(MockNRM.startAgent.mock.calls.length).toBe(6); }); it('should have correct default configuration settings', () => { expect(NewRelic.config.analyticsEventEnabled).toBe(true); expect(NewRelic.config.crashReportingEnabled).toBe(true); expect(NewRelic.config.interactionTracingEnabled).toBe(false); expect(NewRelic.config.networkRequestEnabled).toBe(true); expect(NewRelic.config.networkErrorRequestEnabled).toBe(true); expect(NewRelic.config.httpResponseBodyCaptureEnabled).toBe(true); expect(NewRelic.config.loggingEnabled).toBe(true); expect(NewRelic.config.logLevel).toBe(NewRelic.LogLevel.WARN); expect(NewRelic.config.webViewInstrumentation).toBe(true); expect(NewRelic.config.collectorAddress).toBe(""); expect(NewRelic.config.crashCollectorAddress).toBe(""); expect(NewRelic.config.fedRampEnabled).toBe(false); expect(NewRelic.config.nativeCrashReportingEnabled).toBe(false); expect(NewRelic.config.offlineStorageEnabled).toBe(true); expect(NewRelic.config.newEventSystemEnabled).toBe(false); expect(NewRelic.config.backgroundReportingEnabled).toBe(false); expect(NewRelic.config.distributedTracingEnabled).toBe(true); }); it('should change default agent configuration when configuration is passed into the start call', () => { const customerConfiguration = { analyticsEventEnabled: false, crashReportingEnabled: false, interactionTracingEnabled: false, networkRequestEnabled: false, networkErrorRequestEnabled: false, httpResponseBodyCaptureEnabled: false, loggingEnabled: false, logLevel: "AUDIT", webViewInstrumentation: false, collectorAddress: "gov-mobile-collector.newrelic.com", crashCollectorAddress: "gov-mobile-crash.newrelic.com", fedRampEnabled: true, nativeCrashReportingEnabled:false, offlineStorageEnabled:false, newEventSystemEnabled:false, backgroundReportingEnabled:true, distributedTracingEnabled: false }; NewRelic.startAgent("12345", customerConfiguration); expect(NewRelic.config.analyticsEventEnabled).toBe(false); expect(NewRelic.config.crashReportingEnabled).toBe(false); expect(NewRelic.config.interactionTracingEnabled).toBe(false); expect(NewRelic.config.networkRequestEnabled).toBe(false); expect(NewRelic.config.networkErrorRequestEnabled).toBe(false); expect(NewRelic.config.httpResponseBodyCaptureEnabled).toBe(false); expect(NewRelic.config.loggingEnabled).toBe(false); expect(NewRelic.config.logLevel).toBe("AUDIT"); expect(NewRelic.config.webViewInstrumentation).toBe(false); expect(NewRelic.config.collectorAddress).toBe("gov-mobile-collector.newrelic.com"); expect(NewRelic.config.crashCollectorAddress).toBe("gov-mobile-crash.newrelic.com"); expect(NewRelic.config.fedRampEnabled).toBe(true); expect(NewRelic.config.offlineStorageEnabled).toBe(false); expect(NewRelic.config.nativeCrashReportingEnabled).toBe(false); expect(NewRelic.config.newEventSystemEnabled).toBe(false); expect(NewRelic.config.backgroundReportingEnabled).toBe(true); expect(NewRelic.config.distributedTracingEnabled).toBe(false); }); it('should set the analytics event flag', () => { NewRelic.analyticsEventEnabled(true); NewRelic.analyticsEventEnabled(false); expect(MockNRM.analyticsEventEnabled.mock.calls.length).toBe(2); expect(NewRelic.config.analyticsEventEnabled).toBe(false); }); it('should set the network request flag', () => { NewRelic.networkRequestEnabled(true); NewRelic.networkRequestEnabled(false); expect(MockNRM.networkRequestEnabled.mock.calls.length).toBe(2); expect(NewRelic.config.networkRequestEnabled).toBe(false); }); it('should set the network error request flag', () => { NewRelic.networkErrorRequestEnabled(true); NewRelic.networkErrorRequestEnabled(false); expect(MockNRM.networkErrorRequestEnabled.mock.calls.length).toBe(2); expect(NewRelic.config.networkErrorRequestEnabled).toBe(false); }); it('should set the http response body flag', () => { NewRelic.httpResponseBodyCaptureEnabled(true); NewRelic.httpResponseBodyCaptureEnabled(false); expect(MockNRM.httpResponseBodyCaptureEnabled.mock.calls.length).toBe(2); expect(NewRelic.config.httpResponseBodyCaptureEnabled).toBe(false); }); it('should record a valid breadcrumb', () => { NewRelic.recordBreadcrumb('testName', { test: 123, valid: 'yes' }); NewRelic.recordBreadcrumb(null, { test: 123, valid: 'no' }); expect(MockNRM.recordBreadcrumb.mock.calls.length).toBe(1); }); it('should not record a bad breadcrumb', () => { NewRelic.recordBreadcrumb(null, { test: 123, valid: 'no' }); expect(MockNRM.recordBreadcrumb.mock.calls.length).toBe(0); }); it('should not start InterAction', () => { NewRelic.startInteraction(); expect(MockNRM.startInteraction.mock.calls.length).toBe(0); }); it('should not End InterAction', () => { NewRelic.endInteraction(); expect(MockNRM.endInteraction.mock.calls.length).toBe(0); }); it('should record a valid Custom Event', () => { NewRelic.recordCustomEvent('eventType', 'eventName', { test: 123, valid: 'yes' }); NewRelic.recordCustomEvent('eventType', '', { test: 123, valid: 'yes' }); NewRelic.recordCustomEvent('eventType', undefined, { test: 123, valid: 'yes' }); expect(MockNRM.recordCustomEvent.mock.calls.length).toBe(3); }); it('should not record a bad Custom Event', () => { NewRelic.recordCustomEvent('eventType', null, { test: 123, valid: 'yes' }); NewRelic.recordCustomEvent('eventType', [], { test: 123, valid: 'yes' }); NewRelic.recordCustomEvent('eventType', {}, { test: 123, valid: 'yes' }); expect(MockNRM.recordCustomEvent.mock.calls.length).toBe(0); }); it('should crash on call with a valid message', () => { NewRelic.crashNow(); expect(MockNRM.crashNow.mock.calls.length).toBe(1); NewRelic.crashNow('crash message'); expect(MockNRM.crashNow.mock.calls.length).toBe(2); }); it('should return the current session id', () => { NewRelic.currentSessionId(); expect(MockNRM.currentSessionId.mock.calls.length).toBe(1); }); it('should notice http transactions with correct params', () => { NewRelic.noticeHttpTransaction("https://newrelic.com", "GET", 200, Date.now(), Date.now()+100, 100, 200, "fake body"); NewRelic.noticeHttpTransaction("https://newrelic.com", "POST", 200, Date.now(), Date.now()+100, 100, 200, "fake body"); NewRelic.noticeHttpTransaction("https://newrelic.com", "GET", 400, Date.now(), Date.now()+100, 100, 200, "fake body"); expect(MockNRM.noticeHttpTransaction.mock.calls.length).toBe(3); }); it('should notice network failure with correct params', () => { NewRelic.noticeNetworkFailure("https://newrelic.com", "POST", Date.now(), Date.now(), NewRelic.NetworkFailure.Unknown); NewRelic.noticeNetworkFailure("https://newrelic.com", "POST", Date.now(), Date.now(), NewRelic.NetworkFailure.BadURL); NewRelic.noticeNetworkFailure("https://newrelic.com", "POST", Date.now(), Date.now(), NewRelic.NetworkFailure.CannotConnectToHost); NewRelic.noticeNetworkFailure("https://newrelic.com", "POST", Date.now(), Date.now(), NewRelic.NetworkFailure.DNSLookupFailed); NewRelic.noticeNetworkFailure("https://newrelic.com", "POST", Date.now(), Date.now(), NewRelic.NetworkFailure.BadServerResponse); NewRelic.noticeNetworkFailure("https://newrelic.com", "POST", Date.now(), Date.now(), NewRelic.NetworkFailure.SecureConnectionFailed); expect(MockNRM.noticeNetworkFailure.mock.calls.length).toBe(6); }); it('should not notice network failure with bad failure name', () => { NewRelic.noticeNetworkFailure("https://newrelic.com", "GET", Date.now(), Date.now(), '404'); NewRelic.noticeNetworkFailure("https://newrelic.com", "GET", Date.now(), Date.now(), 'randomname'); expect(MockNRM.noticeNetworkFailure.mock.calls.length).toBe(0); }); it('should record metric with correct params', () => { NewRelic.recordMetric('fakeName', 'fakeCategory'); NewRelic.recordMetric('fakeName', 'fakeCategory', 13) NewRelic.recordMetric('fakeName', 'fakeCategory', 21, NewRelic.MetricUnit.PERCENT, NewRelic.MetricUnit.SECONDS); expect(MockNRM.recordMetric.mock.calls.length).toBe(3); }); it('should not record metric with bad params', () => { NewRelic.recordMetric('fakeName', 'fakeCategory', 2, NewRelic.MetricUnit.SECONDS); NewRelic.recordMetric('fakeName', 'fakeCategory', -1, NewRelic.MetricUnit.SECONDS, NewRelic.MetricUnit.PERCENT); NewRelic.recordMetric('fakeName', 'fakeCategory', 10, null, NewRelic.MetricUnit.BYTES_PER_SECOND); NewRelic.recordMetric('fakeName', 'fakeCategory', 3, NewRelic.MetricUnit.MINUTES, NewRelic.MetricUnit.SECONDS); NewRelic.recordMetric('fakeName', 'fakeCategory', 3, NewRelic.MetricUnit.PERCENT, NewRelic.MetricUnit.HOURS); NewRelic.recordMetric('fakeName', 'fakeCategory', 3, "DAYS", "HOURS"); expect(MockNRM.recordMetric.mock.calls.length).toBe(0); }); it('should remove all attributes', () => { NewRelic.removeAllAttributes(); expect(MockNRM.removeAllAttributes.mock.calls.length).toBe(1); }); it('should record JS error with a given valid error', async () => { NewRelic.setJSAppVersion('new version 123'); await NewRelic.recordError(new TypeError); await NewRelic.recordError(new Error); await NewRelic.recordError(new EvalError); await NewRelic.recordError(new RangeError); await NewRelic.recordError(new ReferenceError); await NewRelic.recordError('fakeErrorName'); expect(MockNRM.recordHandledException.mock.calls.length).toBe(6); }); it('should not record JS error with a bad error', async () => { NewRelic.setJSAppVersion('123'); await NewRelic.recordError(undefined); await NewRelic.recordError(null); await NewRelic.recordError(123); await NewRelic.recordError(true); await NewRelic.recordError(''); expect(MockNRM.recordHandledException.mock.calls.length).toBe(0); }); it('should set max event buffer time', () => { NewRelic.setMaxEventBufferTime(120); expect(MockNRM.setMaxEventBufferTime.mock.calls.length).toBe(1); }); it('should set max event pool size', () => { NewRelic.setMaxEventPoolSize(2000); expect(MockNRM.setMaxEventPoolSize.mock.calls.length).toBe(1); }); it('should set max offline storage size', () => { NewRelic.setMaxOfflineStorageSize(100); expect(MockNRM.setMaxOfflineStorageSize.mock.calls.length).toBe(1); expect(MockNRM.setMaxOfflineStorageSize.mock.calls[0][0]).toBe(100); }); it('should not set max offline storage size with invalid size', () => { NewRelic.setMaxOfflineStorageSize(null); NewRelic.setMaxOfflineStorageSize('100'); NewRelic.setMaxOfflineStorageSize(true); NewRelic.setMaxOfflineStorageSize(-100); expect(MockNRM.setMaxOfflineStorageSize.mock.calls.length).toBe(4); }); it('should set a valid Attribute', () => { NewRelic.setAttribute('eventType', 'eventName'); NewRelic.setAttribute('eventType', 123); NewRelic.setAttribute('eventType', true); NewRelic.setAttribute('eventType', false); expect(MockNRM.setStringAttribute.mock.calls.length).toBe(1); expect(MockNRM.setNumberAttribute.mock.calls.length).toBe(1); expect(MockNRM.setBoolAttribute.mock.calls.length).toBe(2); }); it('should not set bad attributes', () => { NewRelic.setAttribute(null, null); NewRelic.setAttribute(null, 'yes'); NewRelic.setAttribute('yes', null); NewRelic.setAttribute(123, null); NewRelic.setAttribute(true, null); NewRelic.setAttribute('true', undefined); NewRelic.setAttribute('', undefined); expect(MockNRM.setStringAttribute.mock.calls.length).toBe(0); expect(MockNRM.setNumberAttribute.mock.calls.length).toBe(0); expect(MockNRM.setBoolAttribute.mock.calls.length).toBe(0); }); it('should increment attributes', () => { NewRelic.incrementAttribute('eventType'); expect(MockNRM.incrementAttribute.mock.calls.length).toBe(1); NewRelic.incrementAttribute('eventTypeWithValue', 100); expect(MockNRM.incrementAttribute.mock.calls.length).toBe(2); }); it('should not increment attributes with bad values', () => { NewRelic.incrementAttribute(null, null); NewRelic.incrementAttribute(null, 2); NewRelic.incrementAttribute('yes', null); NewRelic.incrementAttribute('', undefined); NewRelic.incrementAttribute(null); NewRelic.incrementAttribute(undefined); NewRelic.incrementAttribute('bool', true); expect(MockNRM.incrementAttribute.mock.calls.length).toBe(0); }); it('should set a valid js app version', () => { NewRelic.setJSAppVersion('new version 123'); NewRelic.setJSAppVersion('12.12.12'); expect(MockNRM.setJSAppVersion.mock.calls.length).toBe(2); }); it('should not set a bad js app version', () => { NewRelic.setJSAppVersion(null); expect(MockNRM.setJSAppVersion.mock.calls.length).toBe(0); }); it('should set a valid User Id', () => { NewRelic.setUserId('new version 123'); NewRelic.setUserId('12.12.12'); expect(MockNRM.setUserId.mock.calls.length).toBe(2); }); it('should record to start method Interaction', () => { NewRelic.startInteraction('Start InterAction'); expect(MockNRM.startInteraction.mock.calls.length).toBe(1); }); it('should end method Interaction', () => { NewRelic.endInteraction('Start InterAction'); expect(MockNRM.endInteraction.mock.calls.length).toBe(1); }); it('should not set a bad User Id', () => { NewRelic.setUserId(null); NewRelic.setUserId(123); NewRelic.setUserId(true); NewRelic.setUserId([]); NewRelic.setUserId({}); NewRelic.setUserId(undefined); expect(MockNRM.setUserId.mock.calls.length).toBe(0); }); it('calling start multiple times should only add one new relic error handler', () => { NewRelic.startAgent(); NewRelic.startAgent(); NewRelic.startAgent(); expect(testHandler.length).toBe(1); }); it('should ignore calls if the agent is not started', () => { NRMAModularAgentWrapper.isAgentStarted = false; NewRelic.setJSAppVersion('new version 123'); expect(MockNRM.setJSAppVersion.mock.calls.length).toBe(0); }); it('should know if its running or not', () => { NRMAModularAgentWrapper.isAgentStarted = false; expect(NewRelic.isAgentStarted()).toBeFalsy(); NRMAModularAgentWrapper.isAgentStarted = true; expect(NewRelic.isAgentStarted()).toBeTruthy(); }); it('sends console.log to record custom Events', () => { // Each agent start call is 2 custom event calls (5 actual calls prior to this test) = 10 NewRelic.startAgent("12345"); console.log('hello'); expect(MockNRM.recordCustomEvent.mock.calls.length).toBe(0); }); it('sends console.warn to record custom Events', () => { // Each agent start call is 2 custom event calls (12 actual calls prior to this test) + 1 console log test = 25 NewRelic.startAgent("12345"); console.log('hello'); console.warn('hello'); console.error('hello'); expect(MockNRM.recordCustomEvent.mock.calls.length).toBe(0); }); it('sends breadcrumb for navigation if it is not first screen', () => { NewRelic.state.isFirstScreen = false; var event = {"initialProps":{"componentId":"Component4"},"rootTag":11}; NewRelic.componentDidAppearListener(event); expect(MockNRM.recordBreadcrumb.mock.calls.length).toBe(1); }); it('not sending breadcrumb for navigation if it is first screen', () => { NewRelic.state.isFirstScreen = false; var event = {"initialProps":{"componentId":"Component4"},"rootTag":11}; NewRelic.componentDidAppearListener(event); expect(MockNRM.recordBreadcrumb.mock.calls.length).toBe(0); }); it('sends breadcrumb from navigationStateChange Listener', () => { NewRelic.state.isFirstScreen = false; var newState = {"index": 1, "isTransitioning": false, "key": "StackRouterRoot", "routes": [{"key": "id-1660675098665-0", "routeName": "Home"}, {"key": "id-1660675098665-1", "params": [Object], "routeName": "Profile"}]}; NewRelic.onNavigationStateChange('',newState,''); expect(MockNRM.recordBreadcrumb.mock.calls.length).toBe(1); }); it('sends breadcrumb from statechange Listener', () => { NewRelic.state.isFirstScreen = false; var newState = {"index": 1, "key": "stack-YjJKdS9Cyw2S_9eqBwGy5", "routeNames": ["Home", "HttpDemo", "ErrorDemo", "CustomDataDemo"], "routes": [{"key": "Home-04bWmlOhC_9ZpO6vsNNai", "name": "Home", "params": undefined}, {"key": "HttpDemo-zQsn6TtkDwiNm4A4OSw32", "name": "HttpDemo", "params": [Object], "path": undefined}], "stale": false, "type": "stack"}; NewRelic.onStateChange(newState); expect(MockNRM.recordBreadcrumb.mock.calls.length).toBe(1); }); it('should shutdown when called', () => { expect(NRMAModularAgentWrapper.isAgentStarted).toBe(true); NewRelic.shutdown(); expect(MockNRM.shutdown.mock.calls.length).toBe(1); expect(NRMAModularAgentWrapper.isAgentStarted).toBe(false); }); it('should addHTTPHeadersTrackingFor when called', () => { expect(NRMAModularAgentWrapper.isAgentStarted).toBe(true); NewRelic.addHTTPHeadersTrackingFor(["Car","Music"]); expect(MockNRM.addHTTPHeadersTrackingFor.mock.calls.length).toBe(1); }); it('should logAttributes when called', () => { expect(NRMAModularAgentWrapper.isAgentStarted).toBe(true); NewRelic.logInfo('test'); NewRelic.log(NewRelic.LogLevel.ERROR, 'test'); var attr = {"key1":"value1","key2":"value2"}; var error = new Error('test'); NewRelic.logAll(error,attr); expect(MockNRM.logAttributes.mock.calls.length).toBe(3); }); it('should not call logAttributes', () => { expect(NRMAModularAgentWrapper.isAgentStarted).toBe(true); NewRelic.logInfo(); expect(MockNRM.logAttributes.mock.calls.length).toBe(6); }); it('should not call logAttributes', () => { expect(NRMAModularAgentWrapper.isAgentStarted).toBe(true); NewRelic.logAttributes({}); expect(MockNRM.logAttributes.mock.calls.length).toBe(6); }); it('should call recordReplay when called', () => { expect(NRMAModularAgentWrapper.isAgentStarted).toBe(true); NewRelic.recordReplay(); expect(MockNRM.recordReplay.mock.calls.length).toBe(1); }); it('should call pauseReplay when called', () => { expect(NRMAModularAgentWrapper.isAgentStarted).toBe(true); NewRelic.pauseReplay(); expect(MockNRM.pauseReplay.mock.calls.length).toBe(1); }); });