@newrelic/browser-agent 1.232.0 → 1.233.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/dist/cjs/cdn/polyfills.js +5 -2
- package/dist/cjs/common/config/state/configurable.js +15 -26
- package/dist/cjs/common/config/state/info.js +1 -1
- package/dist/cjs/common/config/state/init.js +101 -56
- package/dist/cjs/common/config/state/loader-config.js +1 -1
- package/dist/cjs/common/config/state/runtime.js +1 -5
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/drain/drain.js +1 -1
- package/dist/cjs/common/harvest/harvest-scheduler.js +30 -10
- package/dist/cjs/common/harvest/harvest.js +119 -55
- package/dist/cjs/common/session/session-entity.js +35 -22
- package/dist/cjs/common/session/session-entity.test.js +73 -49
- package/dist/cjs/common/timer/interaction-timer.js +9 -12
- package/dist/cjs/common/url/canonicalize-url.js +32 -0
- package/dist/cjs/common/url/canonicalize-url.test.js +42 -0
- package/dist/cjs/common/url/clean-url.js +10 -3
- package/dist/cjs/common/url/protocol.test.js +0 -1
- package/dist/cjs/common/util/feature-flags.js +2 -1
- package/dist/cjs/common/util/global-scope.js +4 -2
- package/dist/cjs/common/util/submit-data.js +57 -18
- package/dist/cjs/common/wrap/wrap-fetch.js +1 -3
- package/dist/cjs/common/wrap/wrap-function.js +1 -3
- package/dist/cjs/common/wrap/wrap-promise.js +1 -1
- package/dist/cjs/features/ajax/aggregate/index.js +2 -2
- package/dist/cjs/features/ajax/instrument/index.js +1 -1
- package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +93 -10
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +164 -38
- package/dist/cjs/features/jserrors/aggregate/index.js +29 -48
- package/dist/cjs/features/jserrors/instrument/index.js +0 -2
- package/dist/cjs/features/metrics/aggregate/framework-detection.js +67 -0
- package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +137 -0
- package/dist/cjs/features/metrics/aggregate/index.js +7 -3
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.js +14 -0
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +17 -0
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.js +53 -0
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +165 -0
- package/dist/cjs/features/page_action/aggregate/index.js +2 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +6 -3
- package/dist/cjs/features/page_view_timing/aggregate/index.js +2 -2
- package/dist/cjs/features/session_replay/aggregate/index.js +333 -0
- package/dist/cjs/features/session_replay/constants.js +9 -0
- package/dist/cjs/features/session_replay/index.js +12 -0
- package/dist/cjs/features/session_replay/instrument/index.js +29 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +163 -164
- package/dist/cjs/features/session_trace/constants.js +2 -9
- package/dist/cjs/features/session_trace/instrument/index.js +24 -66
- package/dist/cjs/features/spa/aggregate/index.js +2 -2
- package/dist/cjs/features/utils/agent-session.js +1 -2
- package/dist/cjs/features/utils/aggregate-base.js +64 -0
- package/dist/cjs/features/utils/feature-base.js +0 -31
- package/dist/cjs/features/utils/handler-cache.js +3 -4
- package/dist/cjs/features/utils/instrument-base.js +42 -10
- package/dist/cjs/features/utils/{lazy-loader.js → lazy-feature-loader.js} +4 -2
- package/dist/cjs/loaders/agent.js +1 -1
- package/dist/cjs/loaders/api/apiAsync.js +3 -1
- package/dist/cjs/loaders/configure/configure.js +3 -3
- package/dist/cjs/loaders/features/featureDependencies.js +0 -12
- package/dist/cjs/loaders/features/features.js +3 -1
- package/dist/cjs/loaders/micro-agent.js +6 -6
- package/dist/esm/cdn/polyfills.js +5 -2
- package/dist/esm/common/config/state/configurable.js +14 -24
- package/dist/esm/common/config/state/info.js +2 -2
- package/dist/esm/common/config/state/init.js +102 -57
- package/dist/esm/common/config/state/loader-config.js +2 -2
- package/dist/esm/common/config/state/runtime.js +2 -4
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/drain/drain.js +1 -1
- package/dist/esm/common/harvest/harvest-scheduler.js +30 -10
- package/dist/esm/common/harvest/harvest.js +121 -56
- package/dist/esm/common/session/session-entity.js +35 -22
- package/dist/esm/common/session/session-entity.test.js +73 -49
- package/dist/esm/common/timer/interaction-timer.js +9 -12
- package/dist/esm/common/url/canonicalize-url.js +27 -0
- package/dist/esm/common/url/canonicalize-url.test.js +38 -0
- package/dist/esm/common/url/clean-url.js +10 -3
- package/dist/esm/common/url/protocol.test.js +0 -1
- package/dist/esm/common/util/feature-flags.js +2 -1
- package/dist/esm/common/util/global-scope.js +1 -0
- package/dist/esm/common/util/submit-data.js +57 -18
- package/dist/esm/common/wrap/wrap-fetch.js +1 -2
- package/dist/esm/common/wrap/wrap-function.js +1 -2
- package/dist/esm/common/wrap/wrap-promise.js +1 -1
- package/dist/esm/features/ajax/aggregate/index.js +2 -2
- package/dist/esm/features/ajax/instrument/index.js +1 -1
- package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +93 -10
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +149 -25
- package/dist/esm/features/jserrors/aggregate/index.js +30 -48
- package/dist/esm/features/jserrors/instrument/index.js +0 -1
- package/dist/esm/features/metrics/aggregate/framework-detection.js +61 -0
- package/dist/esm/features/metrics/aggregate/framework-detection.test.js +133 -0
- package/dist/esm/features/metrics/aggregate/index.js +7 -3
- package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.js +8 -0
- package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +15 -0
- package/dist/esm/features/metrics/aggregate/polyfill-detection.js +47 -0
- package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +163 -0
- package/dist/esm/features/page_action/aggregate/index.js +2 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +6 -3
- package/dist/esm/features/page_view_timing/aggregate/index.js +2 -2
- package/dist/esm/features/session_replay/aggregate/index.js +327 -0
- package/dist/esm/features/session_replay/constants.js +2 -0
- package/dist/esm/features/session_replay/index.js +12 -0
- package/dist/esm/features/session_replay/instrument/index.js +21 -0
- package/dist/esm/features/session_trace/aggregate/index.js +163 -163
- package/dist/esm/features/session_trace/constants.js +1 -5
- package/dist/esm/features/session_trace/instrument/index.js +24 -66
- package/dist/esm/features/spa/aggregate/index.js +2 -2
- package/dist/esm/features/utils/agent-session.js +1 -2
- package/dist/esm/features/utils/aggregate-base.js +57 -0
- package/dist/esm/features/utils/feature-base.js +1 -32
- package/dist/esm/features/utils/handler-cache.js +3 -4
- package/dist/esm/features/utils/instrument-base.js +42 -10
- package/dist/esm/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
- package/dist/esm/loaders/agent.js +1 -1
- package/dist/esm/loaders/api/apiAsync.js +3 -1
- package/dist/esm/loaders/configure/configure.js +3 -3
- package/dist/esm/loaders/features/featureDependencies.js +0 -11
- package/dist/esm/loaders/features/features.js +3 -1
- package/dist/esm/loaders/micro-agent.js +6 -6
- package/dist/types/common/config/state/configurable.d.ts +1 -3
- package/dist/types/common/config/state/configurable.d.ts.map +1 -1
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/config/state/runtime.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.d.ts +37 -34
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts +6 -3
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/timer/interaction-timer.d.ts +2 -1
- package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
- package/dist/types/common/url/canonicalize-url.d.ts +9 -0
- package/dist/types/common/url/canonicalize-url.d.ts.map +1 -0
- package/dist/types/common/url/clean-url.d.ts +7 -1
- package/dist/types/common/url/clean-url.d.ts.map +1 -1
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/common/util/global-scope.d.ts +1 -0
- package/dist/types/common/util/global-scope.d.ts.map +1 -1
- package/dist/types/common/util/submit-data.d.ts +40 -14
- package/dist/types/common/util/submit-data.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts +2 -2
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts +8 -1
- package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts +48 -19
- package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +14 -5
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/framework-detection.d.ts.map +1 -0
- package/dist/types/features/metrics/aggregate/index.d.ts +2 -2
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts +6 -0
- package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts.map +1 -0
- package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts +7 -0
- package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -0
- package/dist/types/features/page_action/aggregate/index.d.ts +3 -3
- package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -2
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -2
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts +96 -0
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -0
- package/dist/types/features/session_replay/constants.d.ts +2 -0
- package/dist/types/features/session_replay/constants.d.ts.map +1 -0
- package/dist/types/features/session_replay/index.d.ts +2 -0
- package/dist/types/features/session_replay/index.d.ts.map +1 -0
- package/dist/types/features/session_replay/instrument/index.d.ts +6 -0
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -0
- package/dist/types/features/session_trace/aggregate/index.d.ts +8 -57
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/constants.d.ts +0 -3
- package/dist/types/features/session_trace/constants.d.ts.map +1 -1
- package/dist/types/features/session_trace/instrument/index.d.ts +1 -3
- package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +2 -2
- package/dist/types/features/spa/aggregate/index.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 +11 -0
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -0
- package/dist/types/features/utils/feature-base.d.ts +0 -5
- package/dist/types/features/utils/feature-base.d.ts.map +1 -1
- package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts +3 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/features/utils/{lazy-loader.d.ts → lazy-feature-loader.d.ts} +2 -2
- package/dist/types/features/utils/lazy-feature-loader.d.ts.map +1 -0
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/features/featureDependencies.d.ts +0 -1
- package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +1 -0
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/package.json +31 -22
- package/src/cdn/polyfills.js +4 -1
- package/src/common/config/state/configurable.js +18 -24
- package/src/common/config/state/info.js +2 -2
- package/src/common/config/state/init.js +62 -28
- package/src/common/config/state/loader-config.js +2 -2
- package/src/common/config/state/runtime.js +2 -4
- package/src/common/drain/drain.js +1 -1
- package/src/common/harvest/harvest-scheduler.js +35 -10
- package/src/common/harvest/harvest.js +73 -50
- package/src/common/session/session-entity.js +34 -23
- package/src/common/session/session-entity.test.js +57 -51
- package/src/common/timer/interaction-timer.js +9 -12
- package/src/common/url/canonicalize-url.js +28 -0
- package/src/common/url/canonicalize-url.test.js +34 -0
- package/src/common/url/clean-url.js +10 -3
- package/src/common/url/protocol.test.js +0 -1
- package/src/common/util/feature-flags.js +2 -2
- package/src/common/util/global-scope.js +2 -0
- package/src/common/util/submit-data.js +28 -17
- package/src/common/wrap/wrap-fetch.js +1 -2
- package/src/common/wrap/wrap-function.js +1 -2
- package/src/common/wrap/wrap-promise.js +1 -1
- package/src/features/ajax/aggregate/index.js +2 -2
- package/src/features/ajax/instrument/index.js +1 -1
- package/src/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/src/features/jserrors/aggregate/compute-stack-trace.js +85 -11
- package/src/features/jserrors/aggregate/compute-stack-trace.test.js +141 -24
- package/src/features/jserrors/aggregate/index.js +28 -52
- package/src/features/jserrors/instrument/index.js +0 -1
- package/src/features/metrics/aggregate/framework-detection.js +73 -0
- package/src/features/metrics/aggregate/framework-detection.test.js +201 -0
- package/src/features/metrics/aggregate/index.js +8 -3
- package/src/features/metrics/aggregate/polyfill-detection.es5.js +9 -0
- package/src/features/metrics/aggregate/polyfill-detection.es5.test.js +16 -0
- package/src/features/metrics/aggregate/polyfill-detection.js +48 -0
- package/src/features/metrics/aggregate/polyfill-detection.test.js +163 -0
- package/src/features/page_action/aggregate/index.js +2 -2
- package/src/features/page_view_event/aggregate/index.js +5 -5
- package/src/features/page_view_timing/aggregate/index.js +2 -2
- package/src/features/session_replay/aggregate/index.js +314 -0
- package/src/features/session_replay/constants.js +3 -0
- package/src/features/session_replay/index.js +12 -0
- package/src/features/session_replay/instrument/index.js +22 -0
- package/src/features/session_trace/aggregate/index.js +148 -188
- package/src/features/session_trace/constants.js +0 -4
- package/src/features/session_trace/instrument/index.js +17 -69
- package/src/features/spa/aggregate/index.js +2 -2
- package/src/features/utils/agent-session.js +1 -2
- package/src/features/utils/aggregate-base.js +51 -0
- package/src/features/utils/feature-base.js +1 -31
- package/src/features/utils/handler-cache.js +3 -4
- package/src/features/utils/instrument-base.js +40 -8
- package/src/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
- package/src/loaders/agent.js +1 -1
- package/src/loaders/api/apiAsync.js +1 -1
- package/src/loaders/configure/configure.js +4 -3
- package/src/loaders/features/featureDependencies.js +0 -12
- package/src/loaders/features/features.js +3 -1
- package/src/loaders/micro-agent.js +4 -4
- package/dist/cjs/common/metrics/framework-detection.js +0 -72
- package/dist/cjs/common/util/user-agent.js +0 -57
- package/dist/cjs/common/window/supports-performance-observer.js +0 -15
- package/dist/esm/common/metrics/framework-detection.js +0 -66
- package/dist/esm/common/util/user-agent.js +0 -48
- package/dist/esm/common/window/supports-performance-observer.js +0 -9
- package/dist/types/common/metrics/framework-detection.d.ts.map +0 -1
- package/dist/types/common/util/user-agent.d.ts +0 -5
- package/dist/types/common/util/user-agent.d.ts.map +0 -1
- package/dist/types/common/window/supports-performance-observer.d.ts +0 -2
- package/dist/types/common/window/supports-performance-observer.d.ts.map +0 -1
- package/dist/types/features/utils/lazy-loader.d.ts.map +0 -1
- package/src/common/metrics/framework-detection.js +0 -71
- package/src/common/util/user-agent.js +0 -56
- package/src/common/window/supports-performance-observer.js +0 -10
- /package/dist/types/{common/metrics → features/metrics/aggregate}/framework-detection.d.ts +0 -0
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
2
|
import { browserErrorUtils } from '../../../../tools/testing-utils';
|
|
3
|
-
|
|
3
|
+
const globalScopeLocation = 'https://example.com/';
|
|
4
|
+
const mockGlobalScopeLocation = url => {
|
|
5
|
+
jest.doMock('../../../common/util/global-scope', () => ({
|
|
6
|
+
initialLocation: url || globalScopeLocation
|
|
7
|
+
}));
|
|
8
|
+
};
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
jest.resetModules();
|
|
11
|
+
jest.clearAllMocks();
|
|
12
|
+
});
|
|
4
13
|
const baseMockError = {
|
|
5
14
|
toString: 'RangeError: Invalid array length',
|
|
6
15
|
name: 'RangeError',
|
|
7
16
|
constructor: 'function RangeError() { [native code] }',
|
|
8
17
|
message: 'Invalid array length',
|
|
9
|
-
stack: 'RangeError: Invalid array length\n at errorTest (
|
|
18
|
+
stack: 'RangeError: Invalid array length\n' + ' at errorTest (' + globalScopeLocation + '?loader=spa#hello:74:16)\n' + ' at captureError (' + globalScopeLocation + 'js/script.js?loader=spa:17:9)\n' + ' at onload (' + globalScopeLocation + 'js/script.js?loader=spa:70:5)'
|
|
10
19
|
};
|
|
11
|
-
test('parsing should return a failure for a null error object', () => {
|
|
20
|
+
test('parsing should return a failure for a null error object', async () => {
|
|
21
|
+
mockGlobalScopeLocation();
|
|
22
|
+
const {
|
|
23
|
+
computeStackTrace
|
|
24
|
+
} = await import('./compute-stack-trace');
|
|
12
25
|
const result = computeStackTrace(null);
|
|
13
26
|
expect(result).toEqual(expect.objectContaining({
|
|
14
27
|
mode: 'failed',
|
|
@@ -17,24 +30,45 @@ test('parsing should return a failure for a null error object', () => {
|
|
|
17
30
|
}));
|
|
18
31
|
});
|
|
19
32
|
describe('errors with stack property', () => {
|
|
20
|
-
test('
|
|
33
|
+
test('should show <inline> for same-page stack string URLs but not sub-paths', async () => {
|
|
34
|
+
const mockError = browserErrorUtils.constructError({
|
|
35
|
+
...baseMockError
|
|
36
|
+
});
|
|
37
|
+
mockGlobalScopeLocation();
|
|
38
|
+
const {
|
|
39
|
+
computeStackTrace
|
|
40
|
+
} = await import('./compute-stack-trace');
|
|
41
|
+
const result = computeStackTrace(mockError);
|
|
42
|
+
expect(result).toEqual(expect.objectContaining({
|
|
43
|
+
stackString:
|
|
44
|
+
// canonicalized
|
|
45
|
+
'RangeError: Invalid array length\n' + ' at errorTest (<inline>:74:16)\n' + ' at captureError (' + globalScopeLocation + 'js/script.js:17:9)\n' + ' at onload (' + globalScopeLocation + 'js/script.js:70:5)'
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
test('parsed name should be unknown when name and constructor are missing', async () => {
|
|
21
49
|
const mockError = browserErrorUtils.constructError({
|
|
22
50
|
...baseMockError,
|
|
23
51
|
name: null,
|
|
24
52
|
constructor: null
|
|
25
53
|
});
|
|
54
|
+
mockGlobalScopeLocation();
|
|
55
|
+
const {
|
|
56
|
+
computeStackTrace
|
|
57
|
+
} = await import('./compute-stack-trace');
|
|
26
58
|
const result = computeStackTrace(mockError);
|
|
27
59
|
expect(result).toEqual(expect.objectContaining({
|
|
28
60
|
mode: 'stack',
|
|
29
|
-
name: 'unknown'
|
|
30
|
-
message: mockError.message,
|
|
31
|
-
stackString: mockError.stack
|
|
61
|
+
name: 'unknown'
|
|
32
62
|
}));
|
|
33
63
|
});
|
|
34
|
-
test('parsed stack should not contain nrWrapper', () => {
|
|
64
|
+
test('parsed stack should not contain nrWrapper', async () => {
|
|
35
65
|
const alteredError = baseMockError;
|
|
36
|
-
alteredError.stack += '\n at nrWrapper (
|
|
66
|
+
alteredError.stack += '\n at nrWrapper (' + globalScopeLocation + '?loader=spa:60:17)';
|
|
37
67
|
const mockError = browserErrorUtils.constructError(alteredError);
|
|
68
|
+
mockGlobalScopeLocation();
|
|
69
|
+
const {
|
|
70
|
+
computeStackTrace
|
|
71
|
+
} = await import('./compute-stack-trace');
|
|
38
72
|
const result = computeStackTrace(mockError);
|
|
39
73
|
expect(result).toEqual(expect.objectContaining({
|
|
40
74
|
mode: 'stack',
|
|
@@ -46,17 +80,21 @@ describe('errors with stack property', () => {
|
|
|
46
80
|
func: 'nrWrapper'
|
|
47
81
|
}));
|
|
48
82
|
});
|
|
49
|
-
test('stack should still parse when column numbers are missing', () => {
|
|
83
|
+
test('stack should still parse when column numbers are missing', async () => {
|
|
50
84
|
const mockError = browserErrorUtils.constructError({
|
|
51
85
|
...baseMockError,
|
|
52
|
-
stack: 'Error: Blocked a frame with origin "http://bam-test-1.nr-local.net:3334" from accessing a cross-origin frame.\n at errorTest (
|
|
86
|
+
stack: 'RangeError: Invalid array length\n' + 'Error: Blocked a frame with origin "http://bam-test-1.nr-local.net:3334" from accessing a cross-origin frame.\n' + ' at errorTest (' + globalScopeLocation + '?loader=spa:60)\n' + ' at captureError (' + globalScopeLocation + '?loader=spa:17)\n' + ' at onload (' + globalScopeLocation + '?loader=spa:57)'
|
|
53
87
|
});
|
|
88
|
+
mockGlobalScopeLocation();
|
|
89
|
+
const {
|
|
90
|
+
computeStackTrace
|
|
91
|
+
} = await import('./compute-stack-trace');
|
|
54
92
|
const result = computeStackTrace(mockError);
|
|
55
93
|
expect(result).toEqual(expect.objectContaining({
|
|
56
94
|
mode: 'stack',
|
|
57
95
|
name: mockError.name,
|
|
58
96
|
message: mockError.message,
|
|
59
|
-
stackString:
|
|
97
|
+
stackString: 'RangeError: Invalid array length\n' + 'Error: Blocked a frame with origin "http://bam-test-1.nr-local.net:3334" from accessing a cross-origin frame.\n' + ' at errorTest (<inline>:60)\n' + ' at captureError (<inline>:17)\n' + ' at onload (<inline>:57)'
|
|
60
98
|
}));
|
|
61
99
|
expect(result.frames.length).toEqual(3);
|
|
62
100
|
expect(result.frames).toContainEqual(expect.objectContaining({
|
|
@@ -72,11 +110,15 @@ describe('errors with stack property', () => {
|
|
|
72
110
|
column: null
|
|
73
111
|
}));
|
|
74
112
|
});
|
|
75
|
-
test('parser can handle chrome eval stack', () => {
|
|
113
|
+
test('parser can handle chrome eval stack', async () => {
|
|
76
114
|
const mockError = browserErrorUtils.constructError({
|
|
77
115
|
...baseMockError,
|
|
78
|
-
stack: ' at foobar (eval at foobar (
|
|
116
|
+
stack: ' at foobar (eval at foobar (' + globalScopeLocation + '))'
|
|
79
117
|
});
|
|
118
|
+
mockGlobalScopeLocation();
|
|
119
|
+
const {
|
|
120
|
+
computeStackTrace
|
|
121
|
+
} = await import('./compute-stack-trace');
|
|
80
122
|
const result = computeStackTrace(mockError);
|
|
81
123
|
expect(result).toEqual(expect.objectContaining({
|
|
82
124
|
mode: 'stack',
|
|
@@ -89,7 +131,7 @@ describe('errors with stack property', () => {
|
|
|
89
131
|
func: 'evaluated code'
|
|
90
132
|
}));
|
|
91
133
|
});
|
|
92
|
-
test('parser can handle ie eval stack', () => {
|
|
134
|
+
test('parser can handle ie eval stack', async () => {
|
|
93
135
|
const mockError = browserErrorUtils.constructError({
|
|
94
136
|
toString: 'TypeError: Permission denied',
|
|
95
137
|
name: 'TypeError',
|
|
@@ -97,6 +139,10 @@ describe('errors with stack property', () => {
|
|
|
97
139
|
message: 'Permission denied',
|
|
98
140
|
stack: ' at Function code (Function code:23:23)'
|
|
99
141
|
});
|
|
142
|
+
mockGlobalScopeLocation();
|
|
143
|
+
const {
|
|
144
|
+
computeStackTrace
|
|
145
|
+
} = await import('./compute-stack-trace');
|
|
100
146
|
const result = computeStackTrace(mockError);
|
|
101
147
|
expect(result).toEqual(expect.objectContaining({
|
|
102
148
|
mode: 'stack',
|
|
@@ -109,11 +155,15 @@ describe('errors with stack property', () => {
|
|
|
109
155
|
func: 'evaluated code'
|
|
110
156
|
}));
|
|
111
157
|
});
|
|
112
|
-
test('parser can handle stack with anonymous function', () => {
|
|
158
|
+
test('parser can handle stack with anonymous function', async () => {
|
|
113
159
|
const mockError = browserErrorUtils.constructError({
|
|
114
160
|
...baseMockError,
|
|
115
161
|
stack: 'anonymous'
|
|
116
162
|
});
|
|
163
|
+
mockGlobalScopeLocation();
|
|
164
|
+
const {
|
|
165
|
+
computeStackTrace
|
|
166
|
+
} = await import('./compute-stack-trace');
|
|
117
167
|
const result = computeStackTrace(mockError);
|
|
118
168
|
expect(result).toEqual(expect.objectContaining({
|
|
119
169
|
mode: 'stack',
|
|
@@ -131,7 +181,7 @@ describe('errors without stack property and with line property', () => {
|
|
|
131
181
|
/**
|
|
132
182
|
* @deprecated sourceURL is no longer present in errors for any browsers we support
|
|
133
183
|
*/
|
|
134
|
-
test('parsed stack should contain sourceURL and line number', () => {
|
|
184
|
+
test('parsed stack should contain sourceURL and line number', async () => {
|
|
135
185
|
const sourceURL = faker.internet.url();
|
|
136
186
|
const mockError = browserErrorUtils.constructError({
|
|
137
187
|
...baseMockError,
|
|
@@ -139,6 +189,10 @@ describe('errors without stack property and with line property', () => {
|
|
|
139
189
|
line: 100,
|
|
140
190
|
sourceURL
|
|
141
191
|
});
|
|
192
|
+
mockGlobalScopeLocation();
|
|
193
|
+
const {
|
|
194
|
+
computeStackTrace
|
|
195
|
+
} = await import('./compute-stack-trace');
|
|
142
196
|
const result = computeStackTrace(mockError);
|
|
143
197
|
expect(result).toEqual(expect.objectContaining({
|
|
144
198
|
mode: 'sourceline',
|
|
@@ -156,7 +210,7 @@ describe('errors without stack property and with line property', () => {
|
|
|
156
210
|
/**
|
|
157
211
|
* @deprecated sourceURL is no longer present in errors for any browsers we support
|
|
158
212
|
*/
|
|
159
|
-
test('parsed stack should contain sourceURL, line number, and column number', () => {
|
|
213
|
+
test('parsed stack should contain sourceURL, line number, and column number', async () => {
|
|
160
214
|
const sourceURL = faker.internet.url();
|
|
161
215
|
const mockError = browserErrorUtils.constructError({
|
|
162
216
|
...baseMockError,
|
|
@@ -165,6 +219,10 @@ describe('errors without stack property and with line property', () => {
|
|
|
165
219
|
stack: undefined,
|
|
166
220
|
sourceURL
|
|
167
221
|
});
|
|
222
|
+
mockGlobalScopeLocation();
|
|
223
|
+
const {
|
|
224
|
+
computeStackTrace
|
|
225
|
+
} = await import('./compute-stack-trace');
|
|
168
226
|
const result = computeStackTrace(mockError);
|
|
169
227
|
expect(result).toEqual(expect.objectContaining({
|
|
170
228
|
mode: 'sourceline',
|
|
@@ -179,13 +237,17 @@ describe('errors without stack property and with line property', () => {
|
|
|
179
237
|
column: mockError.column
|
|
180
238
|
}));
|
|
181
239
|
});
|
|
182
|
-
test('parsed stack should contain "evaluated code" if sourceURL property is not present', () => {
|
|
240
|
+
test('parsed stack should contain "evaluated code" if sourceURL property is not present', async () => {
|
|
183
241
|
const mockError = browserErrorUtils.constructError({
|
|
184
242
|
...baseMockError,
|
|
185
243
|
line: 100,
|
|
186
244
|
column: 200,
|
|
187
245
|
stack: undefined
|
|
188
246
|
});
|
|
247
|
+
mockGlobalScopeLocation();
|
|
248
|
+
const {
|
|
249
|
+
computeStackTrace
|
|
250
|
+
} = await import('./compute-stack-trace');
|
|
189
251
|
const result = computeStackTrace(mockError);
|
|
190
252
|
expect(result).toEqual(expect.objectContaining({
|
|
191
253
|
mode: 'sourceline',
|
|
@@ -199,6 +261,58 @@ describe('errors without stack property and with line property', () => {
|
|
|
199
261
|
}));
|
|
200
262
|
});
|
|
201
263
|
|
|
264
|
+
/**
|
|
265
|
+
* @deprecated sourceURL is no longer present in errors for any browsers we support
|
|
266
|
+
*/
|
|
267
|
+
test('should show <inline> for same-page URLs', async () => {
|
|
268
|
+
const pageLocation = faker.internet.url();
|
|
269
|
+
const sourceURL = pageLocation + '?abc=123';
|
|
270
|
+
const mockError = browserErrorUtils.constructError({
|
|
271
|
+
...baseMockError,
|
|
272
|
+
line: 100,
|
|
273
|
+
column: 200,
|
|
274
|
+
stack: undefined,
|
|
275
|
+
sourceURL: sourceURL
|
|
276
|
+
});
|
|
277
|
+
mockGlobalScopeLocation(pageLocation);
|
|
278
|
+
const {
|
|
279
|
+
computeStackTrace
|
|
280
|
+
} = await import('./compute-stack-trace');
|
|
281
|
+
const result = computeStackTrace(mockError);
|
|
282
|
+
expect(result).toEqual(expect.objectContaining({
|
|
283
|
+
stackString: "".concat(mockError.name, ": ").concat(mockError.message, "\n at <inline>:").concat(mockError.line, ":").concat(mockError.column)
|
|
284
|
+
}));
|
|
285
|
+
expect(result.frames).toContainEqual(expect.objectContaining({
|
|
286
|
+
url: '<inline>'
|
|
287
|
+
}));
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @deprecated sourceURL is no longer present in errors for any browsers we support
|
|
292
|
+
*/
|
|
293
|
+
test('should NOT show <inline> for same-domain URLs with a sub-path', async () => {
|
|
294
|
+
const pageLocation = faker.internet.url();
|
|
295
|
+
const sourceURL = pageLocation + '/path/to/script.js';
|
|
296
|
+
const mockError = browserErrorUtils.constructError({
|
|
297
|
+
...baseMockError,
|
|
298
|
+
line: 100,
|
|
299
|
+
column: 200,
|
|
300
|
+
stack: undefined,
|
|
301
|
+
sourceURL
|
|
302
|
+
});
|
|
303
|
+
mockGlobalScopeLocation(pageLocation);
|
|
304
|
+
const {
|
|
305
|
+
computeStackTrace
|
|
306
|
+
} = await import('./compute-stack-trace');
|
|
307
|
+
const result = computeStackTrace(mockError);
|
|
308
|
+
expect(result).toEqual(expect.objectContaining({
|
|
309
|
+
stackString: "".concat(mockError.name, ": ").concat(mockError.message, "\n at ").concat(sourceURL, ":").concat(mockError.line, ":").concat(mockError.column)
|
|
310
|
+
}));
|
|
311
|
+
expect(result.frames).toContainEqual(expect.objectContaining({
|
|
312
|
+
url: sourceURL
|
|
313
|
+
}));
|
|
314
|
+
});
|
|
315
|
+
|
|
202
316
|
// TODO: computeStackTraceBySourceAndLine does not respect firefox lineNumber and columnNumber properties when stack is empty
|
|
203
317
|
});
|
|
204
318
|
|
|
@@ -207,11 +321,15 @@ describe('errors without stack property and with line property', () => {
|
|
|
207
321
|
* error, including primitives.
|
|
208
322
|
*/
|
|
209
323
|
describe('errors that are messages only or primitives', () => {
|
|
210
|
-
test('parser should get error name from constructor', () => {
|
|
324
|
+
test('parser should get error name from constructor', async () => {
|
|
211
325
|
const mockError = browserErrorUtils.constructError({
|
|
212
326
|
toString: '0',
|
|
213
327
|
constructor: 'function Number() { [native code] }'
|
|
214
328
|
});
|
|
329
|
+
mockGlobalScopeLocation();
|
|
330
|
+
const {
|
|
331
|
+
computeStackTrace
|
|
332
|
+
} = await import('./compute-stack-trace');
|
|
215
333
|
const result = computeStackTrace(mockError);
|
|
216
334
|
expect(result).toEqual(expect.objectContaining({
|
|
217
335
|
mode: 'nameonly',
|
|
@@ -220,12 +338,16 @@ describe('errors that are messages only or primitives', () => {
|
|
|
220
338
|
frames: []
|
|
221
339
|
}));
|
|
222
340
|
});
|
|
223
|
-
test('parser should get error name from name property', () => {
|
|
341
|
+
test('parser should get error name from name property', async () => {
|
|
224
342
|
const mockError = browserErrorUtils.constructError({
|
|
225
343
|
toString: '0',
|
|
226
344
|
name: faker.datatype.uuid(),
|
|
227
345
|
constructor: 'function Number() { [native code] }'
|
|
228
346
|
});
|
|
347
|
+
mockGlobalScopeLocation();
|
|
348
|
+
const {
|
|
349
|
+
computeStackTrace
|
|
350
|
+
} = await import('./compute-stack-trace');
|
|
229
351
|
const result = computeStackTrace(mockError);
|
|
230
352
|
expect(result).toEqual(expect.objectContaining({
|
|
231
353
|
mode: 'nameonly',
|
|
@@ -234,13 +356,17 @@ describe('errors that are messages only or primitives', () => {
|
|
|
234
356
|
frames: []
|
|
235
357
|
}));
|
|
236
358
|
});
|
|
237
|
-
test('parser should include the message property', () => {
|
|
359
|
+
test('parser should include the message property', async () => {
|
|
238
360
|
const mockError = browserErrorUtils.constructError({
|
|
239
361
|
toString: '0',
|
|
240
362
|
name: faker.datatype.uuid(),
|
|
241
363
|
message: faker.datatype.uuid(),
|
|
242
364
|
constructor: 'function Number() { [native code] }'
|
|
243
365
|
});
|
|
366
|
+
mockGlobalScopeLocation();
|
|
367
|
+
const {
|
|
368
|
+
computeStackTrace
|
|
369
|
+
} = await import('./compute-stack-trace');
|
|
244
370
|
const result = computeStackTrace(mockError);
|
|
245
371
|
expect(result).toEqual(expect.objectContaining({
|
|
246
372
|
mode: 'nameonly',
|
|
@@ -250,6 +376,4 @@ describe('errors that are messages only or primitives', () => {
|
|
|
250
376
|
frames: []
|
|
251
377
|
}));
|
|
252
378
|
});
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
// describe('')
|
|
379
|
+
});
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { canonicalFunctionName } from './canonical-function-name';
|
|
7
|
-
import { cleanURL } from '../../../common/url/clean-url';
|
|
8
7
|
import { computeStackTrace } from './compute-stack-trace';
|
|
9
8
|
import { stringHashCode } from './string-hash-code';
|
|
10
9
|
import { truncateSize } from './format-stack-trace';
|
|
@@ -19,8 +18,13 @@ import { globalScope } from '../../../common/util/global-scope';
|
|
|
19
18
|
import { FEATURE_NAME } from '../constants';
|
|
20
19
|
import { drain } from '../../../common/drain/drain';
|
|
21
20
|
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
22
|
-
import {
|
|
23
|
-
|
|
21
|
+
import { AggregateBase } from '../../utils/aggregate-base';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export class Aggregate extends AggregateBase {
|
|
24
28
|
static featureName = FEATURE_NAME;
|
|
25
29
|
constructor(agentIdentifier, aggregator) {
|
|
26
30
|
var _this;
|
|
@@ -103,49 +107,25 @@ export class Aggregate extends FeatureBase {
|
|
|
103
107
|
getBucketName(params, customParams) {
|
|
104
108
|
return this.nameHash(params) + ':' + stringHashCode(stringify(customParams));
|
|
105
109
|
}
|
|
106
|
-
canonicalizeURL(url, cleanedOrigin) {
|
|
107
|
-
if (typeof url !== 'string') return '';
|
|
108
|
-
var cleanedURL = cleanURL(url);
|
|
109
|
-
if (cleanedURL === cleanedOrigin) {
|
|
110
|
-
return '<inline>';
|
|
111
|
-
} else {
|
|
112
|
-
return cleanedURL;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
buildCanonicalStackString(stackInfo, cleanedOrigin) {
|
|
116
|
-
var canonicalStack = '';
|
|
117
|
-
for (var i = 0; i < stackInfo.frames.length; i++) {
|
|
118
|
-
var frame = stackInfo.frames[i];
|
|
119
|
-
var func = canonicalFunctionName(frame.func);
|
|
120
|
-
if (canonicalStack) canonicalStack += '\n';
|
|
121
|
-
if (func) canonicalStack += func + '@';
|
|
122
|
-
if (typeof frame.url === 'string') canonicalStack += frame.url;
|
|
123
|
-
if (frame.line) canonicalStack += ':' + frame.line;
|
|
124
|
-
}
|
|
125
|
-
return canonicalStack;
|
|
126
|
-
}
|
|
127
110
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// for comparing with frame URLs.
|
|
138
|
-
var cleanedOrigin = cleanURL(getRuntime(this.agentIdentifier).origin);
|
|
111
|
+
/**
|
|
112
|
+
* Builds a standardized stack trace string from the frames in the given `stackInfo` object, with each frame separated
|
|
113
|
+
* by a newline character. Lines take the form `<functionName>@<url>:<lineNumber>`.
|
|
114
|
+
*
|
|
115
|
+
* @param {StackInfo} stackInfo - An object specifying a stack string and individual frames.
|
|
116
|
+
* @returns {string} A canonical stack string built from the URLs and function names in the given `stackInfo` object.
|
|
117
|
+
*/
|
|
118
|
+
buildCanonicalStackString(stackInfo) {
|
|
119
|
+
var canonicalStackString = '';
|
|
139
120
|
for (var i = 0; i < stackInfo.frames.length; i++) {
|
|
140
121
|
var frame = stackInfo.frames[i];
|
|
141
|
-
var
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
122
|
+
var func = canonicalFunctionName(frame.func);
|
|
123
|
+
if (canonicalStackString) canonicalStackString += '\n';
|
|
124
|
+
if (func) canonicalStackString += func + '@';
|
|
125
|
+
if (typeof frame.url === 'string') canonicalStackString += frame.url;
|
|
126
|
+
if (frame.line) canonicalStackString += ':' + frame.line;
|
|
147
127
|
}
|
|
148
|
-
return
|
|
128
|
+
return canonicalStackString;
|
|
149
129
|
}
|
|
150
130
|
storeError(err, time, internal, customAttributes) {
|
|
151
131
|
// are we in an interaction
|
|
@@ -162,10 +142,10 @@ export class Aggregate extends FeatureBase {
|
|
|
162
142
|
// Again as with previous usage, all falsey values would include the error.
|
|
163
143
|
}
|
|
164
144
|
|
|
165
|
-
var stackInfo =
|
|
166
|
-
var
|
|
145
|
+
var stackInfo = computeStackTrace(err);
|
|
146
|
+
var canonicalStackString = this.buildCanonicalStackString(stackInfo);
|
|
167
147
|
const params = {
|
|
168
|
-
stackHash: stringHashCode(
|
|
148
|
+
stackHash: stringHashCode(canonicalStackString),
|
|
169
149
|
exceptionClass: stackInfo.name,
|
|
170
150
|
request_uri: globalScope?.location.pathname
|
|
171
151
|
};
|
|
@@ -203,10 +183,12 @@ export class Aggregate extends FeatureBase {
|
|
|
203
183
|
time: time
|
|
204
184
|
};
|
|
205
185
|
|
|
206
|
-
// stn and spa aggregators listen to this event - stn sends the error in its payload,
|
|
186
|
+
// sr, stn and spa aggregators listen to this event - stn sends the error in its payload,
|
|
207
187
|
// and spa annotates the error with interaction info
|
|
208
|
-
|
|
209
|
-
handle('errorAgg',
|
|
188
|
+
const msg = [type, bucketHash, params, newMetrics];
|
|
189
|
+
handle('errorAgg', msg, undefined, FEATURE_NAMES.sessionTrace, this.ee);
|
|
190
|
+
handle('errorAgg', msg, undefined, FEATURE_NAMES.spa, this.ee);
|
|
191
|
+
handle('errorAgg', msg, undefined, FEATURE_NAMES.sessionReplay, this.ee);
|
|
210
192
|
|
|
211
193
|
// still send EE events for other features such as above, but stop this one from aggregating internal data
|
|
212
194
|
if (this.blocked) return;
|
|
@@ -7,7 +7,6 @@ import { handle } from '../../../common/event-emitter/handle';
|
|
|
7
7
|
import { now } from '../../../common/timing/now';
|
|
8
8
|
import { getOrSet } from '../../../common/util/get-or-set';
|
|
9
9
|
import { wrapRaf, wrapTimer, wrapEvents, wrapXhr } from '../../../common/wrap';
|
|
10
|
-
import slice from 'lodash._slice';
|
|
11
10
|
import './debug';
|
|
12
11
|
import { InstrumentBase } from '../../utils/instrument-base';
|
|
13
12
|
import { FEATURE_NAME, NR_ERR_PROP } from '../constants';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { isBrowserScope } from '../../../common/util/global-scope';
|
|
2
|
+
const FRAMEWORKS = {
|
|
3
|
+
REACT: 'React',
|
|
4
|
+
ANGULAR: 'Angular',
|
|
5
|
+
ANGULARJS: 'AngularJS',
|
|
6
|
+
BACKBONE: 'Backbone',
|
|
7
|
+
EMBER: 'Ember',
|
|
8
|
+
VUE: 'Vue',
|
|
9
|
+
METEOR: 'Meteor',
|
|
10
|
+
ZEPTO: 'Zepto',
|
|
11
|
+
JQUERY: 'Jquery',
|
|
12
|
+
MOOTOOLS: 'MooTools'
|
|
13
|
+
};
|
|
14
|
+
export function getFrameworks() {
|
|
15
|
+
if (!isBrowserScope) return []; // don't bother detecting frameworks if not in the main window context
|
|
16
|
+
|
|
17
|
+
const frameworks = [];
|
|
18
|
+
try {
|
|
19
|
+
if (detectReact()) frameworks.push(FRAMEWORKS.REACT);
|
|
20
|
+
if (detectAngularJs()) frameworks.push(FRAMEWORKS.ANGULARJS);
|
|
21
|
+
if (detectAngular()) frameworks.push(FRAMEWORKS.ANGULAR);
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(window, 'Backbone')) frameworks.push(FRAMEWORKS.BACKBONE);
|
|
23
|
+
if (Object.prototype.hasOwnProperty.call(window, 'Ember')) frameworks.push(FRAMEWORKS.EMBER);
|
|
24
|
+
if (Object.prototype.hasOwnProperty.call(window, 'Vue')) frameworks.push(FRAMEWORKS.VUE);
|
|
25
|
+
if (Object.prototype.hasOwnProperty.call(window, 'Meteor')) frameworks.push(FRAMEWORKS.METEOR);
|
|
26
|
+
if (Object.prototype.hasOwnProperty.call(window, 'Zepto')) frameworks.push(FRAMEWORKS.ZEPTO);
|
|
27
|
+
if (Object.prototype.hasOwnProperty.call(window, 'jQuery')) frameworks.push(FRAMEWORKS.JQUERY);
|
|
28
|
+
if (Object.prototype.hasOwnProperty.call(window, 'MooTools')) frameworks.push(FRAMEWORKS.MOOTOOLS);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
// Possibly not supported
|
|
31
|
+
}
|
|
32
|
+
return frameworks;
|
|
33
|
+
}
|
|
34
|
+
function detectReact() {
|
|
35
|
+
try {
|
|
36
|
+
return Object.prototype.hasOwnProperty.call(window, 'React') || Object.prototype.hasOwnProperty.call(window, 'ReactDOM') || Object.prototype.hasOwnProperty.call(window, 'ReactRedux') || document.querySelector('[data-reactroot], [data-reactid]') || (() => {
|
|
37
|
+
const divs = document.querySelectorAll('body > div');
|
|
38
|
+
for (let i = 0; i < divs.length; i++) {
|
|
39
|
+
if (Object.prototype.hasOwnProperty.call(divs[i], '_reactRootContainer')) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
})();
|
|
44
|
+
} catch (err) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function detectAngularJs() {
|
|
49
|
+
try {
|
|
50
|
+
return Object.prototype.hasOwnProperty.call(window, 'angular') || document.querySelector('.ng-binding, [ng-app], [data-ng-app], [ng-controller], [data-ng-controller], [ng-repeat], [data-ng-repeat]') || document.querySelector('script[src*="angular.js"], script[src*="angular.min.js"]');
|
|
51
|
+
} catch (err) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function detectAngular() {
|
|
56
|
+
try {
|
|
57
|
+
return Object.prototype.hasOwnProperty.call(window, 'ng') || document.querySelector('[ng-version]');
|
|
58
|
+
} catch (err) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { getFrameworks } from './framework-detection';
|
|
3
|
+
jest.mock('../../../common/util/global-scope', () => ({
|
|
4
|
+
isBrowserScope: true
|
|
5
|
+
}));
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
document.body.innerHTML = '';
|
|
8
|
+
});
|
|
9
|
+
test('framework detection should not happen in non-browser scope', async () => {
|
|
10
|
+
global.React = {};
|
|
11
|
+
jest.resetModules();
|
|
12
|
+
jest.doMock('../../../common/util/global-scope', () => ({
|
|
13
|
+
isBrowserScope: false
|
|
14
|
+
}));
|
|
15
|
+
const frameworkDetector = await import('./framework-detection');
|
|
16
|
+
expect(frameworkDetector.getFrameworks()).toEqual([]);
|
|
17
|
+
delete global.React;
|
|
18
|
+
});
|
|
19
|
+
test('should detect react from global React property', () => {
|
|
20
|
+
global.React = {};
|
|
21
|
+
expect(getFrameworks()).toEqual(['React']);
|
|
22
|
+
delete global.React;
|
|
23
|
+
});
|
|
24
|
+
test('should detect react from global ReactDOM property', () => {
|
|
25
|
+
global.ReactDOM = {};
|
|
26
|
+
expect(getFrameworks()).toEqual(['React']);
|
|
27
|
+
delete global.ReactDOM;
|
|
28
|
+
});
|
|
29
|
+
test('should detect react from global ReactRedux property', () => {
|
|
30
|
+
global.ReactRedux = {};
|
|
31
|
+
expect(getFrameworks()).toEqual(['React']);
|
|
32
|
+
delete global.ReactRedux;
|
|
33
|
+
});
|
|
34
|
+
test('should detect react from html [data-reactroot] property', () => {
|
|
35
|
+
document.body.innerHTML = '<div data-reactroot=""></div>';
|
|
36
|
+
expect(getFrameworks()).toEqual(['React']);
|
|
37
|
+
});
|
|
38
|
+
test('should detect react from html [data-reactid] property', () => {
|
|
39
|
+
document.body.innerHTML = '<div data-reactid=""></div>';
|
|
40
|
+
expect(getFrameworks()).toEqual(['React']);
|
|
41
|
+
});
|
|
42
|
+
test('should detect react from element _reactRootContainer property', () => {
|
|
43
|
+
const element = document.createElement('div');
|
|
44
|
+
element._reactRootContainer = {};
|
|
45
|
+
document.body.innerHTML = '<html><body></body></html>';
|
|
46
|
+
document.body.appendChild(element);
|
|
47
|
+
expect(getFrameworks()).toEqual(['React']);
|
|
48
|
+
});
|
|
49
|
+
test('should detect angularjs from global angular property', () => {
|
|
50
|
+
global.angular = {};
|
|
51
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
52
|
+
delete global.angular;
|
|
53
|
+
});
|
|
54
|
+
test('should detect angularjs from html .ng-binding property', () => {
|
|
55
|
+
document.body.innerHTML = '<div class="ng-binding"></div>';
|
|
56
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
57
|
+
});
|
|
58
|
+
test('should detect angularjs from html [ng-app] property', () => {
|
|
59
|
+
document.body.innerHTML = '<div ng-app=""></div>';
|
|
60
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
61
|
+
});
|
|
62
|
+
test('should detect angularjs from html [data-ng-app] property', () => {
|
|
63
|
+
document.body.innerHTML = '<div data-ng-app=""></div>';
|
|
64
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
65
|
+
});
|
|
66
|
+
test('should detect angularjs from html [ng-controller] property', () => {
|
|
67
|
+
document.body.innerHTML = '<div ng-controller=""></div>';
|
|
68
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
69
|
+
});
|
|
70
|
+
test('should detect angularjs from html [data-ng-controller] property', () => {
|
|
71
|
+
document.body.innerHTML = '<div data-ng-controller=""></div>';
|
|
72
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
73
|
+
});
|
|
74
|
+
test('should detect angularjs from html [ng-repeat] property', () => {
|
|
75
|
+
document.body.innerHTML = '<div ng-repeat=""></div>';
|
|
76
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
77
|
+
});
|
|
78
|
+
test('should detect angularjs from html [data-ng-repeat] property', () => {
|
|
79
|
+
document.body.innerHTML = '<div data-ng-repeat=""></div>';
|
|
80
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
81
|
+
});
|
|
82
|
+
test('should detect angularjs from angular.js script element', () => {
|
|
83
|
+
document.body.innerHTML = "<script src=\"".concat(faker.internet.url(), "/angular.js\"></script>");
|
|
84
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
85
|
+
});
|
|
86
|
+
test('should detect angularjs from angular.min.js script element', () => {
|
|
87
|
+
document.body.innerHTML = "<script src=\"".concat(faker.internet.url(), "/angular.min.js\"></script>");
|
|
88
|
+
expect(getFrameworks()).toEqual(['AngularJS']);
|
|
89
|
+
});
|
|
90
|
+
test('should detect angular from global ng property', () => {
|
|
91
|
+
global.ng = {};
|
|
92
|
+
expect(getFrameworks()).toEqual(['Angular']);
|
|
93
|
+
delete global.ng;
|
|
94
|
+
});
|
|
95
|
+
test('should detect angular from html [ng-version] property', () => {
|
|
96
|
+
document.body.innerHTML = '<div ng-version=""></div>';
|
|
97
|
+
expect(getFrameworks()).toEqual(['Angular']);
|
|
98
|
+
});
|
|
99
|
+
test('should detect backbone from global Backbone property', () => {
|
|
100
|
+
global.Backbone = {};
|
|
101
|
+
expect(getFrameworks()).toEqual(['Backbone']);
|
|
102
|
+
delete global.Backbone;
|
|
103
|
+
});
|
|
104
|
+
test('should detect ember from global Ember property', () => {
|
|
105
|
+
global.Ember = {};
|
|
106
|
+
expect(getFrameworks()).toEqual(['Ember']);
|
|
107
|
+
delete global.Ember;
|
|
108
|
+
});
|
|
109
|
+
test('should detect vue from global Vue property', () => {
|
|
110
|
+
global.Vue = {};
|
|
111
|
+
expect(getFrameworks()).toEqual(['Vue']);
|
|
112
|
+
delete global.Vue;
|
|
113
|
+
});
|
|
114
|
+
test('should detect meteor from global Meteor property', () => {
|
|
115
|
+
global.Meteor = {};
|
|
116
|
+
expect(getFrameworks()).toEqual(['Meteor']);
|
|
117
|
+
delete global.Meteor;
|
|
118
|
+
});
|
|
119
|
+
test('should detect zepto from global Zepto property', () => {
|
|
120
|
+
global.Zepto = {};
|
|
121
|
+
expect(getFrameworks()).toEqual(['Zepto']);
|
|
122
|
+
delete global.Zepto;
|
|
123
|
+
});
|
|
124
|
+
test('should detect jquery from global jQuery property', () => {
|
|
125
|
+
global.jQuery = {};
|
|
126
|
+
expect(getFrameworks()).toEqual(['Jquery']);
|
|
127
|
+
delete global.jQuery;
|
|
128
|
+
});
|
|
129
|
+
test('should detect mootools from global MooTools property', () => {
|
|
130
|
+
global.MooTools = {};
|
|
131
|
+
expect(getFrameworks()).toEqual(['MooTools']);
|
|
132
|
+
delete global.MooTools;
|
|
133
|
+
});
|