@newrelic/browser-agent 1.238.0 → 1.239.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.
Files changed (249) hide show
  1. package/dist/cjs/common/config/state/init.js +21 -13
  2. package/dist/cjs/common/config/state/runtime.js +0 -4
  3. package/dist/cjs/common/constants/env.cdn.js +1 -1
  4. package/dist/cjs/common/constants/env.npm.js +1 -1
  5. package/dist/cjs/common/constants/runtime.js +3 -3
  6. package/dist/cjs/common/constants/shared-channel.js +3 -1
  7. package/dist/cjs/common/deny-list/deny-list.js +2 -8
  8. package/dist/cjs/common/drain/drain.js +1 -1
  9. package/dist/cjs/common/event-emitter/contextual-ee.js +6 -6
  10. package/dist/cjs/common/harvest/harvest-scheduler.js +2 -4
  11. package/dist/cjs/common/harvest/harvest.js +2 -6
  12. package/dist/cjs/common/serialize/bel-serializer.js +1 -1
  13. package/dist/cjs/common/session/session-entity.js +16 -12
  14. package/dist/cjs/common/storage/first-party-cookies.js +5 -4
  15. package/dist/cjs/common/storage/local-storage.js +3 -2
  16. package/dist/cjs/common/timer/interaction-timer.js +14 -6
  17. package/dist/cjs/common/timing/nav-timing.js +1 -1
  18. package/dist/cjs/common/unload/eol.js +4 -30
  19. package/dist/cjs/common/util/feature-flags.js +14 -15
  20. package/dist/cjs/common/util/invoke.js +3 -1
  21. package/dist/cjs/common/util/obfuscate.js +3 -5
  22. package/dist/cjs/common/util/traverse.js +1 -0
  23. package/dist/cjs/common/window/page-visibility.js +1 -2
  24. package/dist/cjs/common/wrap/wrap-jsonp.js +1 -1
  25. package/dist/cjs/features/ajax/aggregate/index.js +5 -7
  26. package/dist/cjs/features/ajax/instrument/distributed-tracing.js +8 -8
  27. package/dist/cjs/features/ajax/instrument/index.js +47 -15
  28. package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +0 -1
  29. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +4 -4
  30. package/dist/cjs/features/jserrors/aggregate/index.js +4 -5
  31. package/dist/cjs/features/metrics/aggregate/framework-detection.js +103 -7
  32. package/dist/cjs/features/metrics/aggregate/index.js +20 -37
  33. package/dist/cjs/features/metrics/instrument/index.js +0 -2
  34. package/dist/cjs/features/page_action/aggregate/index.js +17 -19
  35. package/dist/cjs/features/page_view_event/aggregate/index.js +1 -2
  36. package/dist/cjs/features/page_view_event/instrument/index.js +4 -2
  37. package/dist/cjs/features/page_view_timing/aggregate/index.js +6 -7
  38. package/dist/cjs/features/session_replay/aggregate/index.js +3 -3
  39. package/dist/cjs/features/session_trace/aggregate/index.js +8 -8
  40. package/dist/cjs/features/spa/aggregate/index.js +14 -20
  41. package/dist/cjs/features/spa/aggregate/interaction.js +0 -2
  42. package/dist/cjs/features/spa/aggregate/serializer.js +1 -1
  43. package/dist/cjs/features/utils/aggregate-base.js +4 -0
  44. package/dist/cjs/features/utils/handler-cache.js +3 -1
  45. package/dist/cjs/features/utils/instrument-base.js +24 -6
  46. package/dist/cjs/loaders/agent-base.js +11 -0
  47. package/dist/cjs/loaders/agent.js +7 -7
  48. package/dist/cjs/loaders/api/api.js +21 -4
  49. package/dist/cjs/loaders/api/apiAsync.js +19 -20
  50. package/dist/cjs/loaders/configure/configure.js +3 -0
  51. package/dist/cjs/loaders/micro-agent.js +20 -3
  52. package/dist/esm/common/config/state/init.js +21 -13
  53. package/dist/esm/common/config/state/runtime.js +0 -4
  54. package/dist/esm/common/constants/env.cdn.js +1 -1
  55. package/dist/esm/common/constants/env.npm.js +1 -1
  56. package/dist/esm/common/constants/runtime.js +1 -1
  57. package/dist/esm/common/constants/shared-channel.js +3 -1
  58. package/dist/esm/common/deny-list/deny-list.js +2 -8
  59. package/dist/esm/common/drain/drain.js +1 -1
  60. package/dist/esm/common/event-emitter/contextual-ee.js +6 -6
  61. package/dist/esm/common/harvest/harvest-scheduler.js +2 -4
  62. package/dist/esm/common/harvest/harvest.js +2 -6
  63. package/dist/esm/common/serialize/bel-serializer.js +1 -1
  64. package/dist/esm/common/session/session-entity.js +16 -12
  65. package/dist/esm/common/storage/first-party-cookies.js +5 -4
  66. package/dist/esm/common/storage/local-storage.js +3 -2
  67. package/dist/esm/common/timer/interaction-timer.js +14 -6
  68. package/dist/esm/common/timing/nav-timing.js +1 -1
  69. package/dist/esm/common/unload/eol.js +5 -31
  70. package/dist/esm/common/util/feature-flags.js +14 -15
  71. package/dist/esm/common/util/invoke.js +3 -1
  72. package/dist/esm/common/util/obfuscate.js +3 -5
  73. package/dist/esm/common/util/traverse.js +1 -0
  74. package/dist/esm/common/window/page-visibility.js +1 -2
  75. package/dist/esm/common/wrap/wrap-jsonp.js +1 -1
  76. package/dist/esm/features/ajax/aggregate/index.js +5 -7
  77. package/dist/esm/features/ajax/instrument/distributed-tracing.js +8 -8
  78. package/dist/esm/features/ajax/instrument/index.js +47 -15
  79. package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +0 -1
  80. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +4 -4
  81. package/dist/esm/features/jserrors/aggregate/index.js +4 -5
  82. package/dist/esm/features/metrics/aggregate/framework-detection.js +103 -7
  83. package/dist/esm/features/metrics/aggregate/index.js +22 -39
  84. package/dist/esm/features/metrics/instrument/index.js +1 -3
  85. package/dist/esm/features/page_action/aggregate/index.js +17 -19
  86. package/dist/esm/features/page_view_event/aggregate/index.js +1 -2
  87. package/dist/esm/features/page_view_event/instrument/index.js +4 -2
  88. package/dist/esm/features/page_view_timing/aggregate/index.js +7 -8
  89. package/dist/esm/features/session_replay/aggregate/index.js +2 -2
  90. package/dist/esm/features/session_trace/aggregate/index.js +8 -8
  91. package/dist/esm/features/spa/aggregate/index.js +14 -20
  92. package/dist/esm/features/spa/aggregate/interaction.js +0 -2
  93. package/dist/esm/features/spa/aggregate/serializer.js +1 -1
  94. package/dist/esm/features/utils/aggregate-base.js +4 -0
  95. package/dist/esm/features/utils/handler-cache.js +3 -1
  96. package/dist/esm/features/utils/instrument-base.js +24 -6
  97. package/dist/esm/loaders/agent-base.js +11 -0
  98. package/dist/esm/loaders/agent.js +7 -7
  99. package/dist/esm/loaders/api/api.js +21 -4
  100. package/dist/esm/loaders/api/apiAsync.js +19 -20
  101. package/dist/esm/loaders/configure/configure.js +3 -0
  102. package/dist/esm/loaders/features/enabled-features.js +1 -1
  103. package/dist/esm/loaders/micro-agent.js +21 -4
  104. package/dist/types/common/config/state/init.d.ts.map +1 -1
  105. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  106. package/dist/types/common/constants/runtime.d.ts +1 -1
  107. package/dist/types/common/constants/runtime.d.ts.map +1 -1
  108. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  109. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  110. package/dist/types/common/session/session-entity.d.ts +6 -9
  111. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  112. package/dist/types/common/storage/first-party-cookies.d.ts +1 -1
  113. package/dist/types/common/storage/first-party-cookies.d.ts.map +1 -1
  114. package/dist/types/common/storage/local-storage.d.ts.map +1 -1
  115. package/dist/types/common/timer/interaction-timer.d.ts +3 -0
  116. package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
  117. package/dist/types/common/unload/eol.d.ts +1 -2
  118. package/dist/types/common/unload/eol.d.ts.map +1 -1
  119. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  120. package/dist/types/common/util/obfuscate.d.ts.map +1 -1
  121. package/dist/types/common/util/traverse.d.ts.map +1 -1
  122. package/dist/types/common/window/page-visibility.d.ts.map +1 -1
  123. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  124. package/dist/types/features/ajax/instrument/index.d.ts.map +1 -1
  125. package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts.map +1 -1
  126. package/dist/types/features/jserrors/aggregate/index.d.ts +1 -1
  127. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  128. package/dist/types/features/metrics/aggregate/framework-detection.d.ts.map +1 -1
  129. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  130. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  131. package/dist/types/features/page_action/aggregate/index.d.ts +2 -2
  132. package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
  133. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  134. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  135. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
  136. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  137. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  138. package/dist/types/features/spa/aggregate/interaction.d.ts.map +1 -1
  139. package/dist/types/features/utils/aggregate-base.d.ts +1 -0
  140. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  141. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  142. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  143. package/dist/types/loaders/agent-base.d.ts +6 -0
  144. package/dist/types/loaders/agent-base.d.ts.map +1 -1
  145. package/dist/types/loaders/agent.d.ts +1 -1
  146. package/dist/types/loaders/agent.d.ts.map +1 -1
  147. package/dist/types/loaders/api/api.d.ts +1 -0
  148. package/dist/types/loaders/api/api.d.ts.map +1 -1
  149. package/dist/types/loaders/api/apiAsync.d.ts.map +1 -1
  150. package/dist/types/loaders/configure/configure.d.ts +1 -0
  151. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  152. package/dist/types/loaders/micro-agent.d.ts +7 -1
  153. package/dist/types/loaders/micro-agent.d.ts.map +1 -1
  154. package/package.json +41 -12
  155. package/src/common/aggregate/aggregator.test.js +107 -0
  156. package/src/common/config/state/configurable.test.js +73 -0
  157. package/src/common/config/state/info.test.js +31 -0
  158. package/src/common/config/state/init.js +13 -12
  159. package/src/common/config/state/init.test.js +28 -0
  160. package/src/common/config/state/loader-config.test.js +21 -0
  161. package/src/common/config/state/runtime.js +0 -2
  162. package/src/common/config/state/runtime.test.js +21 -0
  163. package/src/common/constants/__mocks__/runtime.js +1 -1
  164. package/src/common/constants/runtime.js +1 -1
  165. package/src/common/constants/runtime.test.js +2 -2
  166. package/src/common/constants/shared-channel.js +1 -1
  167. package/src/common/deny-list/deny-list.js +2 -10
  168. package/src/common/drain/drain.js +1 -1
  169. package/src/common/drain/drain.test.js +74 -0
  170. package/src/common/event-emitter/contextual-ee.js +6 -6
  171. package/src/common/harvest/harvest-scheduler.js +2 -5
  172. package/src/common/harvest/harvest-scheduler.test.js +2 -6
  173. package/src/common/harvest/harvest.js +2 -6
  174. package/src/common/harvest/harvest.test.js +0 -2
  175. package/src/common/ids/id.test.js +6 -6
  176. package/src/common/serialize/bel-serializer.js +1 -1
  177. package/src/common/session/session-entity.component-test.js +3 -2
  178. package/src/common/session/session-entity.js +11 -9
  179. package/src/common/storage/first-party-cookies.js +5 -4
  180. package/src/common/storage/local-storage.js +3 -2
  181. package/src/common/timer/interaction-timer.component-test.js +52 -7
  182. package/src/common/timer/interaction-timer.js +15 -6
  183. package/src/common/timer/timer.test.js +0 -1
  184. package/src/common/timing/nav-timing.js +1 -1
  185. package/src/common/unload/eol.js +5 -31
  186. package/src/common/url/encode.test.js +1 -0
  187. package/src/common/util/__mocks__/invoke.js +1 -0
  188. package/src/common/util/data-size.test.js +0 -1
  189. package/src/common/util/feature-flags.js +15 -17
  190. package/src/common/util/feature-flags.test.js +4 -8
  191. package/src/common/util/invoke.js +1 -1
  192. package/src/common/util/obfuscate.js +3 -5
  193. package/src/common/util/submit-data.test.js +1 -1
  194. package/src/common/util/traverse.js +1 -0
  195. package/src/common/window/__mocks__/nreum.js +3 -1
  196. package/src/common/window/page-visibility.js +1 -2
  197. package/src/common/wrap/wrap-jsonp.js +1 -1
  198. package/src/features/ajax/aggregate/index.js +5 -7
  199. package/src/features/ajax/instrument/distributed-tracing.js +8 -8
  200. package/src/features/ajax/instrument/index.js +40 -17
  201. package/src/features/jserrors/aggregate/canonical-function-name.js +0 -2
  202. package/src/features/jserrors/aggregate/compute-stack-trace.js +4 -4
  203. package/src/features/jserrors/aggregate/compute-stack-trace.test.js +1 -1
  204. package/src/features/jserrors/aggregate/index.js +4 -5
  205. package/src/features/metrics/aggregate/framework-detection.js +129 -8
  206. package/src/features/metrics/aggregate/framework-detection.test.js +213 -82
  207. package/src/features/metrics/aggregate/index.js +22 -45
  208. package/src/features/metrics/instrument/index.js +1 -3
  209. package/src/features/page_action/aggregate/index.js +12 -13
  210. package/src/features/page_view_event/aggregate/index.js +1 -2
  211. package/src/features/page_view_event/instrument/index.js +2 -2
  212. package/src/features/page_view_timing/aggregate/index.js +7 -8
  213. package/src/features/session_replay/aggregate/index.component-test.js +3 -15
  214. package/src/features/session_replay/aggregate/index.js +2 -2
  215. package/src/features/session_trace/aggregate/index.js +6 -9
  216. package/src/features/spa/aggregate/index.js +14 -20
  217. package/src/features/spa/aggregate/interaction.js +0 -2
  218. package/src/features/spa/aggregate/serializer.js +1 -1
  219. package/src/features/utils/aggregate-base.js +5 -0
  220. package/src/features/utils/aggregate-base.test.js +2 -1
  221. package/src/features/utils/handler-cache.js +3 -2
  222. package/src/features/utils/instrument-base.js +25 -6
  223. package/src/features/utils/instrument-base.test.js +2 -2
  224. package/src/loaders/agent-base.js +11 -0
  225. package/src/loaders/agent.js +7 -7
  226. package/src/loaders/api/api.js +21 -4
  227. package/src/loaders/api/api.test.js +85 -0
  228. package/src/loaders/api/apiAsync.js +19 -20
  229. package/src/loaders/api/apiAsync.test.js +17 -0
  230. package/src/loaders/configure/configure.js +3 -0
  231. package/src/loaders/features/enabled-features.js +1 -1
  232. package/src/loaders/micro-agent.js +22 -4
  233. package/dist/cjs/features/metrics/aggregate/endpoint-map.js +0 -14
  234. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.js +0 -14
  235. package/dist/cjs/features/metrics/aggregate/polyfill-detection.js +0 -53
  236. package/dist/esm/features/metrics/aggregate/endpoint-map.js +0 -7
  237. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.js +0 -8
  238. package/dist/esm/features/metrics/aggregate/polyfill-detection.js +0 -47
  239. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +0 -8
  240. package/dist/types/features/metrics/aggregate/endpoint-map.d.ts.map +0 -1
  241. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts +0 -6
  242. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts.map +0 -1
  243. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts +0 -7
  244. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +0 -1
  245. package/src/features/metrics/aggregate/endpoint-map.js +0 -7
  246. package/src/features/metrics/aggregate/polyfill-detection.es5.js +0 -8
  247. package/src/features/metrics/aggregate/polyfill-detection.es5.test.js +0 -16
  248. package/src/features/metrics/aggregate/polyfill-detection.js +0 -48
  249. package/src/features/metrics/aggregate/polyfill-detection.test.js +0 -163
@@ -41,29 +41,25 @@ describe('constructor', () => {
41
41
  })
42
42
 
43
43
  test('refresh type timers set event listeners', () => {
44
- // eslint-disable-next-line
45
44
  let ee = { on: jest.fn().mockImplementation((evt, cb) => { cb([{ type: 'click' }]) }) }
46
45
  let it = new InteractionTimer({ onEnd: jest.fn(), onRefresh: jest.fn(), ee }, 100)
47
46
  // scroll, keypress, click
48
47
  expect(ee.on).toHaveBeenCalledTimes(1)
49
48
  expect(it.onRefresh).toHaveBeenCalledTimes(1)
50
49
 
51
- // eslint-disable-next-line
52
- ee = { on: jest.fn().mockImplementation((evt, cb) => { cb([{ type: 'scroll' }]) }) }
50
+ ee = { on: jest.fn().mockImplementation((evt, cb) => { cb([{ type: 'scroll' }]) }) }
53
51
  it = new InteractionTimer({ onEnd: jest.fn(), onRefresh: jest.fn(), ee }, 100)
54
52
  // scroll, keypress, click
55
53
  expect(ee.on).toHaveBeenCalledTimes(1)
56
54
  expect(it.onRefresh).toHaveBeenCalledTimes(1)
57
55
 
58
- // eslint-disable-next-line
59
- ee = { on: jest.fn().mockImplementation((evt, cb) => { cb([{ type: 'keydown' }]) }) }
56
+ ee = { on: jest.fn().mockImplementation((evt, cb) => { cb([{ type: 'keydown' }]) }) }
60
57
  it = new InteractionTimer({ onEnd: jest.fn(), onRefresh: jest.fn(), ee }, 100)
61
58
  // scroll, keypress, click
62
59
  expect(ee.on).toHaveBeenCalledTimes(1)
63
60
  expect(it.onRefresh).toHaveBeenCalledTimes(1)
64
61
 
65
62
  const aelSpy = jest.spyOn(document, 'addEventListener')
66
- // eslint-disable-next-line
67
63
  ee = { on: jest.fn().mockImplementation((evt, cb) => { cb([{ type: 'keydown' }]) }) }
68
64
  it = new InteractionTimer({ onEnd: jest.fn(), onRefresh: jest.fn(), ee }, 100)
69
65
  // visibility change
@@ -81,7 +77,6 @@ describe('create()', () => {
81
77
  })
82
78
 
83
79
  test('Create can fallback to use defaults', () => {
84
- let called = 0
85
80
  const timer1 = new InteractionTimer({ onEnd: jest.fn() }, 100)
86
81
  timer1.create()
87
82
 
@@ -136,6 +131,26 @@ describe('pause()', () => {
136
131
  })
137
132
  })
138
133
 
134
+ describe('resume()', () => {
135
+ test('resume allows the callback continue firing', () => {
136
+ const timer = new InteractionTimer({ onEnd: jest.fn() }, 100)
137
+ expect(timer.onEnd).toHaveBeenCalledTimes(0)
138
+ timer.pause()
139
+ jest.advanceTimersByTime(150)
140
+ expect(timer.onEnd).toHaveBeenCalledTimes(0)
141
+ timer.resume()
142
+ jest.advanceTimersByTime(150)
143
+ expect(timer.onEnd).toHaveBeenCalledTimes(1)
144
+ })
145
+
146
+ test('resume fires the refresh callback', () => {
147
+ const timer = new InteractionTimer({ onEnd: jest.fn(), onRefresh: jest.fn() }, 100)
148
+ timer.pause()
149
+ timer.resume()
150
+ expect(timer.onRefresh).toHaveBeenCalledTimes(1)
151
+ })
152
+ })
153
+
139
154
  describe('clear()', () => {
140
155
  test('clear prevents the callback from firing and deletes the pointer', () => {
141
156
  const timer = new InteractionTimer({ onEnd: jest.fn() }, 100)
@@ -165,3 +180,33 @@ describe('isValid', () => {
165
180
  expect(timer.isValid()).toEqual(false)
166
181
  })
167
182
  })
183
+
184
+ describe('abort()', () => {
185
+ test('should unregister the event emitter listener', () => {
186
+ const ee = { on: jest.fn(), removeEventListener: jest.fn() }
187
+ const it = new InteractionTimer({ onEnd: jest.fn(), onRefresh: jest.fn(), ee }, 100)
188
+
189
+ it.abort()
190
+
191
+ expect(ee.on).toHaveBeenCalledTimes(1)
192
+ expect(ee.on).toHaveBeenCalledWith('fn-end', expect.any(Function))
193
+
194
+ expect(ee.removeEventListener).toHaveBeenCalledTimes(1)
195
+ expect(ee.removeEventListener).toHaveBeenCalledWith('fn-end', expect.any(Function))
196
+
197
+ // Verify the same function is passed to both methods
198
+ expect(jest.mocked(ee.on).mock.calls[0][1]).toEqual(jest.mocked(ee.removeEventListener).mock.calls[0][1])
199
+ })
200
+
201
+ test('should not attempt to unregister the event emitter listener when an event emitter was not supplied', () => {
202
+ const it = new InteractionTimer({ onEnd: jest.fn(), onRefresh: jest.fn() }, 100)
203
+
204
+ expect(it.ee).toBeUndefined()
205
+ expect(it.refreshHandler).toBeUndefined()
206
+
207
+ it.abort()
208
+
209
+ expect(it.ee).toBeUndefined()
210
+ expect(it.refreshHandler).toBeUndefined()
211
+ })
212
+ })
@@ -24,12 +24,14 @@ export class InteractionTimer extends Timer {
24
24
 
25
25
  if (isBrowserScope && opts.ee) {
26
26
  if (opts.ee) {
27
+ this.ee = opts.ee
27
28
  const debouncedRefresh = debounce(this.refresh.bind(this), 500, { leading: true })
28
- opts.ee.on('fn-end', (evts) => {
29
+ this.refreshHandler = (evts) => {
29
30
  if (opts.refreshEvents.includes(evts?.[0]?.type)) {
30
31
  debouncedRefresh()
31
32
  }
32
- })
33
+ }
34
+ opts.ee.on('fn-end', this.refreshHandler)
33
35
  }
34
36
 
35
37
  // watch for the vis state changing. If the page is hidden, the local inactivity timer should be paused
@@ -43,10 +45,7 @@ export class InteractionTimer extends Timer {
43
45
  subscribeToVisibilityChange((state) => {
44
46
  if (state === 'hidden') this.pause()
45
47
  // vis change --> visible is treated like a new interaction with the page
46
- else {
47
- this.refresh()
48
- this.onResume() // emit resume event after state updated
49
- }
48
+ else this.resume()
50
49
  }, false, false, this.abortController?.signal)
51
50
  }
52
51
  }
@@ -54,6 +53,11 @@ export class InteractionTimer extends Timer {
54
53
  abort () {
55
54
  this.clear()
56
55
  this.abortController?.abort()
56
+
57
+ if (this.refreshHandler) {
58
+ this.ee.removeEventListener('fn-end', this.refreshHandler)
59
+ this.refreshHandler = this.ee = null
60
+ }
57
61
  }
58
62
 
59
63
  pause () {
@@ -62,6 +66,11 @@ export class InteractionTimer extends Timer {
62
66
  this.remainingMs = this.initialMs - (Date.now() - this.startTimestamp)
63
67
  }
64
68
 
69
+ resume () {
70
+ this.refresh()
71
+ this.onResume() // emit resume event after state updated
72
+ }
73
+
65
74
  refresh (cb, ms) {
66
75
  this.clear()
67
76
  this.timer = this.create(cb, ms)
@@ -51,7 +51,6 @@ describe('create()', () => {
51
51
  })
52
52
 
53
53
  test('Create can fallback to use defaults', () => {
54
- let called = 0
55
54
  const timer1 = new Timer({ onEnd: jest.fn() }, 100)
56
55
  timer1.create()
57
56
 
@@ -28,7 +28,7 @@ var DOM_CONTENT_LOAD_EVENT = 'domContentLoadedEvent'
28
28
  export var navTimingValues = []
29
29
 
30
30
  function getPntType (type) {
31
- if (typeof type == 'number') return type
31
+ if (typeof type === 'number') return type
32
32
  const types = {
33
33
  navigate: undefined,
34
34
  reload: 1,
@@ -3,8 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { windowAddEventListener } from '../event-listener/event-listener-opts'
6
- import { single } from '../util/invoke'
7
- import { ffVersion, globalScope, isWorkerScope, isBrowserScope } from '../constants/runtime'
6
+ import { globalScope, isWorkerScope, isBrowserScope } from '../constants/runtime'
8
7
  import { subscribeToVisibilityChange } from '../window/page-visibility'
9
8
 
10
9
  if (isWorkerScope) {
@@ -23,37 +22,12 @@ if (isWorkerScope) {
23
22
  * Subscribes a provided callback to the time/event when the agent should treat it as end-of-life.
24
23
  * This is used, for example, to submit a final harvest and send all remaining data on best-effort.
25
24
  * @param {function} cb - func to run before or during the last reliable event or time of an env's life span
26
- * @param {boolean} allowBFCache - (temp) feature flag to gate new v1222 BFC support
27
25
  */
28
- export function subscribeToEOL (cb, allowBFCache) {
26
+ export function subscribeToEOL (cb) {
29
27
  if (isBrowserScope) {
30
- if (allowBFCache) {
31
- subscribeToVisibilityChange(cb, true) // when user switches tab or hides window, esp. mobile scenario
32
- windowAddEventListener('pagehide', cb) // when user navigates away, and because safari iOS v14.4- doesn't fully support vis change
33
- // --this ought to be removed once support for version below 14.5 phases out
34
- } else {
35
- var oneCall = single(cb)
36
-
37
- // Firefox has a bug wherein a slow-loading resource loaded from the 'pagehide'
38
- // or 'unload' event will delay the 'load' event firing on the next page load.
39
- // In Firefox versions that support sendBeacon, this doesn't matter, because
40
- // we'll use it instead of an image load for our final harvest.
41
- //
42
- // Some Safari versions never fire the 'unload' event for pages that are being
43
- // put into the WebKit page cache, so we *need* to use the pagehide event for
44
- // the final submission from Safari.
45
- //
46
- // Generally speaking, we will try to submit our final harvest from either
47
- // pagehide or unload, whichever comes first, but in Firefox, we need to avoid
48
- // attempting to submit from pagehide to ensure that we don't slow down loading
49
- // of the next page.
50
- if (!ffVersion || navigator.sendBeacon) {
51
- windowAddEventListener('pagehide', oneCall)
52
- } else {
53
- windowAddEventListener('beforeunload', oneCall)
54
- }
55
- windowAddEventListener('unload', oneCall)
56
- }
28
+ subscribeToVisibilityChange(cb, true) // when user switches tab or hides window, esp. mobile scenario
29
+ windowAddEventListener('pagehide', cb) // when user navigates away, and because safari iOS v14.4- doesn't fully support vis change
30
+ // --this ought to be removed once support for version below 14.5 phases out
57
31
  } else if (isWorkerScope) {
58
32
  globalScope.cleanupTasks.push(cb) // close() should run these tasks before quitting thread
59
33
  }
@@ -46,6 +46,7 @@ describe('object encoding', () => {
46
46
  })
47
47
 
48
48
  test('handles circular objects', () => {
49
+ // eslint-disable-next-line sonarjs/prefer-object-literal
49
50
  const circular = {}
50
51
  circular.circular = circular
51
52
  const input = { bar: ['a', circular, 'c'] }
@@ -0,0 +1 @@
1
+ export const single = jest.fn(cb => cb)
@@ -47,7 +47,6 @@ describe('dataSize', () => {
47
47
  const input = {
48
48
  [faker.datatype.uuid()]: faker.lorem.sentence()
49
49
  }
50
- const expectedSize = faker.datatype.number({ min: 1000, max: 10000 })
51
50
 
52
51
  jest.spyOn(stringifyModule, 'stringify').mockImplementation(() => { throw new Error(faker.lorem.sentence()) })
53
52
 
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import { ee } from '../event-emitter/contextual-ee'
6
6
  import { handle } from '../event-emitter/handle'
7
- import { drain } from '../drain/drain'
8
7
  import { FEATURE_NAMES } from '../../loaders/features/features'
9
8
 
10
9
  const bucketMap = {
@@ -15,26 +14,25 @@ const bucketMap = {
15
14
  sr: [FEATURE_NAMES.sessionReplay, FEATURE_NAMES.sessionTrace]
16
15
  }
17
16
 
17
+ const sentIds = new Set()
18
+
18
19
  /** Note that this function only processes each unique flag ONCE, with the first occurrence of each flag and numeric value determining its switch on/off setting. */
19
20
  export function activateFeatures (flags, agentIdentifier) {
20
21
  const sharedEE = ee.get(agentIdentifier)
21
22
  if (!(flags && typeof flags === 'object')) return
22
23
 
23
- Object.entries(flags).forEach(([flag, num]) => {
24
- if (activatedFeatures[flag] !== undefined) return
25
-
26
- if (bucketMap[flag]) {
27
- bucketMap[flag].forEach(feat => {
28
- if (!num) handle('block-' + flag, [], undefined, feat, sharedEE)
29
- else handle('feat-' + flag, [], undefined, feat, sharedEE)
30
-
31
- handle('rumresp-' + flag, [Boolean(num)], undefined, feat, sharedEE) // this is a duplicate of feat-/block- but makes awaiting for 1 event easier than 2
32
- })
33
- } else if (num) handle('feat-' + flag, [], undefined, undefined, sharedEE) // not sure what other flags are overlooked, but there's a test for ones not in the map --
34
- // ^^^ THIS DOESN'T ACTUALLY DO ANYTHHING AS UNDEFINED/FEATURE GROUP ISN'T DRAINED
35
-
36
- activatedFeatures[flag] = Boolean(num)
37
- })
24
+ if (!sentIds.has(agentIdentifier)) {
25
+ Object.entries(flags).forEach(([flag, num]) => {
26
+ if (bucketMap[flag]) {
27
+ bucketMap[flag].forEach(feat => {
28
+ if (!num) handle('block-' + flag, [], undefined, feat, sharedEE)
29
+ else handle('feat-' + flag, [], undefined, feat, sharedEE)
30
+ handle('rumresp-' + flag, [Boolean(num)], undefined, feat, sharedEE) // this is a duplicate of feat-/block- but makes awaiting for 1 event easier than 2
31
+ })
32
+ } else if (num) handle('feat-' + flag, [], undefined, undefined, sharedEE) // not sure what other flags are overlooked, but there's a test for ones not in the map --
33
+ activatedFeatures[flag] = Boolean(num)
34
+ })
35
+ }
38
36
 
39
37
  // Let the features waiting on their respective flags know that RUM response was received and that any missing flags are interpreted as bad entitlement / "off".
40
38
  // Hence, those features will not be hanging forever if their flags aren't included in the response.
@@ -44,7 +42,7 @@ export function activateFeatures (flags, agentIdentifier) {
44
42
  activatedFeatures[flag] = false
45
43
  }
46
44
  })
47
- drain(agentIdentifier, FEATURE_NAMES.pageViewEvent)
45
+ sentIds.add(agentIdentifier)
48
46
  }
49
47
 
50
48
  export const activatedFeatures = {}
@@ -48,7 +48,7 @@ const bucketMap = {
48
48
 
49
49
  test('emits the right events when feature flag = 1', () => {
50
50
  const flags = {}
51
- Object.keys(bucketMap).forEach(flag => flags[flag] = 1)
51
+ Object.keys(bucketMap).forEach(flag => { flags[flag] = 1 })
52
52
  activateFeatures(flags, agentIdentifier)
53
53
 
54
54
  const sharedEE = jest.mocked(eventEmitterModule.ee.get).mock.results[0].value
@@ -57,15 +57,14 @@ test('emits the right events when feature flag = 1', () => {
57
57
  expect(handleModule.handle).toHaveBeenCalledTimes(14)
58
58
  expect(handleModule.handle).toHaveBeenNthCalledWith(1, 'feat-stn', [], undefined, FEATURE_NAMES.sessionTrace, sharedEE)
59
59
  expect(handleModule.handle).toHaveBeenLastCalledWith('rumresp-sr', [true], undefined, FEATURE_NAMES.sessionTrace, sharedEE)
60
- expect(drainModule.drain).toHaveBeenCalledWith(agentIdentifier, 'page_view_event')
61
60
 
62
- Object.keys(flags).forEach(flag => flags[flag] = true)
61
+ Object.keys(flags).forEach(flag => { flags[flag] = true })
63
62
  expect(activatedFeatures).toEqual(flags)
64
63
  })
65
64
 
66
65
  test('emits the right events when feature flag = 0', () => {
67
66
  const flags = {}
68
- Object.keys(bucketMap).forEach(flag => flags[flag] = 0)
67
+ Object.keys(bucketMap).forEach(flag => { flags[flag] = 0 })
69
68
  activateFeatures(flags, agentIdentifier)
70
69
 
71
70
  const sharedEE = jest.mocked(eventEmitterModule.ee.get).mock.results[0].value
@@ -74,9 +73,8 @@ test('emits the right events when feature flag = 0', () => {
74
73
  expect(handleModule.handle).toHaveBeenCalledTimes(14)
75
74
  expect(handleModule.handle).toHaveBeenNthCalledWith(1, 'block-stn', [], undefined, FEATURE_NAMES.sessionTrace, sharedEE)
76
75
  expect(handleModule.handle).toHaveBeenLastCalledWith('rumresp-sr', [false], undefined, FEATURE_NAMES.sessionTrace, sharedEE)
77
- expect(drainModule.drain).toHaveBeenCalledWith(agentIdentifier, 'page_view_event')
78
76
 
79
- Object.keys(flags).forEach(flag => flags[flag] = false)
77
+ Object.keys(flags).forEach(flag => { flags[flag] = false })
80
78
  expect(activatedFeatures).toEqual(flags)
81
79
  })
82
80
 
@@ -92,7 +90,5 @@ test('only the first activate of the same feature is respected', () => {
92
90
  expect(handleModule.handle).toHaveBeenNthCalledWith(1, 'feat-stn', [], undefined, 'session_trace', sharedEE1)
93
91
  expect(handleModule.handle).toHaveBeenNthCalledWith(2, 'rumresp-stn', [true], undefined, 'session_trace', sharedEE1)
94
92
  expect(handleModule.handle).not.toHaveBeenNthCalledWith(1, 'feat-stn', [], undefined, 'session_trace', sharedEE2)
95
- expect(drainModule.drain).toHaveBeenCalledWith(agentIdentifier, 'page_view_event')
96
- expect(drainModule.drain).toHaveBeenCalledTimes(2)
97
93
  expect(activatedFeatures.stn).toBeTruthy()
98
94
  })
@@ -26,7 +26,7 @@ export function debounce (func, timeout = 500, options = {}) {
26
26
  return (...args) => {
27
27
  if (leading && timer === undefined) {
28
28
  func.apply(this, args)
29
- timer = setTimeout(() => timer = clearTimeout(timer), timeout)
29
+ timer = setTimeout(() => { timer = clearTimeout(timer) }, timeout)
30
30
  }
31
31
 
32
32
  if (!leading) {
@@ -57,11 +57,9 @@ export function validateRules (rules) {
57
57
  }
58
58
 
59
59
  var replacement = rules[i].replacement
60
- if (replacement) {
61
- if (typeof replacement !== 'string') {
62
- warn('An obfuscation replacement rule contains a "replacement" value with an invalid type (must be a string)')
63
- invalidReplacementDetected = true
64
- }
60
+ if (replacement && typeof replacement !== 'string') {
61
+ warn('An obfuscation replacement rule contains a "replacement" value with an invalid type (must be a string)')
62
+ invalidReplacementDetected = true
65
63
  }
66
64
  }
67
65
 
@@ -66,7 +66,7 @@ describe('xhr', () => {
66
66
  this._withCredentials = false
67
67
  Object.defineProperty(this, 'withCredentials', {
68
68
  get: jest.fn(() => this._withCredentials),
69
- set: jest.fn((val) => this._withCredentials = val)
69
+ set: jest.fn((val) => { this._withCredentials = val })
70
70
  })
71
71
  })
72
72
  })
@@ -19,6 +19,7 @@ export function applyFnToProps (obj, fn, type = 'string', ignoreKeys = []) {
19
19
  if (typeof obj[property] === 'object') {
20
20
  applyFnToProps(obj[property], fn, type, ignoreKeys)
21
21
  } else {
22
+ // eslint-disable-next-line valid-typeof
22
23
  if (typeof obj[property] === type && !ignoreKeys.includes(property)) obj[property] = fn(obj[property])
23
24
  }
24
25
  })
@@ -7,4 +7,6 @@ export const gosNREUMOriginals = jest.fn(() => ({}))
7
7
  export const gosNREUMInitializedAgents = jest.fn(() => ({}))
8
8
  export const addToNREUM = jest.fn(() => ({}))
9
9
  export const NREUMinitialized = jest.fn(() => ({}))
10
- export const gosCDN = jest.fn(() => ({}))
10
+ export const gosCDN = jest.fn(() => (newrelicGlob))
11
+
12
+ const newrelicGlob = {}
@@ -12,11 +12,10 @@ import { documentAddEventListener } from '../event-listener/event-listener-opts'
12
12
  */
13
13
  export function subscribeToVisibilityChange (cb, toHiddenOnly = false, capture, abortSignal) {
14
14
  documentAddEventListener('visibilitychange', handleVisibilityChange, capture, abortSignal)
15
- return
16
15
 
17
16
  function handleVisibilityChange () {
18
17
  if (toHiddenOnly) { // trigger cb on change to hidden state only
19
- if (document.visibilityState == 'hidden') cb()
18
+ if (document.visibilityState === 'hidden') cb()
20
19
  return
21
20
  }
22
21
  cb(document.visibilityState)
@@ -122,7 +122,7 @@ export function wrapJsonP (sharedEE) {
122
122
  }
123
123
  }
124
124
  return {
125
- key: key,
125
+ key,
126
126
  parent: window
127
127
  }
128
128
  }
@@ -10,7 +10,6 @@ import { getConfiguration, getInfo, getRuntime } from '../../../common/config/co
10
10
  import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler'
11
11
  import { setDenyList, shouldCollectEvent } from '../../../common/deny-list/deny-list'
12
12
  import { FEATURE_NAME } from '../constants'
13
- import { drain } from '../../../common/drain/drain'
14
13
  import { FEATURE_NAMES } from '../../../loaders/features/features'
15
14
  import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
16
15
  import { AggregateBase } from '../../utils/aggregate-base'
@@ -24,7 +23,7 @@ export class Aggregate extends AggregateBase {
24
23
 
25
24
  register('xhr', storeXhr, this.featureName, this.ee)
26
25
  if (!allAjaxIsEnabled) {
27
- drain(this.agentIdentifier, this.featureName)
26
+ this.drain()
28
27
  return // feature will only collect timeslice metrics & ajax trace nodes if it's not fully enabled
29
28
  }
30
29
 
@@ -66,8 +65,7 @@ export class Aggregate extends AggregateBase {
66
65
 
67
66
  ee.on(`drain-${this.featureName}`, () => { scheduler.startTimer(harvestTimeSeconds) })
68
67
 
69
- drain(this.agentIdentifier, this.featureName)
70
- return
68
+ this.drain()
71
69
 
72
70
  function storeXhr (params, metrics, startTime, endTime, type) {
73
71
  metrics.time = startTime
@@ -105,9 +103,9 @@ export class Aggregate extends AggregateBase {
105
103
  path: params.pathname,
106
104
  requestSize: metrics.txSize,
107
105
  responseSize: metrics.rxSize,
108
- type: type,
109
- startTime: startTime,
110
- endTime: endTime,
106
+ type,
107
+ startTime,
108
+ endTime,
111
109
  callbackDuration: metrics.cbTime
112
110
  }
113
111
 
@@ -18,14 +18,14 @@ export class DT {
18
18
  return null
19
19
  }
20
20
 
21
- var loader_config = getLoaderConfig(this.agentIdentifier)
22
- if (!loader_config) {
21
+ var loaderConfig = getLoaderConfig(this.agentIdentifier)
22
+ if (!loaderConfig) {
23
23
  return null
24
24
  }
25
25
 
26
- var accountId = (loader_config.accountID || '').toString() || null
27
- var agentId = (loader_config.agentID || '').toString() || null
28
- var trustKey = (loader_config.trustKey || '').toString() || null
26
+ var accountId = (loaderConfig.accountID || '').toString() || null
27
+ var agentId = (loaderConfig.agentID || '').toString() || null
28
+ var trustKey = (loaderConfig.trustKey || '').toString() || null
29
29
 
30
30
  if (!accountId || !agentId) {
31
31
  return null
@@ -36,9 +36,9 @@ export class DT {
36
36
  var timestamp = Date.now()
37
37
 
38
38
  var payload = {
39
- spanId: spanId,
40
- traceId: traceId,
41
- timestamp: timestamp
39
+ spanId,
40
+ traceId,
41
+ timestamp
42
42
  }
43
43
 
44
44
  if (parsedOrigin.sameOrigin ||
@@ -34,6 +34,29 @@ export class Instrument extends InstrumentBase {
34
34
  this.dt = new DT(agentIdentifier)
35
35
 
36
36
  this.handler = (type, args, ctx, group) => handle(type, args, ctx, group, this.ee)
37
+
38
+ // this is a best (but imperfect) effort at capturing AJAX calls that may have fired before the agent was instantiated
39
+ // this could happen because the agent was "improperly" set up (ie, not at the top of the head) or
40
+ // because it was deferred from loading in some way -- e.g. 'deferred' script loading tags or other lazy-loading techniques
41
+ //
42
+ // it is "imperfect" because we cannot capture the following with the API vs wrapping the events directly:
43
+ // * requestBodySize - (txSize -- request body size)
44
+ // * method - request type (GET, POST, etc)
45
+ // * callbackDuration - (cbTime -- sum of resulting callback time)
46
+ try {
47
+ const initiators = { xmlhttprequest: 'xhr', fetch: 'fetch', beacon: 'beacon' }
48
+ globalScope?.performance?.getEntriesByType('resource').forEach(resource => {
49
+ if (resource.initiatorType in initiators && resource.responseStatus !== 0) {
50
+ const params = { status: resource.responseStatus }
51
+ const metrics = { rxSize: resource.transferSize, duration: Math.floor(resource.duration), cbTime: 0 }
52
+ addUrl(params, resource.name)
53
+ this.handler('xhr', [params, metrics, resource.startTime, resource.responseEnd, initiators[resource.initiatorType]], undefined, FEATURE_NAMES.ajax)
54
+ }
55
+ })
56
+ } catch (err) {
57
+ // do nothing
58
+ }
59
+
37
60
  wrapFetch(this.ee)
38
61
  wrapXhr(this.ee)
39
62
  subscribeToEvents(agentIdentifier, this.ee, this.handler, this.dt)
@@ -97,9 +120,9 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
97
120
  }
98
121
 
99
122
  function onOpenXhrEnd (args, xhr) {
100
- var loader_config = getLoaderConfig(agentIdentifier)
101
- if (loader_config.xpid && this.sameOrigin) {
102
- xhr.setRequestHeader('X-NewRelic-ID', loader_config.xpid)
123
+ var loaderConfig = getLoaderConfig(agentIdentifier)
124
+ if (loaderConfig.xpid && this.sameOrigin) {
125
+ xhr.setRequestHeader('X-NewRelic-ID', loaderConfig.xpid)
103
126
  }
104
127
 
105
128
  var payload = dt.generateTracePayload(this.parsedOrigin)
@@ -312,7 +335,7 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
312
335
 
313
336
  // we capture failed call as status 0, the actual error is ignored
314
337
  // eslint-disable-next-line handle-callback-err
315
- function onFetchDone (err, res) {
338
+ function onFetchDone (_, res) {
316
339
  this.endTime = now()
317
340
  if (!this.params) {
318
341
  this.params = {}
@@ -360,19 +383,6 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
360
383
  handler('xhr', [params, metrics, this.startTime, this.endTime, 'xhr'], this, FEATURE_NAMES.ajax)
361
384
  }
362
385
 
363
- function addUrl (ctx, url) {
364
- var parsed = parseUrl(url)
365
- var params = ctx.params
366
-
367
- params.hostname = parsed.hostname
368
- params.port = parsed.port
369
- params.protocol = parsed.protocol
370
- params.host = parsed.hostname + ':' + parsed.port
371
- params.pathname = parsed.pathname
372
- ctx.parsedOrigin = parsed
373
- ctx.sameOrigin = parsed.sameOrigin
374
- }
375
-
376
386
  function captureXhrData (ctx, xhr) {
377
387
  ctx.params.status = xhr.status
378
388
 
@@ -389,3 +399,16 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
389
399
  ctx.loadCaptureCalled = true
390
400
  }
391
401
  }
402
+
403
+ function addUrl (ctx, url) {
404
+ var parsed = parseUrl(url)
405
+ var params = ctx.params || ctx
406
+
407
+ params.hostname = parsed.hostname
408
+ params.port = parsed.port
409
+ params.protocol = parsed.protocol
410
+ params.host = parsed.hostname + ':' + parsed.port
411
+ params.pathname = parsed.pathname
412
+ ctx.parsedOrigin = parsed
413
+ ctx.sameOrigin = parsed.sameOrigin
414
+ }
@@ -17,6 +17,4 @@ export function canonicalFunctionName (functionNameString) {
17
17
 
18
18
  const match = functionNameString.match(canonicalFunctionNameRe)
19
19
  if (match) return match[1]
20
-
21
- return
22
20
  }
@@ -64,8 +64,8 @@ var debug = false
64
64
  var classNameRegex = /function (.+?)\s*\(/
65
65
  var chrome = /^\s*at (?:((?:\[object object\])?(?:[^(]*\([^)]*\))*[^()]*(?: \[as \S+\])?) )?\(?((?:file|http|https|chrome-extension):.*?)?:(\d+)(?::(\d+))?\)?\s*$/i
66
66
  var gecko = /^\s*(?:(\S*|global code)(?:\(.*?\))?@)?((?:file|http|https|chrome|safari-extension).*?):(\d+)(?::(\d+))?\s*$/i
67
- var chrome_eval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i
68
- var ie_eval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i
67
+ var chromeEval = /^\s*at .+ \(eval at \S+ \((?:(?:file|http|https):[^)]+)?\)(?:, [^:]*:\d+:\d+)?\)$/i
68
+ var ieEval = /^\s*at Function code \(Function code:\d+:\d+\)\s*/i
69
69
 
70
70
  /**
71
71
  * Represents an error with a stack trace.
@@ -209,7 +209,7 @@ function getStackElement (line) {
209
209
  })
210
210
  }
211
211
 
212
- if (line.match(chrome_eval) || line.match(ie_eval) || line === 'anonymous') {
212
+ if (line.match(chromeEval) || line.match(ieEval) || line === 'anonymous') {
213
213
  return { func: 'evaluated code' }
214
214
  }
215
215
  }
@@ -255,7 +255,7 @@ function computeStackTraceBySourceAndLine (ex) {
255
255
  mode: 'sourceline',
256
256
  name: className,
257
257
  message: ex.message,
258
- stackString: stackString,
258
+ stackString,
259
259
  frames: [{
260
260
  url: canonicalUrl,
261
261
  line: ex.line,
@@ -305,7 +305,7 @@ describe('errors without stack property and with line property', () => {
305
305
  line: 100,
306
306
  column: 200,
307
307
  stack: undefined,
308
- sourceURL: sourceURL
308
+ sourceURL
309
309
  })
310
310
 
311
311
  mockGlobalScopeLocation(pageLocation)