diff --git a/src/features/session_replay/replay-mode.js b/src/features/session_replay/replay-mode.js index 63c96ffb1..67fa5a4bb 100644 --- a/src/features/session_replay/replay-mode.js +++ b/src/features/session_replay/replay-mode.js @@ -15,8 +15,8 @@ export async function getSessionReplayMode (agentId) { const newrelic = gosNREUM() // Should be enabled by configuration and using an agent build that includes it (via checking that the instrument class was initialized). if (getConfigurationValue(agentId, 'session_replay.enabled') && typeof newrelic.initializedAgents[agentId].features.session_replay === 'object') { - await newrelic.initializedAgents[agentId].features.session_replay.onAggregateImported // if Replay could not initialize, this throws a (uncaught) rejection - return await sharedChannel.sessionReplayInitialized // wait for replay to determine which mode it's after running its sampling logic + const srInitialized = await newrelic.initializedAgents[agentId].features.session_replay.onAggregateImported + if (srInitialized) return await sharedChannel.sessionReplayInitialized // wait for replay to determine which mode it's after running its sampling logic } } catch (e) { /* exception ==> off */ } return MODE.OFF // at any step of the way s.t. SR cannot be on by implication or is explicitly off diff --git a/src/features/utils/instrument-base.js b/src/features/utils/instrument-base.js index 938f344fc..0d7d06c87 100644 --- a/src/features/utils/instrument-base.js +++ b/src/features/utils/instrument-base.js @@ -56,8 +56,8 @@ export class InstrumentBase extends FeatureBase { if (this.featAggregate || !this.auto) return const enableSessionTracking = isBrowserScope && getConfigurationValue(this.agentIdentifier, 'privacy.cookies_enabled') === true let loadedSuccessfully, loadFailed - this.onAggregateImported = new Promise((resolve, reject) => { - loadedSuccessfully = resolve; loadFailed = reject + this.onAggregateImported = new Promise(resolve => { + loadedSuccessfully = resolve }) const importLater = async () => { @@ -83,12 +83,12 @@ export class InstrumentBase extends FeatureBase { const { lazyFeatureLoader } = await import(/* webpackChunkName: "lazy-feature-loader" */ './lazy-feature-loader') const { Aggregate } = await lazyFeatureLoader(this.featureName, 'aggregate') this.featAggregate = new Aggregate(this.agentIdentifier, this.aggregator, argsObjFromInstrument) - loadedSuccessfully() + loadedSuccessfully(true) } catch (e) { warn(`Downloading and initializing ${this.featureName} failed...`, e) this.abortHandler?.() // undo any important alterations made to the page // not supported yet but nice to do: "abort" this agent's EE for this feature specifically - loadFailed() + loadedSuccessfully(false) } } diff --git a/src/features/utils/instrument-base.test.js b/src/features/utils/instrument-base.test.js index 40e0c6cd7..79b306a11 100644 --- a/src/features/utils/instrument-base.test.js +++ b/src/features/utils/instrument-base.test.js @@ -57,7 +57,7 @@ beforeEach(() => { aggregator = {} featureName = faker.datatype.uuid() - mockAggregate = jest.fn(() => { /* noop */ }) + mockAggregate = jest.fn() jest.mocked(lazyFeatureLoader).mockResolvedValue({ Aggregate: mockAggregate }) }) @@ -187,4 +187,23 @@ test('feature still imports by default even when setupAgentSession throws an err expect(warn).toHaveBeenCalledWith(expect.stringContaining('A problem occurred when starting up session manager'), expect.any(Error)) expect(lazyFeatureLoader).toHaveBeenCalled() expect(mockAggregate).toHaveBeenCalled() + await expect(instrument.onAggregateImported).resolves.toBe(true) +}) + +test('no uncaught async exception is thrown when an import fails', async () => { + jest.mocked(lazyFeatureLoader).mockRejectedValue(new Error('ChunkLoadError')) // () => { throw new Error('ChunkLoadError: loading chunk xxx failed.') }) + const mockOnError = jest.fn() + global.onerror = mockOnError + + const instrument = new InstrumentBase(agentIdentifier, aggregator, featureName) + instrument.abortHandler = jest.fn() + instrument.importAggregator() + + const windowLoadCallback = jest.mocked(onWindowLoad).mock.calls[0][0] + await windowLoadCallback() + + expect(warn).toHaveBeenNthCalledWith(2, expect.stringContaining(`Downloading and initializing ${featureName} failed`), expect.any(Error)) + expect(instrument.abortHandler).toHaveBeenCalled() + await expect(instrument.onAggregateImported).resolves.toBe(false) + expect(mockOnError).not.toHaveBeenCalled() })