@newrelic/browser-agent 1.233.1 → 1.235.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/constants/shared-channel.js +19 -0
- package/dist/cjs/common/event-emitter/contextual-ee.test.js +10 -10
- package/dist/cjs/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
- package/dist/cjs/common/harvest/harvest-scheduler.js +21 -5
- package/dist/cjs/common/harvest/harvest.component-test.js +224 -0
- package/dist/cjs/common/harvest/harvest.js +4 -11
- package/dist/cjs/common/session/{session-entity.test.js → session-entity.component-test.js} +79 -42
- package/dist/cjs/common/session/session-entity.js +19 -11
- package/dist/cjs/common/timer/interaction-timer.js +1 -1
- package/dist/cjs/common/url/canonicalize-url.test.js +26 -30
- package/dist/cjs/common/url/encode.js +2 -2
- package/dist/cjs/common/util/console.test.js +30 -0
- package/dist/cjs/common/util/data-size.test.js +37 -20
- package/dist/cjs/common/util/feature-flags.js +23 -12
- package/dist/cjs/common/util/feature-flags.test.js +84 -0
- package/dist/cjs/common/util/get-or-set.js +8 -1
- package/dist/cjs/common/util/get-or-set.test.js +47 -0
- package/dist/cjs/common/util/global-scope.js +1 -32
- package/dist/cjs/common/util/global-scope.test.js +72 -0
- package/dist/cjs/common/util/obfuscate.component-test.js +129 -0
- package/dist/cjs/common/util/obfuscate.js +2 -2
- package/dist/cjs/common/util/stringify.test.js +48 -0
- package/dist/cjs/common/util/submit-data.js +18 -18
- package/dist/cjs/common/util/submit-data.test.js +245 -0
- package/dist/cjs/common/util/traverse.js +19 -27
- package/dist/cjs/common/util/traverse.test.js +44 -0
- package/dist/cjs/common/wrap/wrap-raf.js +1 -1
- package/dist/cjs/common/wrap/wrap-timer.js +1 -1
- package/dist/cjs/features/jserrors/aggregate/index.js +4 -0
- package/dist/cjs/features/jserrors/instrument/index.js +2 -15
- package/dist/cjs/features/metrics/aggregate/endpoint-map.js +14 -0
- package/dist/cjs/features/metrics/aggregate/index.js +3 -2
- package/dist/cjs/features/metrics/instrument/index.js +0 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +58 -44
- package/dist/cjs/features/session_replay/aggregate/index.component-test.js +457 -0
- package/dist/cjs/features/session_replay/aggregate/index.js +99 -82
- package/dist/cjs/features/session_replay/replay-mode.js +28 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +222 -99
- package/dist/cjs/features/session_trace/constants.js +1 -3
- package/dist/cjs/features/session_trace/instrument/index.js +0 -16
- package/dist/cjs/features/spa/constants.js +0 -1
- package/dist/cjs/features/utils/agent-session.js +20 -36
- package/dist/cjs/features/utils/agent-session.test.js +211 -0
- package/dist/cjs/features/utils/aggregate-base.js +7 -12
- package/dist/cjs/features/utils/aggregate-base.test.js +110 -0
- package/dist/cjs/features/utils/feature-base.test.js +42 -0
- package/dist/cjs/features/utils/handler-cache.js +28 -23
- package/dist/cjs/features/utils/handler-cache.test.js +53 -0
- package/dist/cjs/features/utils/instrument-base.js +58 -39
- package/dist/cjs/features/utils/instrument-base.test.js +179 -0
- package/dist/cjs/features/utils/lazy-feature-loader.test.js +30 -0
- package/dist/cjs/loaders/agent.js +0 -1
- package/dist/cjs/loaders/api/api.js +1 -1
- package/dist/cjs/loaders/configure/configure.js +0 -1
- package/dist/cjs/loaders/features/featureDependencies.js +2 -0
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/constants/shared-channel.js +12 -0
- package/dist/esm/common/event-emitter/contextual-ee.test.js +10 -10
- package/dist/esm/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
- package/dist/esm/common/harvest/harvest-scheduler.js +21 -5
- package/dist/esm/common/harvest/harvest.component-test.js +222 -0
- package/dist/esm/common/harvest/harvest.js +4 -11
- package/dist/esm/common/session/{session-entity.test.js → session-entity.component-test.js} +77 -40
- package/dist/esm/common/session/session-entity.js +17 -11
- package/dist/esm/common/timer/interaction-timer.js +1 -1
- package/dist/esm/common/url/canonicalize-url.test.js +25 -29
- package/dist/esm/common/url/encode.js +2 -2
- package/dist/esm/common/util/console.test.js +28 -0
- package/dist/esm/common/util/data-size.test.js +35 -20
- package/dist/esm/common/util/feature-flags.js +23 -12
- package/dist/esm/common/util/feature-flags.test.js +80 -0
- package/dist/esm/common/util/get-or-set.js +8 -1
- package/dist/esm/common/util/get-or-set.test.js +45 -0
- package/dist/esm/common/util/global-scope.js +1 -29
- package/dist/esm/common/util/global-scope.test.js +70 -0
- package/dist/esm/common/util/obfuscate.component-test.js +125 -0
- package/dist/esm/common/util/obfuscate.js +2 -2
- package/dist/esm/common/util/stringify.test.js +46 -0
- package/dist/esm/common/util/submit-data.js +18 -18
- package/dist/esm/common/util/submit-data.test.js +241 -0
- package/dist/esm/common/util/traverse.js +19 -27
- package/dist/esm/common/util/traverse.test.js +42 -0
- package/dist/esm/common/wrap/wrap-raf.js +1 -1
- package/dist/esm/common/wrap/wrap-timer.js +1 -1
- package/dist/esm/features/jserrors/aggregate/index.js +4 -0
- package/dist/esm/features/jserrors/instrument/index.js +2 -15
- package/dist/esm/features/metrics/aggregate/endpoint-map.js +7 -0
- package/dist/esm/features/metrics/aggregate/index.js +3 -2
- package/dist/esm/features/metrics/instrument/index.js +0 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +58 -44
- package/dist/esm/features/session_replay/aggregate/index.component-test.js +453 -0
- package/dist/esm/features/session_replay/aggregate/index.js +92 -78
- package/dist/esm/features/session_replay/replay-mode.js +23 -0
- package/dist/esm/features/session_trace/aggregate/index.js +223 -100
- package/dist/esm/features/session_trace/constants.js +0 -1
- package/dist/esm/features/session_trace/instrument/index.js +1 -17
- package/dist/esm/features/spa/constants.js +0 -1
- package/dist/esm/features/utils/agent-session.js +21 -37
- package/dist/esm/features/utils/agent-session.test.js +207 -0
- package/dist/esm/features/utils/aggregate-base.js +7 -12
- package/dist/esm/features/utils/aggregate-base.test.js +108 -0
- package/dist/esm/features/utils/feature-base.test.js +40 -0
- package/dist/esm/features/utils/handler-cache.js +28 -23
- package/dist/esm/features/utils/handler-cache.test.js +51 -0
- package/dist/esm/features/utils/instrument-base.js +58 -39
- package/dist/esm/features/utils/instrument-base.test.js +175 -0
- package/dist/esm/features/utils/lazy-feature-loader.test.js +29 -0
- package/dist/esm/loaders/agent.js +0 -1
- package/dist/esm/loaders/api/api.js +2 -2
- package/dist/esm/loaders/configure/configure.js +0 -1
- package/dist/esm/loaders/features/featureDependencies.js +2 -0
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/constants/shared-channel.d.ts +5 -0
- package/dist/types/common/constants/shared-channel.d.ts.map +1 -0
- package/dist/types/common/context/shared-context.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts +2 -0
- package/dist/types/common/harvest/harvest-scheduler.component-test.d.ts.map +1 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts +4 -0
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.component-test.d.ts +2 -0
- package/dist/types/common/harvest/harvest.component-test.d.ts.map +1 -0
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.component-test.d.ts +2 -0
- package/dist/types/common/session/session-entity.component-test.d.ts.map +1 -0
- package/dist/types/common/session/session-entity.d.ts +9 -5
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/timer/interaction-timer.component-test.d.ts +2 -0
- package/dist/types/common/timer/interaction-timer.component-test.d.ts.map +1 -0
- package/dist/types/common/timer/timer.d.ts.map +1 -1
- package/dist/types/common/url/encode.component-test.d.ts +2 -0
- package/dist/types/common/url/encode.component-test.d.ts.map +1 -0
- package/dist/types/common/url/protocol.component-test.d.ts +2 -0
- package/dist/types/common/url/protocol.component-test.d.ts.map +1 -0
- package/dist/types/common/util/feature-flags.d.ts +1 -0
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/common/util/get-or-set.d.ts +9 -1
- package/dist/types/common/util/get-or-set.d.ts.map +1 -1
- package/dist/types/common/util/global-scope.d.ts +0 -9
- package/dist/types/common/util/global-scope.d.ts.map +1 -1
- package/dist/types/common/util/obfuscate.component-test.d.ts +2 -0
- package/dist/types/common/util/obfuscate.component-test.d.ts.map +1 -0
- package/dist/types/common/util/submit-data.d.ts +14 -10
- package/dist/types/common/util/submit-data.d.ts.map +1 -1
- package/dist/types/common/util/traverse.d.ts +10 -1
- package/dist/types/common/util/traverse.d.ts.map +1 -1
- package/dist/types/common/window/nreum.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +1 -0
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +8 -0
- package/dist/types/features/metrics/aggregate/endpoint-map.d.ts.map +1 -0
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -1
- package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.component-test.d.ts +2 -0
- package/dist/types/features/session_replay/aggregate/index.component-test.d.ts.map +1 -0
- package/dist/types/features/session_replay/aggregate/index.d.ts +14 -5
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/replay-mode.d.ts +9 -0
- package/dist/types/features/session_replay/replay-mode.d.ts.map +1 -0
- package/dist/types/features/session_trace/aggregate/index.d.ts +21 -3
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/constants.d.ts +0 -1
- package/dist/types/features/session_trace/constants.d.ts.map +1 -1
- package/dist/types/features/session_trace/instrument/index.d.ts +0 -2
- package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
- package/dist/types/features/spa/constants.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +6 -1
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/handler-cache.d.ts +12 -11
- package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts +17 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/agent.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
- package/package.json +14 -8
- package/src/common/config/state/init.js +0 -1
- package/src/common/constants/shared-channel.js +13 -0
- package/src/common/context/shared-context.js +0 -1
- package/src/common/event-emitter/contextual-ee.test.js +10 -10
- package/src/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js} +2 -2
- package/src/common/harvest/harvest-scheduler.js +17 -6
- package/src/common/harvest/harvest.component-test.js +169 -0
- package/src/common/harvest/harvest.js +5 -9
- package/src/common/session/{session-entity.test.js → session-entity.component-test.js} +70 -48
- package/src/common/session/session-entity.js +15 -12
- package/src/common/timer/interaction-timer.js +1 -1
- package/src/common/timer/timer.js +0 -1
- package/src/common/url/canonicalize-url.test.js +32 -21
- package/src/common/url/encode.js +2 -2
- package/src/common/util/console.test.js +34 -0
- package/src/common/util/data-size.test.js +27 -20
- package/src/common/util/feature-flags.js +24 -12
- package/src/common/util/feature-flags.test.js +98 -0
- package/src/common/util/get-or-set.js +8 -1
- package/src/common/util/get-or-set.test.js +58 -0
- package/src/common/util/global-scope.js +0 -26
- package/src/common/util/global-scope.test.js +87 -0
- package/src/common/util/obfuscate.component-test.js +173 -0
- package/src/common/util/obfuscate.js +2 -2
- package/src/common/util/stringify.test.js +49 -0
- package/src/common/util/submit-data.js +18 -19
- package/src/common/util/submit-data.test.js +226 -0
- package/src/common/util/traverse.js +18 -27
- package/src/common/util/traverse.test.js +50 -0
- package/src/common/window/nreum.js +0 -1
- package/src/common/wrap/wrap-raf.js +1 -1
- package/src/common/wrap/wrap-timer.js +1 -1
- package/src/features/jserrors/aggregate/index.js +5 -0
- package/src/features/jserrors/instrument/index.js +2 -15
- package/src/features/metrics/aggregate/endpoint-map.js +7 -0
- package/src/features/metrics/aggregate/index.js +3 -2
- package/src/features/metrics/aggregate/polyfill-detection.es5.js +0 -1
- package/src/features/metrics/instrument/index.js +0 -2
- package/src/features/page_view_event/aggregate/index.js +48 -51
- package/src/features/page_view_event/instrument/index.js +0 -1
- package/src/features/session_replay/aggregate/index.component-test.js +368 -0
- package/src/features/session_replay/aggregate/index.js +96 -71
- package/src/features/session_replay/instrument/index.js +0 -1
- package/src/features/session_replay/replay-mode.js +23 -0
- package/src/features/session_trace/aggregate/index.js +198 -79
- package/src/features/session_trace/constants.js +0 -1
- package/src/features/session_trace/instrument/index.js +2 -19
- package/src/features/spa/constants.js +0 -1
- package/src/features/utils/agent-session.js +22 -34
- package/src/features/utils/agent-session.test.js +194 -0
- package/src/features/utils/aggregate-base.js +12 -9
- package/src/features/utils/aggregate-base.test.js +122 -0
- package/src/features/utils/feature-base.test.js +45 -0
- package/src/features/utils/handler-cache.js +29 -24
- package/src/features/utils/handler-cache.test.js +72 -0
- package/src/features/utils/instrument-base.js +45 -29
- package/src/features/utils/instrument-base.test.js +190 -0
- package/src/features/utils/lazy-feature-loader.test.js +37 -0
- package/src/loaders/agent.js +0 -1
- package/src/loaders/api/api.js +2 -2
- package/src/loaders/configure/configure.js +0 -1
- package/src/loaders/features/featureDependencies.js +2 -0
- package/dist/cjs/common/storage/local-memory.js +0 -35
- package/dist/cjs/common/storage/local-memory.test.js +0 -20
- package/dist/cjs/common/util/s-hash.js +0 -19
- package/dist/cjs/features/metrics/instrument/workers-helper.js +0 -124
- package/dist/esm/common/storage/local-memory.js +0 -28
- package/dist/esm/common/storage/local-memory.test.js +0 -18
- package/dist/esm/common/util/s-hash.js +0 -13
- package/dist/esm/features/metrics/instrument/workers-helper.js +0 -119
- package/dist/types/common/storage/local-memory.d.ts +0 -8
- package/dist/types/common/storage/local-memory.d.ts.map +0 -1
- package/dist/types/common/util/s-hash.d.ts +0 -2
- package/dist/types/common/util/s-hash.d.ts.map +0 -1
- package/dist/types/features/metrics/instrument/workers-helper.d.ts +0 -7
- package/dist/types/features/metrics/instrument/workers-helper.d.ts.map +0 -1
- package/src/common/storage/local-memory.js +0 -30
- package/src/common/storage/local-memory.test.js +0 -19
- package/src/common/util/s-hash.js +0 -14
- package/src/features/metrics/instrument/workers-helper.js +0 -113
- /package/dist/cjs/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
- /package/dist/cjs/common/url/{encode.test.js → encode.component-test.js} +0 -0
- /package/dist/cjs/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
- /package/dist/esm/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
- /package/dist/esm/common/url/{encode.test.js → encode.component-test.js} +0 -0
- /package/dist/esm/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
- /package/src/common/timer/{interaction-timer.test.js → interaction-timer.component-test.js} +0 -0
- /package/src/common/url/{encode.test.js → encode.component-test.js} +0 -0
- /package/src/common/url/{protocol.test.js → protocol.component-test.js} +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _faker = require("@faker-js/faker");
|
|
4
|
+
var _instrumentBase = require("./instrument-base");
|
|
5
|
+
var _featureBase = require("./feature-base");
|
|
6
|
+
var _drain = require("../../common/drain/drain");
|
|
7
|
+
var _load = require("../../common/window/load");
|
|
8
|
+
var _lazyFeatureLoader = require("./lazy-feature-loader");
|
|
9
|
+
var _config = require("../../common/config/config");
|
|
10
|
+
var _agentSession = require("./agent-session");
|
|
11
|
+
var _console = require("../../common/util/console");
|
|
12
|
+
var globalScopeModule = _interopRequireWildcard(require("../../common/util/global-scope"));
|
|
13
|
+
var _features = require("../../loaders/features/features");
|
|
14
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
15
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
16
|
+
jest.enableAutomock();
|
|
17
|
+
jest.unmock('./instrument-base');
|
|
18
|
+
jest.unmock('../../loaders/features/features');
|
|
19
|
+
jest.mock('../../common/drain/drain', () => ({
|
|
20
|
+
__esModule: true,
|
|
21
|
+
drain: jest.fn(),
|
|
22
|
+
registerDrain: jest.fn()
|
|
23
|
+
}));
|
|
24
|
+
jest.mock('../../common/window/load', () => ({
|
|
25
|
+
__esModule: true,
|
|
26
|
+
onWindowLoad: jest.fn()
|
|
27
|
+
}));
|
|
28
|
+
jest.mock('../../common/util/global-scope', () => ({
|
|
29
|
+
__esModule: true,
|
|
30
|
+
isBrowserScope: undefined,
|
|
31
|
+
isWorkerScope: undefined
|
|
32
|
+
}));
|
|
33
|
+
jest.mock('../../common/config/config', () => ({
|
|
34
|
+
__esModule: true,
|
|
35
|
+
getConfigurationValue: jest.fn()
|
|
36
|
+
}));
|
|
37
|
+
jest.mock('./feature-base', () => ({
|
|
38
|
+
__esModule: true,
|
|
39
|
+
FeatureBase: jest.fn(function () {
|
|
40
|
+
this.agentIdentifier = arguments.length <= 0 ? undefined : arguments[0];
|
|
41
|
+
this.aggregator = arguments.length <= 1 ? undefined : arguments[1];
|
|
42
|
+
this.featureName = arguments.length <= 2 ? undefined : arguments[2];
|
|
43
|
+
})
|
|
44
|
+
}));
|
|
45
|
+
jest.mock('./agent-session', () => ({
|
|
46
|
+
__esModule: true,
|
|
47
|
+
setupAgentSession: jest.fn()
|
|
48
|
+
}));
|
|
49
|
+
let agentIdentifier;
|
|
50
|
+
let aggregator;
|
|
51
|
+
let featureName;
|
|
52
|
+
let mockAggregate;
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
jest.replaceProperty(globalScopeModule, 'isBrowserScope', true);
|
|
55
|
+
jest.replaceProperty(globalScopeModule, 'isWorkerScope', false);
|
|
56
|
+
agentIdentifier = _faker.faker.datatype.uuid();
|
|
57
|
+
aggregator = {};
|
|
58
|
+
featureName = _faker.faker.datatype.uuid();
|
|
59
|
+
mockAggregate = jest.fn(() => {/* noop */});
|
|
60
|
+
jest.mocked(_lazyFeatureLoader.lazyFeatureLoader).mockResolvedValue({
|
|
61
|
+
Aggregate: mockAggregate
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
test('should construct a new instrument', () => {
|
|
65
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
|
|
66
|
+
expect(_featureBase.FeatureBase).toHaveBeenCalledWith(agentIdentifier, aggregator, featureName);
|
|
67
|
+
expect(instrument.featAggregate).toBeUndefined();
|
|
68
|
+
expect(instrument.auto).toEqual(true);
|
|
69
|
+
expect(instrument.abortHandler).toBeUndefined();
|
|
70
|
+
expect(_drain.registerDrain).toHaveBeenCalledWith(agentIdentifier, featureName);
|
|
71
|
+
});
|
|
72
|
+
test('should not immediately drain', () => {
|
|
73
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName, false);
|
|
74
|
+
expect(_drain.registerDrain).not.toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
test('should import aggregator on window load', async () => {
|
|
77
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
|
|
78
|
+
const aggregateArgs = {
|
|
79
|
+
[_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
|
|
80
|
+
};
|
|
81
|
+
instrument.importAggregator(aggregateArgs);
|
|
82
|
+
const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
|
|
83
|
+
await windowLoadCallback();
|
|
84
|
+
expect(_load.onWindowLoad).toHaveBeenCalledWith(expect.any(Function), true);
|
|
85
|
+
expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(featureName, 'aggregate');
|
|
86
|
+
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
|
|
87
|
+
});
|
|
88
|
+
test('should immediately import aggregator in worker scope', async () => {
|
|
89
|
+
jest.replaceProperty(globalScopeModule, 'isBrowserScope', false);
|
|
90
|
+
jest.replaceProperty(globalScopeModule, 'isWorkerScope', true);
|
|
91
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
|
|
92
|
+
const aggregateArgs = {
|
|
93
|
+
[_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
|
|
94
|
+
};
|
|
95
|
+
instrument.importAggregator(aggregateArgs);
|
|
96
|
+
|
|
97
|
+
// In worker scope, we cannot wait on importLater method
|
|
98
|
+
await new Promise(process.nextTick);
|
|
99
|
+
expect(_load.onWindowLoad).not.toHaveBeenCalled();
|
|
100
|
+
expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(featureName, 'aggregate');
|
|
101
|
+
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
|
|
102
|
+
});
|
|
103
|
+
test('should import the session manager and replay aggregate for new session', async () => {
|
|
104
|
+
jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
|
|
105
|
+
jest.mocked(_agentSession.setupAgentSession).mockReturnValue({
|
|
106
|
+
isNew: true
|
|
107
|
+
});
|
|
108
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, _features.FEATURE_NAMES.sessionReplay);
|
|
109
|
+
const aggregateArgs = {
|
|
110
|
+
[_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
|
|
111
|
+
};
|
|
112
|
+
instrument.importAggregator(aggregateArgs);
|
|
113
|
+
const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
|
|
114
|
+
await windowLoadCallback();
|
|
115
|
+
expect(_config.getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled');
|
|
116
|
+
expect(_agentSession.setupAgentSession).toHaveBeenCalledWith(agentIdentifier);
|
|
117
|
+
expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(_features.FEATURE_NAMES.sessionReplay, 'aggregate');
|
|
118
|
+
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
|
|
119
|
+
});
|
|
120
|
+
test('should import the session manager and replay aggregate when a recording is active', async () => {
|
|
121
|
+
jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
|
|
122
|
+
jest.mocked(_agentSession.setupAgentSession).mockReturnValue({
|
|
123
|
+
isNew: false,
|
|
124
|
+
state: {
|
|
125
|
+
sessionReplay: 1
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, _features.FEATURE_NAMES.sessionReplay);
|
|
129
|
+
const aggregateArgs = {
|
|
130
|
+
[_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
|
|
131
|
+
};
|
|
132
|
+
instrument.importAggregator(aggregateArgs);
|
|
133
|
+
const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
|
|
134
|
+
await windowLoadCallback();
|
|
135
|
+
expect(_config.getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled');
|
|
136
|
+
expect(_agentSession.setupAgentSession).toHaveBeenCalledWith(agentIdentifier);
|
|
137
|
+
expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalledWith(_features.FEATURE_NAMES.sessionReplay, 'aggregate');
|
|
138
|
+
expect(mockAggregate).toHaveBeenCalledWith(agentIdentifier, aggregator, aggregateArgs);
|
|
139
|
+
});
|
|
140
|
+
test('should not import session aggregate when session is not new and a recording is not active', async () => {
|
|
141
|
+
jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
|
|
142
|
+
jest.mocked(_agentSession.setupAgentSession).mockReturnValue({
|
|
143
|
+
isNew: false,
|
|
144
|
+
state: {
|
|
145
|
+
sessionReplay: 0
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, _features.FEATURE_NAMES.sessionReplay);
|
|
149
|
+
const aggregateArgs = {
|
|
150
|
+
[_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
|
|
151
|
+
};
|
|
152
|
+
instrument.importAggregator(aggregateArgs);
|
|
153
|
+
const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
|
|
154
|
+
await windowLoadCallback();
|
|
155
|
+
expect(_config.getConfigurationValue).toHaveBeenCalledWith(agentIdentifier, 'privacy.cookies_enabled');
|
|
156
|
+
expect(_agentSession.setupAgentSession).toHaveBeenCalledWith(agentIdentifier);
|
|
157
|
+
expect(_drain.drain).toHaveBeenCalledWith(agentIdentifier, _features.FEATURE_NAMES.sessionReplay);
|
|
158
|
+
expect(_lazyFeatureLoader.lazyFeatureLoader).not.toHaveBeenCalled();
|
|
159
|
+
expect(mockAggregate).not.toHaveBeenCalled();
|
|
160
|
+
});
|
|
161
|
+
test('feature still imports by default even when setupAgentSession throws an error', async () => {
|
|
162
|
+
jest.mocked(_config.getConfigurationValue).mockReturnValue(true);
|
|
163
|
+
jest.mocked(_agentSession.setupAgentSession).mockImplementation(() => {
|
|
164
|
+
throw new Error(_faker.faker.lorem.sentence());
|
|
165
|
+
});
|
|
166
|
+
const instrument = new _instrumentBase.InstrumentBase(agentIdentifier, aggregator, featureName);
|
|
167
|
+
const aggregateArgs = {
|
|
168
|
+
[_faker.faker.datatype.uuid()]: _faker.faker.lorem.sentence()
|
|
169
|
+
};
|
|
170
|
+
instrument.abortHandler = jest.fn();
|
|
171
|
+
instrument.importAggregator(aggregateArgs);
|
|
172
|
+
const windowLoadCallback = jest.mocked(_load.onWindowLoad).mock.calls[0][0];
|
|
173
|
+
await windowLoadCallback();
|
|
174
|
+
expect(_load.onWindowLoad).toHaveBeenCalledWith(expect.any(Function), true);
|
|
175
|
+
expect(instrument.abortHandler).not.toHaveBeenCalled();
|
|
176
|
+
expect(_console.warn).toHaveBeenCalledWith(expect.stringContaining('A problem occurred when starting up session manager'), expect.any(Error));
|
|
177
|
+
expect(_lazyFeatureLoader.lazyFeatureLoader).toHaveBeenCalled();
|
|
178
|
+
expect(mockAggregate).toHaveBeenCalled();
|
|
179
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _faker = require("@faker-js/faker");
|
|
4
|
+
var _features = require("../../loaders/features/features");
|
|
5
|
+
var _lazyFeatureLoader = require("./lazy-feature-loader");
|
|
6
|
+
// Use enableAutomock to make it easier to mock all the things that get imported by the aggregators
|
|
7
|
+
jest.enableAutomock();
|
|
8
|
+
// Unmock the file under test and the constants file
|
|
9
|
+
jest.unmock('../../loaders/features/features');
|
|
10
|
+
jest.unmock('./lazy-feature-loader');
|
|
11
|
+
test.each(Object.keys(_features.FEATURE_NAMES))('should import the aggregate for feature %s', async key => {
|
|
12
|
+
const featureName = _features.FEATURE_NAMES[key];
|
|
13
|
+
const randomId = _faker.faker.datatype.uuid();
|
|
14
|
+
jest.setMock("../".concat(featureName, "/aggregate"), {
|
|
15
|
+
id: randomId,
|
|
16
|
+
featureName
|
|
17
|
+
});
|
|
18
|
+
const result = await (0, _lazyFeatureLoader.lazyFeatureLoader)(featureName, 'aggregate');
|
|
19
|
+
expect(result.id).toEqual(randomId);
|
|
20
|
+
expect(result.featureName).toEqual(featureName);
|
|
21
|
+
});
|
|
22
|
+
test('should throw an error when the featureName is not supported', async () => {
|
|
23
|
+
const featureName = _faker.faker.datatype.uuid();
|
|
24
|
+
expect(() => (0, _lazyFeatureLoader.lazyFeatureLoader)(featureName, 'aggregate')).toThrow();
|
|
25
|
+
});
|
|
26
|
+
test('should return undefined when the featurePart is not supported', async () => {
|
|
27
|
+
const featureName = _faker.faker.datatype.uuid();
|
|
28
|
+
const featurePart = _faker.faker.datatype.uuid();
|
|
29
|
+
expect((0, _lazyFeatureLoader.lazyFeatureLoader)(featureName, featurePart)).toBeUndefined();
|
|
30
|
+
});
|
|
@@ -34,7 +34,6 @@ class Agent {
|
|
|
34
34
|
});
|
|
35
35
|
this.features = {};
|
|
36
36
|
this.desiredFeatures = new Set(options.features || []); // expected to be a list of static Instrument/InstrumentBase classes, see "spa.js" for example
|
|
37
|
-
|
|
38
37
|
// For Now... ALL agents must make the rum call whether the page_view_event feature was enabled or not.
|
|
39
38
|
// NR1 creates an index on the rum call, and if not seen for a few days, will remove the browser app!
|
|
40
39
|
// Future work is being planned to evaluate removing this behavior from the backend, but for now we must ensure this call is made
|
|
@@ -158,7 +158,7 @@ function setAPI(agentIdentifier, forceDrain) {
|
|
|
158
158
|
};
|
|
159
159
|
|
|
160
160
|
// theres no window.load event on non-browser scopes, lazy load immediately
|
|
161
|
-
if (_globalScope.
|
|
161
|
+
if (!_globalScope.isBrowserScope) lazyLoad();
|
|
162
162
|
// try to stay out of the way of the window.load event, lazy load once that has finished.
|
|
163
163
|
else (0, _load.onWindowLoad)(() => lazyLoad(), true);
|
|
164
164
|
function lazyLoad() {
|
|
@@ -42,6 +42,5 @@ function configure(agentIdentifier) {
|
|
|
42
42
|
(0, _nreum.gosNREUMInitializedAgents)(agentIdentifier, api, 'api');
|
|
43
43
|
(0, _nreum.gosNREUMInitializedAgents)(agentIdentifier, exposed, 'exposed');
|
|
44
44
|
(0, _nreum.addToNREUM)('activatedFeatures', _featureFlags.activatedFeatures);
|
|
45
|
-
(0, _nreum.addToNREUM)('setToken', flags => (0, _featureFlags.activateFeatures)(flags, agentIdentifier));
|
|
46
45
|
return api;
|
|
47
46
|
}
|
|
@@ -11,6 +11,8 @@ function getFeatureDependencyNames(feature) {
|
|
|
11
11
|
return [_features.FEATURE_NAMES.jserrors];
|
|
12
12
|
case _features.FEATURE_NAMES.sessionTrace:
|
|
13
13
|
return [_features.FEATURE_NAMES.ajax, _features.FEATURE_NAMES.pageViewEvent];
|
|
14
|
+
case _features.FEATURE_NAMES.sessionReplay:
|
|
15
|
+
return [_features.FEATURE_NAMES.sessionTrace];
|
|
14
16
|
case _features.FEATURE_NAMES.pageViewTiming:
|
|
15
17
|
return [_features.FEATURE_NAMES.pageViewEvent];
|
|
16
18
|
// this could change if we disconnect window load timings
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Keeps an object alive that is passed to all feature aggregate modules.
|
|
3
|
+
* The purpose is to have a way for communication and signals to relay across features at runtime.
|
|
4
|
+
* This object can hold any arbitrary values and should be treated as on-the-fly dynamic.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
let onReplayReady;
|
|
8
|
+
const sessionReplayInitialized = new Promise(resolve => onReplayReady = resolve);
|
|
9
|
+
export const sharedChannel = Object.freeze({
|
|
10
|
+
onReplayReady,
|
|
11
|
+
sessionReplayInitialized
|
|
12
|
+
});
|
|
@@ -89,7 +89,7 @@ describe('event-emitter context', () => {
|
|
|
89
89
|
});
|
|
90
90
|
});
|
|
91
91
|
describe('event-emitter buffer', () => {
|
|
92
|
-
|
|
92
|
+
test('it should create a new buffer for the given group', async () => {
|
|
93
93
|
const {
|
|
94
94
|
ee
|
|
95
95
|
} = await import('./contextual-ee');
|
|
@@ -101,7 +101,7 @@ describe('event-emitter buffer', () => {
|
|
|
101
101
|
}));
|
|
102
102
|
expect(ee.isBuffering(eventType)).toEqual(true);
|
|
103
103
|
});
|
|
104
|
-
|
|
104
|
+
test('it should default group to "feature"', async () => {
|
|
105
105
|
const {
|
|
106
106
|
ee
|
|
107
107
|
} = await import('./contextual-ee');
|
|
@@ -112,7 +112,7 @@ describe('event-emitter buffer', () => {
|
|
|
112
112
|
}));
|
|
113
113
|
expect(ee.isBuffering(eventType)).toEqual(true);
|
|
114
114
|
});
|
|
115
|
-
|
|
115
|
+
test('it should not create buffer if event-emitter is aborted', async () => {
|
|
116
116
|
const {
|
|
117
117
|
ee
|
|
118
118
|
} = await import('./contextual-ee');
|
|
@@ -152,7 +152,7 @@ describe('event-emitter abort', () => {
|
|
|
152
152
|
});
|
|
153
153
|
});
|
|
154
154
|
describe('event-emitter emit', () => {
|
|
155
|
-
|
|
155
|
+
test('should execute the listener', async () => {
|
|
156
156
|
const {
|
|
157
157
|
ee
|
|
158
158
|
} = await import('./contextual-ee');
|
|
@@ -163,7 +163,7 @@ describe('event-emitter emit', () => {
|
|
|
163
163
|
ee.emit(eventType, eventArgs);
|
|
164
164
|
expect(mockListener).toHaveBeenCalledWith(eventArgs[0], eventArgs[1], eventArgs[2]);
|
|
165
165
|
});
|
|
166
|
-
|
|
166
|
+
test('should not execute the listener after removal', async () => {
|
|
167
167
|
const {
|
|
168
168
|
ee
|
|
169
169
|
} = await import('./contextual-ee');
|
|
@@ -176,7 +176,7 @@ describe('event-emitter emit', () => {
|
|
|
176
176
|
ee.emit(eventType, eventArgs);
|
|
177
177
|
expect(mockListener).toHaveBeenCalledTimes(1);
|
|
178
178
|
});
|
|
179
|
-
|
|
179
|
+
test('should return early if global event-emitter is aborted', async () => {
|
|
180
180
|
const {
|
|
181
181
|
ee
|
|
182
182
|
} = await import('./contextual-ee');
|
|
@@ -191,7 +191,7 @@ describe('event-emitter emit', () => {
|
|
|
191
191
|
ee.emit(eventType, eventArgs);
|
|
192
192
|
expect(mockListener).toHaveBeenCalledTimes(0);
|
|
193
193
|
});
|
|
194
|
-
|
|
194
|
+
test('should still emit if global event-emitter is aborted but force flag is true', async () => {
|
|
195
195
|
const {
|
|
196
196
|
ee
|
|
197
197
|
} = await import('./contextual-ee');
|
|
@@ -207,7 +207,7 @@ describe('event-emitter emit', () => {
|
|
|
207
207
|
scopeEE.emit(eventType, eventArgs, {}, true);
|
|
208
208
|
expect(mockScopeListener).toHaveBeenCalledTimes(1);
|
|
209
209
|
});
|
|
210
|
-
|
|
210
|
+
test('should bubble the event if bubble flag is true', async () => {
|
|
211
211
|
const {
|
|
212
212
|
ee
|
|
213
213
|
} = await import('./contextual-ee');
|
|
@@ -222,7 +222,7 @@ describe('event-emitter emit', () => {
|
|
|
222
222
|
expect(mockScopeListener).toHaveBeenCalledTimes(1);
|
|
223
223
|
expect(mockListener).toHaveBeenCalledTimes(1);
|
|
224
224
|
});
|
|
225
|
-
|
|
225
|
+
test('should not bubble the event if bubble flag is false', async () => {
|
|
226
226
|
const {
|
|
227
227
|
ee
|
|
228
228
|
} = await import('./contextual-ee');
|
|
@@ -237,7 +237,7 @@ describe('event-emitter emit', () => {
|
|
|
237
237
|
expect(mockScopeListener).toHaveBeenCalledTimes(1);
|
|
238
238
|
expect(mockListener).not.toHaveBeenCalled();
|
|
239
239
|
});
|
|
240
|
-
|
|
240
|
+
test('should buffer the event on the scoped event-emitter', async () => {
|
|
241
241
|
const {
|
|
242
242
|
ee
|
|
243
243
|
} = await import('./contextual-ee');
|
package/dist/esm/common/harvest/{harvest-scheduler.test.js → harvest-scheduler.component-test.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { setConfiguration } from '../config/state/init';
|
|
2
2
|
import { HarvestScheduler } from './harvest-scheduler';
|
|
3
3
|
describe('runHarvest', () => {
|
|
4
|
-
|
|
4
|
+
test('should re-schedule harvest even if there is no accumulated data', () => {
|
|
5
5
|
setConfiguration('asdf', {});
|
|
6
6
|
const scheduler = new HarvestScheduler('events', {
|
|
7
7
|
getPayload: jest.fn()
|
|
@@ -17,7 +17,7 @@ describe('runHarvest', () => {
|
|
|
17
17
|
expect(scheduler.opts.getPayload()).toBeFalsy();
|
|
18
18
|
expect(scheduler.scheduleHarvest).toHaveBeenCalledTimes(1);
|
|
19
19
|
});
|
|
20
|
-
|
|
20
|
+
test('should also re-schedule harvest if there is accumulated data', () => {
|
|
21
21
|
setConfiguration('asdf', {});
|
|
22
22
|
const scheduler = new HarvestScheduler('events', {
|
|
23
23
|
getPayload: jest.fn().mockImplementation(() => 'payload')
|
|
@@ -8,6 +8,7 @@ import { SharedContext } from '../context/shared-context';
|
|
|
8
8
|
import { Harvest, getSubmitMethod } from './harvest';
|
|
9
9
|
import { subscribeToEOL } from '../unload/eol';
|
|
10
10
|
import { getConfigurationValue } from '../config/config';
|
|
11
|
+
import { SESSION_EVENTS } from '../session/session-entity';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Periodically invokes harvest calls and handles retries
|
|
@@ -37,9 +38,18 @@ export class HarvestScheduler extends SharedContext {
|
|
|
37
38
|
// unload if EOL mechanism fires
|
|
38
39
|
subscribeToEOL(this.unload.bind(this), getConfigurationValue(this.sharedContext.agentIdentifier, 'allow_bfcache')); // TO DO: remove feature flag after rls stable
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
/* Flush all buffered data if session resets and give up retries. This should be synchronous to ensure that the correct `session` value is sent.
|
|
42
|
+
Since session-reset generates a new session ID and the ID is grabbed at send-time, any delays or retries would cause the payload to be sent under
|
|
43
|
+
the wrong session ID. */
|
|
44
|
+
this.sharedContext?.ee.on(SESSION_EVENTS.RESET, () => this.runHarvest({
|
|
45
|
+
forceNoRetry: true
|
|
46
|
+
}));
|
|
42
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* This function is only meant for the last outgoing harvest cycle of a page. It trickles down to using sendBeacon, which should not be used
|
|
51
|
+
* to send payloads while the page is still active, due to limitations on how much data can be buffered in the API at any one time.
|
|
52
|
+
*/
|
|
43
53
|
unload() {
|
|
44
54
|
if (this.aborted) return;
|
|
45
55
|
// If opts.onUnload is defined, these are special actions to execute before attempting to send the final payload.
|
|
@@ -111,7 +121,7 @@ export class HarvestScheduler extends SharedContext {
|
|
|
111
121
|
payload,
|
|
112
122
|
opts,
|
|
113
123
|
submitMethod,
|
|
114
|
-
cbFinished:
|
|
124
|
+
cbFinished: cbRanAfterSend,
|
|
115
125
|
customUrl: this.opts.customUrl,
|
|
116
126
|
raw: this.opts.raw
|
|
117
127
|
});
|
|
@@ -120,8 +130,14 @@ export class HarvestScheduler extends SharedContext {
|
|
|
120
130
|
this.scheduleHarvest();
|
|
121
131
|
}
|
|
122
132
|
return;
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* This is executed immediately after harvest sends the data via XHR, or if there's nothing to send. Note that this excludes on unloading / sendBeacon.
|
|
136
|
+
* @param {Object} result
|
|
137
|
+
*/
|
|
138
|
+
function cbRanAfterSend(result) {
|
|
139
|
+
if (opts?.forceNoRetry) result.retry = false; // discard unsent data rather than re-queuing for next harvest attempt
|
|
140
|
+
scheduler.onHarvestFinished(opts, result);
|
|
125
141
|
}
|
|
126
142
|
}
|
|
127
143
|
onHarvestFinished(opts, result) {
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { submitData } from '../util/submit-data';
|
|
2
|
+
import { Harvest } from './harvest';
|
|
3
|
+
jest.mock('../context/shared-context', () => ({
|
|
4
|
+
__esModule: true,
|
|
5
|
+
SharedContext: function () {
|
|
6
|
+
this.sharedContext = {
|
|
7
|
+
agentIdentifier: 'abcd'
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}));
|
|
11
|
+
jest.mock('../config/config', () => ({
|
|
12
|
+
__esModule: true,
|
|
13
|
+
getConfigurationValue: jest.fn(),
|
|
14
|
+
getInfo: jest.fn().mockReturnValue({
|
|
15
|
+
errorBeacon: 'example.com',
|
|
16
|
+
licenseKey: 'abcd'
|
|
17
|
+
}),
|
|
18
|
+
getRuntime: jest.fn().mockReturnValue({
|
|
19
|
+
bytesSent: {},
|
|
20
|
+
queryBytesSent: {}
|
|
21
|
+
})
|
|
22
|
+
}));
|
|
23
|
+
jest.mock('../util/submit-data', () => ({
|
|
24
|
+
__esModule: true,
|
|
25
|
+
submitData: {
|
|
26
|
+
xhr: jest.fn(() => ({
|
|
27
|
+
addEventListener: jest.fn()
|
|
28
|
+
})),
|
|
29
|
+
beacon: jest.fn(),
|
|
30
|
+
img: jest.fn()
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
describe('sendX', () => {
|
|
34
|
+
test.each([null, undefined, false])('should not send request when body is empty and sendEmptyBody is %s', sendEmptyBody => {
|
|
35
|
+
const sendCallback = jest.fn();
|
|
36
|
+
const harvester = new Harvest();
|
|
37
|
+
harvester.on('jserrors', () => ({
|
|
38
|
+
body: {},
|
|
39
|
+
qs: {}
|
|
40
|
+
}));
|
|
41
|
+
harvester.sendX({
|
|
42
|
+
endpoint: 'jserrors',
|
|
43
|
+
cbFinished: sendCallback
|
|
44
|
+
});
|
|
45
|
+
expect(sendCallback).toHaveBeenCalledWith({
|
|
46
|
+
sent: false
|
|
47
|
+
});
|
|
48
|
+
expect(submitData.xhr).not.toHaveBeenCalled();
|
|
49
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
50
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
51
|
+
});
|
|
52
|
+
test('should send request when body is empty and sendEmptyBody is true', () => {
|
|
53
|
+
const harvester = new Harvest();
|
|
54
|
+
harvester.on('jserrors', () => ({
|
|
55
|
+
body: {},
|
|
56
|
+
qs: {}
|
|
57
|
+
}));
|
|
58
|
+
harvester.sendX({
|
|
59
|
+
endpoint: 'jserrors',
|
|
60
|
+
opts: {
|
|
61
|
+
sendEmptyBody: true
|
|
62
|
+
},
|
|
63
|
+
cbFinished: jest.fn()
|
|
64
|
+
});
|
|
65
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
66
|
+
url: expect.stringContaining('https://example.com/jserrors/1/abcd?'),
|
|
67
|
+
body: undefined
|
|
68
|
+
}));
|
|
69
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
70
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
71
|
+
});
|
|
72
|
+
test.each([null, undefined, []])('should remove %s values from the body and query string when sending', emptyValue => {
|
|
73
|
+
const harvester = new Harvest();
|
|
74
|
+
harvester.on('jserrors', () => ({
|
|
75
|
+
body: {
|
|
76
|
+
bar: 'foo',
|
|
77
|
+
empty: emptyValue
|
|
78
|
+
},
|
|
79
|
+
qs: {
|
|
80
|
+
foo: 'bar',
|
|
81
|
+
empty: emptyValue
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
harvester.sendX({
|
|
85
|
+
endpoint: 'jserrors',
|
|
86
|
+
cbFinished: jest.fn()
|
|
87
|
+
});
|
|
88
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
89
|
+
url: expect.stringContaining('&foo=bar'),
|
|
90
|
+
body: JSON.stringify({
|
|
91
|
+
bar: 'foo'
|
|
92
|
+
})
|
|
93
|
+
}));
|
|
94
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
95
|
+
url: expect.not.stringContaining('&empty'),
|
|
96
|
+
body: expect.not.stringContaining('empty')
|
|
97
|
+
}));
|
|
98
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
99
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
100
|
+
});
|
|
101
|
+
test.each([1, false, true])('should not remove value %s (when it doesn\'t have a length) from the body and query string when sending', nonStringValue => {
|
|
102
|
+
const harvester = new Harvest();
|
|
103
|
+
harvester.on('jserrors', () => ({
|
|
104
|
+
body: {
|
|
105
|
+
bar: 'foo',
|
|
106
|
+
nonString: nonStringValue
|
|
107
|
+
},
|
|
108
|
+
qs: {
|
|
109
|
+
foo: 'bar',
|
|
110
|
+
nonString: nonStringValue
|
|
111
|
+
}
|
|
112
|
+
}));
|
|
113
|
+
harvester.sendX({
|
|
114
|
+
endpoint: 'jserrors',
|
|
115
|
+
cbFinished: jest.fn()
|
|
116
|
+
});
|
|
117
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
118
|
+
url: expect.stringContaining("&nonString=".concat(nonStringValue)),
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
bar: 'foo',
|
|
121
|
+
nonString: nonStringValue
|
|
122
|
+
})
|
|
123
|
+
}));
|
|
124
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
125
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe('send', () => {
|
|
129
|
+
test.each([null, undefined, false])('should not send request when body is empty and sendEmptyBody is %s', sendEmptyBody => {
|
|
130
|
+
const sendCallback = jest.fn();
|
|
131
|
+
const harvester = new Harvest();
|
|
132
|
+
harvester.send({
|
|
133
|
+
endpoint: 'rum',
|
|
134
|
+
payload: {
|
|
135
|
+
qs: {},
|
|
136
|
+
body: {}
|
|
137
|
+
},
|
|
138
|
+
opts: {
|
|
139
|
+
sendEmptyBody
|
|
140
|
+
},
|
|
141
|
+
cbFinished: sendCallback
|
|
142
|
+
});
|
|
143
|
+
expect(sendCallback).toHaveBeenCalledWith({
|
|
144
|
+
sent: false
|
|
145
|
+
});
|
|
146
|
+
expect(submitData.xhr).not.toHaveBeenCalled();
|
|
147
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
148
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
149
|
+
});
|
|
150
|
+
test('should send request when body is empty and sendEmptyBody is true', () => {
|
|
151
|
+
const harvester = new Harvest();
|
|
152
|
+
harvester.send({
|
|
153
|
+
endpoint: 'rum',
|
|
154
|
+
payload: {
|
|
155
|
+
qs: {},
|
|
156
|
+
body: {}
|
|
157
|
+
},
|
|
158
|
+
opts: {
|
|
159
|
+
sendEmptyBody: true
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
163
|
+
url: expect.stringContaining('https://example.com/1/abcd?'),
|
|
164
|
+
body: undefined
|
|
165
|
+
}));
|
|
166
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
167
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
168
|
+
});
|
|
169
|
+
test.each([null, undefined, []])('should remove %s values from the body and query string when sending', emptyValue => {
|
|
170
|
+
const harvester = new Harvest();
|
|
171
|
+
harvester.send({
|
|
172
|
+
endpoint: 'rum',
|
|
173
|
+
payload: {
|
|
174
|
+
qs: {
|
|
175
|
+
foo: 'bar',
|
|
176
|
+
empty: emptyValue
|
|
177
|
+
},
|
|
178
|
+
body: {
|
|
179
|
+
bar: 'foo',
|
|
180
|
+
empty: emptyValue
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
185
|
+
url: expect.stringContaining('&foo=bar'),
|
|
186
|
+
body: JSON.stringify({
|
|
187
|
+
bar: 'foo'
|
|
188
|
+
})
|
|
189
|
+
}));
|
|
190
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
191
|
+
url: expect.not.stringContaining('&empty'),
|
|
192
|
+
body: expect.not.stringContaining('empty')
|
|
193
|
+
}));
|
|
194
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
195
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
196
|
+
});
|
|
197
|
+
test.each([1, false, true])('should not remove value %s (when it doesn\'t have a length) from the body and query string when sending', nonStringValue => {
|
|
198
|
+
const harvester = new Harvest();
|
|
199
|
+
harvester.send({
|
|
200
|
+
endpoint: 'rum',
|
|
201
|
+
payload: {
|
|
202
|
+
qs: {
|
|
203
|
+
foo: 'bar',
|
|
204
|
+
nonString: nonStringValue
|
|
205
|
+
},
|
|
206
|
+
body: {
|
|
207
|
+
bar: 'foo',
|
|
208
|
+
nonString: nonStringValue
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
expect(submitData.xhr).toHaveBeenCalledWith(expect.objectContaining({
|
|
213
|
+
url: expect.stringContaining("&nonString=".concat(nonStringValue)),
|
|
214
|
+
body: JSON.stringify({
|
|
215
|
+
bar: 'foo',
|
|
216
|
+
nonString: nonStringValue
|
|
217
|
+
})
|
|
218
|
+
}));
|
|
219
|
+
expect(submitData.img).not.toHaveBeenCalled();
|
|
220
|
+
expect(submitData.beacon).not.toHaveBeenCalled();
|
|
221
|
+
});
|
|
222
|
+
});
|