utneque 1.0.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 (431) hide show
  1. package/.editorconfig +10 -0
  2. package/.eslintrc.isomorphic.js +26 -0
  3. package/.eslintrc.js +86 -0
  4. package/.gitattributes +1 -0
  5. package/.github/workflows/ci.yml +33 -0
  6. package/.github/workflows/deploy-browser-cdn-candidate.yml +51 -0
  7. package/.github/workflows/deploy-releases.yml +178 -0
  8. package/.nvmrc +1 -0
  9. package/.prettierrc +7 -0
  10. package/.vscode/extensions.json +3 -0
  11. package/.vscode/launch.json +81 -0
  12. package/.vscode/settings.json +41 -0
  13. package/.yarn/plugins/@yarnpkg/plugin-constraints.cjs +52 -0
  14. package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +546 -0
  15. package/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +9 -0
  16. package/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +28 -0
  17. package/.yarn/releases/yarn-3.4.1.cjs +873 -0
  18. package/.yarnrc.yml +15 -0
  19. package/jest.config.js +18 -0
  20. package/package.json +59 -0
  21. package/packages/browser/.eslintrc.js +9 -0
  22. package/packages/browser/.lintstagedrc.js +1 -0
  23. package/packages/browser/ARCHITECTURE.md +48 -0
  24. package/packages/browser/LICENSE.MD +45 -0
  25. package/packages/browser/Makefile +64 -0
  26. package/packages/browser/README.md +227 -0
  27. package/packages/browser/e2e-tests/local-server.ts +28 -0
  28. package/packages/browser/e2e-tests/performance/ajs-perf-browser.test.ts +75 -0
  29. package/packages/browser/jest.config.js +15 -0
  30. package/packages/browser/jest.setup.js +10 -0
  31. package/packages/browser/package.json +106 -0
  32. package/packages/browser/qa/README.md +41 -0
  33. package/packages/browser/qa/__fixtures__/snippets.ts +148 -0
  34. package/packages/browser/qa/__tests__/backwards-compatibility.test.ts +180 -0
  35. package/packages/browser/qa/__tests__/destinations.test.ts +101 -0
  36. package/packages/browser/qa/__tests__/smoke.test.ts +170 -0
  37. package/packages/browser/qa/lib/benchmark.ts +36 -0
  38. package/packages/browser/qa/lib/browser.ts +28 -0
  39. package/packages/browser/qa/lib/jest-reporter.js +57 -0
  40. package/packages/browser/qa/lib/runner.ts +142 -0
  41. package/packages/browser/qa/lib/schema.ts +59 -0
  42. package/packages/browser/qa/lib/server.ts +54 -0
  43. package/packages/browser/qa/lib/stats.ts +52 -0
  44. package/packages/browser/scripts/build-prep.sh +7 -0
  45. package/packages/browser/scripts/ci.sh +15 -0
  46. package/packages/browser/scripts/release.js +121 -0
  47. package/packages/browser/scripts/release.sh +9 -0
  48. package/packages/browser/scripts/run.sh +8 -0
  49. package/packages/browser/src/browser/__tests__/analytics-lazy-init.integration.test.ts +51 -0
  50. package/packages/browser/src/browser/__tests__/analytics-pre-init.integration.test.ts +440 -0
  51. package/packages/browser/src/browser/__tests__/anon-id-and-reset.integration.test.ts +73 -0
  52. package/packages/browser/src/browser/__tests__/cdn.test.ts +53 -0
  53. package/packages/browser/src/browser/__tests__/csp-detection.test.ts +140 -0
  54. package/packages/browser/src/browser/__tests__/inspector.integration.test.ts +121 -0
  55. package/packages/browser/src/browser/__tests__/integration.test.ts +1213 -0
  56. package/packages/browser/src/browser/__tests__/integrations.integration.test.ts +260 -0
  57. package/packages/browser/src/browser/__tests__/page-enrichment.integration.test.ts +216 -0
  58. package/packages/browser/src/browser/__tests__/query-string.integration.test.ts +116 -0
  59. package/packages/browser/src/browser/__tests__/standalone-analytics.test.ts +303 -0
  60. package/packages/browser/src/browser/__tests__/standalone-errors.test.ts +136 -0
  61. package/packages/browser/src/browser/__tests__/standalone.test.ts +97 -0
  62. package/packages/browser/src/browser/__tests__/typedef-tests/analytics-browser.ts +150 -0
  63. package/packages/browser/src/browser/__tests__/update-cdn-settings.test.ts +71 -0
  64. package/packages/browser/src/browser/browser-umd.ts +19 -0
  65. package/packages/browser/src/browser/index.ts +486 -0
  66. package/packages/browser/src/browser/standalone-analytics.ts +62 -0
  67. package/packages/browser/src/browser/standalone-interface.ts +11 -0
  68. package/packages/browser/src/browser/standalone.ts +92 -0
  69. package/packages/browser/src/core/__tests__/track-form.test.ts +193 -0
  70. package/packages/browser/src/core/__tests__/track-link.test.ts +252 -0
  71. package/packages/browser/src/core/analytics/__tests__/integration.test.ts +334 -0
  72. package/packages/browser/src/core/analytics/__tests__/test-plugins.ts +94 -0
  73. package/packages/browser/src/core/analytics/index.ts +672 -0
  74. package/packages/browser/src/core/analytics/interfaces.ts +100 -0
  75. package/packages/browser/src/core/arguments-resolver/__tests__/index.test.ts +524 -0
  76. package/packages/browser/src/core/arguments-resolver/index.ts +200 -0
  77. package/packages/browser/src/core/auto-track.ts +152 -0
  78. package/packages/browser/src/core/buffer/__tests__/index.test.ts +455 -0
  79. package/packages/browser/src/core/buffer/index.ts +371 -0
  80. package/packages/browser/src/core/callback/index.ts +1 -0
  81. package/packages/browser/src/core/connection/__tests__/index.test.ts +25 -0
  82. package/packages/browser/src/core/connection/index.ts +13 -0
  83. package/packages/browser/src/core/constants/index.ts +1 -0
  84. package/packages/browser/src/core/context/__tests__/index.test.ts +201 -0
  85. package/packages/browser/src/core/context/index.ts +21 -0
  86. package/packages/browser/src/core/environment/index.ts +7 -0
  87. package/packages/browser/src/core/events/__tests__/index.test.ts +450 -0
  88. package/packages/browser/src/core/events/index.ts +280 -0
  89. package/packages/browser/src/core/events/interfaces.ts +36 -0
  90. package/packages/browser/src/core/inspector/index.ts +14 -0
  91. package/packages/browser/src/core/page/__tests__/index.test.ts +130 -0
  92. package/packages/browser/src/core/page/add-page-context.ts +33 -0
  93. package/packages/browser/src/core/page/get-page-context.ts +140 -0
  94. package/packages/browser/src/core/page/index.ts +2 -0
  95. package/packages/browser/src/core/plugin/index.ts +12 -0
  96. package/packages/browser/src/core/query-string/__tests__/gracefulDecodeURIComponent.test.ts +17 -0
  97. package/packages/browser/src/core/query-string/__tests__/index.test.ts +149 -0
  98. package/packages/browser/src/core/query-string/__tests__/pickPrefix.test.ts +31 -0
  99. package/packages/browser/src/core/query-string/__tests__/useQueryString.test.ts +60 -0
  100. package/packages/browser/src/core/query-string/gracefulDecodeURIComponent.ts +16 -0
  101. package/packages/browser/src/core/query-string/index.ts +64 -0
  102. package/packages/browser/src/core/query-string/pickPrefix.ts +20 -0
  103. package/packages/browser/src/core/queue/__tests__/event-queue.test.ts +82 -0
  104. package/packages/browser/src/core/queue/event-queue.ts +22 -0
  105. package/packages/browser/src/core/session/__tests__/index.test.ts +41 -0
  106. package/packages/browser/src/core/session/index.ts +107 -0
  107. package/packages/browser/src/core/stats/__tests__/index.test.ts +15 -0
  108. package/packages/browser/src/core/stats/__tests__/remote-metrics.test.ts +189 -0
  109. package/packages/browser/src/core/stats/index.ts +15 -0
  110. package/packages/browser/src/core/stats/remote-metrics.ts +144 -0
  111. package/packages/browser/src/core/storage/__tests__/cookieStorage.test.ts +58 -0
  112. package/packages/browser/src/core/storage/__tests__/localStorage.test.ts +70 -0
  113. package/packages/browser/src/core/storage/__tests__/test-helpers.ts +26 -0
  114. package/packages/browser/src/core/storage/__tests__/universalStorage.test.ts +167 -0
  115. package/packages/browser/src/core/storage/cookieStorage.ts +80 -0
  116. package/packages/browser/src/core/storage/index.ts +64 -0
  117. package/packages/browser/src/core/storage/localStorage.ts +45 -0
  118. package/packages/browser/src/core/storage/memoryStorage.ts +22 -0
  119. package/packages/browser/src/core/storage/settings.ts +23 -0
  120. package/packages/browser/src/core/storage/types.ts +49 -0
  121. package/packages/browser/src/core/storage/universalStorage.ts +78 -0
  122. package/packages/browser/src/core/user/__tests__/index.test.ts +922 -0
  123. package/packages/browser/src/core/user/__tests__/migrate.test.ts +101 -0
  124. package/packages/browser/src/core/user/__tests__/session.test.ts +136 -0
  125. package/packages/browser/src/core/user/__tests__/tld.test.ts +36 -0
  126. package/packages/browser/src/core/user/index.ts +399 -0
  127. package/packages/browser/src/core/user/migrate.ts +126 -0
  128. package/packages/browser/src/core/user/tld.ts +65 -0
  129. package/packages/browser/src/core/user/vendor/crypto-es/LICENSE +53 -0
  130. package/packages/browser/src/core/user/vendor/crypto-es/lib/aes.ts +302 -0
  131. package/packages/browser/src/core/user/vendor/crypto-es/lib/cipher-core.ts +922 -0
  132. package/packages/browser/src/core/user/vendor/crypto-es/lib/core.ts +806 -0
  133. package/packages/browser/src/core/user/vendor/crypto-es/lib/enc-base64.ts +110 -0
  134. package/packages/browser/src/core/user/vendor/crypto-es/lib/evpkdf.ts +110 -0
  135. package/packages/browser/src/core/user/vendor/crypto-es/lib/md5.ts +238 -0
  136. package/packages/browser/src/core/user/vendor/readme.md +7 -0
  137. package/packages/browser/src/generated/__tests__/version.test.ts +18 -0
  138. package/packages/browser/src/generated/version.ts +2 -0
  139. package/packages/browser/src/index.ts +13 -0
  140. package/packages/browser/src/lib/__tests__/embedded-write-key.test.ts +15 -0
  141. package/packages/browser/src/lib/__tests__/fetch.test.ts +35 -0
  142. package/packages/browser/src/lib/__tests__/get-process-env.test.ts +5 -0
  143. package/packages/browser/src/lib/__tests__/group-by.test.ts +96 -0
  144. package/packages/browser/src/lib/__tests__/is-plan-event-enabled.test.ts +36 -0
  145. package/packages/browser/src/lib/__tests__/is-thenable.test.ts +39 -0
  146. package/packages/browser/src/lib/__tests__/merged-options.test.ts +123 -0
  147. package/packages/browser/src/lib/__tests__/on-page-change.test.ts +74 -0
  148. package/packages/browser/src/lib/__tests__/parse-cdn.test.ts +88 -0
  149. package/packages/browser/src/lib/__tests__/pick.test.ts +34 -0
  150. package/packages/browser/src/lib/__tests__/pick.typedef.ts +39 -0
  151. package/packages/browser/src/lib/bind-all.ts +19 -0
  152. package/packages/browser/src/lib/browser-polyfill.ts +23 -0
  153. package/packages/browser/src/lib/client-hints/__tests__/index.test.ts +66 -0
  154. package/packages/browser/src/lib/client-hints/index.ts +16 -0
  155. package/packages/browser/src/lib/client-hints/interfaces.ts +42 -0
  156. package/packages/browser/src/lib/create-deferred.ts +16 -0
  157. package/packages/browser/src/lib/csp-detection.ts +8 -0
  158. package/packages/browser/src/lib/embedded-write-key.ts +24 -0
  159. package/packages/browser/src/lib/fetch.ts +10 -0
  160. package/packages/browser/src/lib/get-global.ts +16 -0
  161. package/packages/browser/src/lib/get-process-env.ts +11 -0
  162. package/packages/browser/src/lib/global-analytics-helper.ts +31 -0
  163. package/packages/browser/src/lib/group-by.ts +30 -0
  164. package/packages/browser/src/lib/is-plan-event-enabled.ts +20 -0
  165. package/packages/browser/src/lib/is-thenable.ts +9 -0
  166. package/packages/browser/src/lib/load-script.ts +66 -0
  167. package/packages/browser/src/lib/merged-options.ts +46 -0
  168. package/packages/browser/src/lib/on-page-change.ts +29 -0
  169. package/packages/browser/src/lib/p-while.ts +12 -0
  170. package/packages/browser/src/lib/parse-cdn.ts +56 -0
  171. package/packages/browser/src/lib/pick.ts +28 -0
  172. package/packages/browser/src/lib/priority-queue/__tests__/backoff.test.ts +23 -0
  173. package/packages/browser/src/lib/priority-queue/__tests__/index.test.ts +158 -0
  174. package/packages/browser/src/lib/priority-queue/__tests__/persisted.test.ts +228 -0
  175. package/packages/browser/src/lib/priority-queue/backoff.ts +24 -0
  176. package/packages/browser/src/lib/priority-queue/index.ts +6 -0
  177. package/packages/browser/src/lib/priority-queue/persisted.ts +127 -0
  178. package/packages/browser/src/lib/sleep.ts +4 -0
  179. package/packages/browser/src/lib/to-facade.ts +53 -0
  180. package/packages/browser/src/lib/version-type.ts +10 -0
  181. package/packages/browser/src/node/__tests__/node-integration.test.ts +19 -0
  182. package/packages/browser/src/node/index.ts +36 -0
  183. package/packages/browser/src/node/node.browser.ts +7 -0
  184. package/packages/browser/src/plugins/ajs-destination/__tests__/index.test.ts +834 -0
  185. package/packages/browser/src/plugins/ajs-destination/index.ts +392 -0
  186. package/packages/browser/src/plugins/ajs-destination/loader.ts +129 -0
  187. package/packages/browser/src/plugins/ajs-destination/types.ts +44 -0
  188. package/packages/browser/src/plugins/ajs-destination/utils.ts +32 -0
  189. package/packages/browser/src/plugins/analytics-node/__tests__/index.test.ts +69 -0
  190. package/packages/browser/src/plugins/analytics-node/index.ts +67 -0
  191. package/packages/browser/src/plugins/env-enrichment/__tests__/index.test.ts +421 -0
  192. package/packages/browser/src/plugins/env-enrichment/index.ts +208 -0
  193. package/packages/browser/src/plugins/hightouchio/__tests__/batched-dispatcher.test.ts +299 -0
  194. package/packages/browser/src/plugins/hightouchio/__tests__/index.test.ts +317 -0
  195. package/packages/browser/src/plugins/hightouchio/__tests__/normalize.test.ts +181 -0
  196. package/packages/browser/src/plugins/hightouchio/__tests__/retries.test.ts +82 -0
  197. package/packages/browser/src/plugins/hightouchio/batched-dispatcher.ts +127 -0
  198. package/packages/browser/src/plugins/hightouchio/fetch-dispatcher.ts +27 -0
  199. package/packages/browser/src/plugins/hightouchio/index.ts +147 -0
  200. package/packages/browser/src/plugins/hightouchio/normalize.ts +71 -0
  201. package/packages/browser/src/plugins/hightouchio/schedule-flush.ts +58 -0
  202. package/packages/browser/src/plugins/legacy-video-plugins/__tests__/index.test.ts +48 -0
  203. package/packages/browser/src/plugins/legacy-video-plugins/index.ts +16 -0
  204. package/packages/browser/src/plugins/middleware/__tests__/index.test.ts +268 -0
  205. package/packages/browser/src/plugins/middleware/index.ts +131 -0
  206. package/packages/browser/src/plugins/remote-loader/__tests__/index.test.ts +943 -0
  207. package/packages/browser/src/plugins/remote-loader/index.ts +256 -0
  208. package/packages/browser/src/plugins/remote-middleware/__tests__/index.test.ts +116 -0
  209. package/packages/browser/src/plugins/remote-middleware/index.ts +44 -0
  210. package/packages/browser/src/plugins/routing-middleware/__tests__/index.test.ts +64 -0
  211. package/packages/browser/src/plugins/routing-middleware/index.ts +37 -0
  212. package/packages/browser/src/plugins/schema-filter/__tests__/index.test.ts +520 -0
  213. package/packages/browser/src/plugins/schema-filter/index.ts +90 -0
  214. package/packages/browser/src/plugins/validation/__tests__/index.test.ts +78 -0
  215. package/packages/browser/src/plugins/validation/index.ts +44 -0
  216. package/packages/browser/src/test-helpers/browser-storage.ts +75 -0
  217. package/packages/browser/src/test-helpers/factories.ts +18 -0
  218. package/packages/browser/src/test-helpers/fetch-parse.ts +8 -0
  219. package/packages/browser/src/test-helpers/fixtures/cdn-settings.ts +301 -0
  220. package/packages/browser/src/test-helpers/fixtures/classic-destination.ts +25 -0
  221. package/packages/browser/src/test-helpers/fixtures/client-hints.ts +28 -0
  222. package/packages/browser/src/test-helpers/fixtures/create-fetch-method.ts +30 -0
  223. package/packages/browser/src/test-helpers/fixtures/index.ts +4 -0
  224. package/packages/browser/src/test-helpers/fixtures/page-context.ts +11 -0
  225. package/packages/browser/src/test-helpers/test-writekeys.ts +5 -0
  226. package/packages/browser/src/test-helpers/type-assertions.ts +11 -0
  227. package/packages/browser/src/tester/__fixtures__/hightouch-snippet.ts +64 -0
  228. package/packages/browser/src/tester/__fixtures__/index.html +8 -0
  229. package/packages/browser/src/tester/ajs-perf.ts +30 -0
  230. package/packages/browser/src/tester/ajs-tester.ts +119 -0
  231. package/packages/browser/src/tester/server.js +16 -0
  232. package/packages/browser/tsconfig.build.json +9 -0
  233. package/packages/browser/tsconfig.json +13 -0
  234. package/packages/browser/webpack.config.js +106 -0
  235. package/packages/config/package.json +10 -0
  236. package/packages/config/src/index.js +4 -0
  237. package/packages/config/src/jest/config.js +50 -0
  238. package/packages/config/src/jest/get-module-map.js +34 -0
  239. package/packages/config/src/lint-staged/config.js +4 -0
  240. package/packages/config-webpack/package.json +20 -0
  241. package/packages/config-webpack/webpack.config.common.js +75 -0
  242. package/packages/consent/consent-tools/.eslintrc.js +7 -0
  243. package/packages/consent/consent-tools/.lintstagedrc.js +1 -0
  244. package/packages/consent/consent-tools/LICENSE +45 -0
  245. package/packages/consent/consent-tools/README.md +104 -0
  246. package/packages/consent/consent-tools/jest.config.js +6 -0
  247. package/packages/consent/consent-tools/jest.setup.js +4 -0
  248. package/packages/consent/consent-tools/package.json +48 -0
  249. package/packages/consent/consent-tools/src/domain/__tests__/assertions/integrations-assertions.ts +37 -0
  250. package/packages/consent/consent-tools/src/domain/__tests__/consent-stamping.test.ts +45 -0
  251. package/packages/consent/consent-tools/src/domain/__tests__/create-wrapper.test.ts +816 -0
  252. package/packages/consent/consent-tools/src/domain/__tests__/typedef-tests.ts +21 -0
  253. package/packages/consent/consent-tools/src/domain/consent-changed.ts +51 -0
  254. package/packages/consent/consent-tools/src/domain/consent-stamping.ts +19 -0
  255. package/packages/consent/consent-tools/src/domain/create-wrapper.ts +238 -0
  256. package/packages/consent/consent-tools/src/domain/get-initialized-analytics.ts +25 -0
  257. package/packages/consent/consent-tools/src/domain/load-cancellation.ts +31 -0
  258. package/packages/consent/consent-tools/src/domain/validation/__tests__/options-validators.test.ts +77 -0
  259. package/packages/consent/consent-tools/src/domain/validation/__tests__/validation-error.test.ts +15 -0
  260. package/packages/consent/consent-tools/src/domain/validation/common-validators.ts +19 -0
  261. package/packages/consent/consent-tools/src/domain/validation/index.ts +1 -0
  262. package/packages/consent/consent-tools/src/domain/validation/options-validators.ts +74 -0
  263. package/packages/consent/consent-tools/src/domain/validation/validation-error.ts +11 -0
  264. package/packages/consent/consent-tools/src/index.ts +16 -0
  265. package/packages/consent/consent-tools/src/types/errors.ts +14 -0
  266. package/packages/consent/consent-tools/src/types/index.ts +3 -0
  267. package/packages/consent/consent-tools/src/types/settings.ts +121 -0
  268. package/packages/consent/consent-tools/src/types/wrapper.ts +107 -0
  269. package/packages/consent/consent-tools/src/utils/index.ts +4 -0
  270. package/packages/consent/consent-tools/src/utils/pick.ts +18 -0
  271. package/packages/consent/consent-tools/src/utils/pipe.ts +14 -0
  272. package/packages/consent/consent-tools/src/utils/resolve-when.ts +32 -0
  273. package/packages/consent/consent-tools/src/utils/uniq.ts +4 -0
  274. package/packages/consent/consent-tools/tsconfig.build.json +9 -0
  275. package/packages/consent/consent-tools/tsconfig.json +12 -0
  276. package/packages/consent/consent-wrapper-onetrust/.eslintrc.js +7 -0
  277. package/packages/consent/consent-wrapper-onetrust/.lintstagedrc.js +1 -0
  278. package/packages/consent/consent-wrapper-onetrust/LICENSE +45 -0
  279. package/packages/consent/consent-wrapper-onetrust/README.md +125 -0
  280. package/packages/consent/consent-wrapper-onetrust/img/onetrust-cat-id.jpg +0 -0
  281. package/packages/consent/consent-wrapper-onetrust/img/onetrust-popup.jpg +0 -0
  282. package/packages/consent/consent-wrapper-onetrust/jest.config.js +6 -0
  283. package/packages/consent/consent-wrapper-onetrust/jest.setup.js +4 -0
  284. package/packages/consent/consent-wrapper-onetrust/package.json +60 -0
  285. package/packages/consent/consent-wrapper-onetrust/src/domain/__tests__/wrapper.test.ts +151 -0
  286. package/packages/consent/consent-wrapper-onetrust/src/domain/wrapper.ts +61 -0
  287. package/packages/consent/consent-wrapper-onetrust/src/index.ts +6 -0
  288. package/packages/consent/consent-wrapper-onetrust/src/index.umd.ts +11 -0
  289. package/packages/consent/consent-wrapper-onetrust/src/lib/__tests__/onetrust-api.test.ts +181 -0
  290. package/packages/consent/consent-wrapper-onetrust/src/lib/onetrust-api.ts +155 -0
  291. package/packages/consent/consent-wrapper-onetrust/src/lib/validation/index.ts +1 -0
  292. package/packages/consent/consent-wrapper-onetrust/src/lib/validation/onetrust-api-error.ts +11 -0
  293. package/packages/consent/consent-wrapper-onetrust/src/test-helpers/mocks.ts +23 -0
  294. package/packages/consent/consent-wrapper-onetrust/src/test-helpers/onetrust-globals.d.ts +11 -0
  295. package/packages/consent/consent-wrapper-onetrust/src/test-helpers/utils.ts +3 -0
  296. package/packages/consent/consent-wrapper-onetrust/tsconfig.build.json +9 -0
  297. package/packages/consent/consent-wrapper-onetrust/tsconfig.json +11 -0
  298. package/packages/consent/consent-wrapper-onetrust/webpack.config.js +25 -0
  299. package/packages/core/.eslintrc.js +4 -0
  300. package/packages/core/.lintstagedrc.js +1 -0
  301. package/packages/core/LICENSE.MD +45 -0
  302. package/packages/core/README.md +3 -0
  303. package/packages/core/jest.config.js +5 -0
  304. package/packages/core/jest.setup.js +10 -0
  305. package/packages/core/package.json +40 -0
  306. package/packages/core/src/analytics/__tests__/dispatch.test.ts +95 -0
  307. package/packages/core/src/analytics/dispatch.ts +58 -0
  308. package/packages/core/src/analytics/index.ts +11 -0
  309. package/packages/core/src/callback/__tests__/index.test.ts +85 -0
  310. package/packages/core/src/callback/index.ts +51 -0
  311. package/packages/core/src/context/index.ts +123 -0
  312. package/packages/core/src/emitter/__tests__/emitter.test.ts +74 -0
  313. package/packages/core/src/emitter/index.ts +65 -0
  314. package/packages/core/src/emitter/interface.ts +31 -0
  315. package/packages/core/src/events/__tests__/index.test.ts +394 -0
  316. package/packages/core/src/events/index.ts +280 -0
  317. package/packages/core/src/events/interfaces.ts +475 -0
  318. package/packages/core/src/index.ts +19 -0
  319. package/packages/core/src/logger/__tests__/index.test.ts +66 -0
  320. package/packages/core/src/logger/index.ts +74 -0
  321. package/packages/core/src/plugins/index.ts +43 -0
  322. package/packages/core/src/priority-queue/__tests__/backoff.test.ts +23 -0
  323. package/packages/core/src/priority-queue/__tests__/index.test.ts +158 -0
  324. package/packages/core/src/priority-queue/backoff.ts +24 -0
  325. package/packages/core/src/priority-queue/index.ts +103 -0
  326. package/packages/core/src/queue/__tests__/event-queue.test.ts +678 -0
  327. package/packages/core/src/queue/__tests__/extension-flushing.test.ts +416 -0
  328. package/packages/core/src/queue/delivery.ts +73 -0
  329. package/packages/core/src/queue/event-queue.ts +318 -0
  330. package/packages/core/src/stats/__tests__/index.test.ts +103 -0
  331. package/packages/core/src/stats/index.ts +88 -0
  332. package/packages/core/src/task/__tests__/task-group.test.ts +26 -0
  333. package/packages/core/src/task/task-group.ts +31 -0
  334. package/packages/core/src/user/index.ts +7 -0
  335. package/packages/core/src/utils/__tests__/group-by.test.ts +96 -0
  336. package/packages/core/src/utils/__tests__/is-plain-object.test.ts +27 -0
  337. package/packages/core/src/utils/__tests__/is-thenable.test.ts +39 -0
  338. package/packages/core/src/utils/bind-all.ts +19 -0
  339. package/packages/core/src/utils/get-global.ts +17 -0
  340. package/packages/core/src/utils/group-by.ts +30 -0
  341. package/packages/core/src/utils/has-properties.ts +7 -0
  342. package/packages/core/src/utils/is-plain-object.ts +26 -0
  343. package/packages/core/src/utils/is-thenable.ts +9 -0
  344. package/packages/core/src/utils/p-while.ts +12 -0
  345. package/packages/core/src/utils/pick.ts +8 -0
  346. package/packages/core/src/utils/ts-helpers.ts +13 -0
  347. package/packages/core/src/validation/__tests__/assertions.test.ts +155 -0
  348. package/packages/core/src/validation/assertions.ts +72 -0
  349. package/packages/core/src/validation/errors.ts +8 -0
  350. package/packages/core/src/validation/helpers.ts +23 -0
  351. package/packages/core/test-helpers/index.ts +2 -0
  352. package/packages/core/test-helpers/test-ctx.ts +7 -0
  353. package/packages/core/test-helpers/test-event-queue.ts +7 -0
  354. package/packages/core/tsconfig.build.json +9 -0
  355. package/packages/core/tsconfig.json +11 -0
  356. package/packages/node/.eslintrc.js +7 -0
  357. package/packages/node/.lintstagedrc.js +1 -0
  358. package/packages/node/LICENSE +45 -0
  359. package/packages/node/README.md +138 -0
  360. package/packages/node/jest.config.js +5 -0
  361. package/packages/node/jest.setup.js +4 -0
  362. package/packages/node/package.json +50 -0
  363. package/packages/node/scripts/version.sh +11 -0
  364. package/packages/node/src/__tests__/callback.test.ts +47 -0
  365. package/packages/node/src/__tests__/disable.integration.test.ts +42 -0
  366. package/packages/node/src/__tests__/emitter.integration.test.ts +45 -0
  367. package/packages/node/src/__tests__/graceful-shutdown-integration.test.ts +244 -0
  368. package/packages/node/src/__tests__/http-client.integration.test.ts +69 -0
  369. package/packages/node/src/__tests__/http-integration.test.ts +362 -0
  370. package/packages/node/src/__tests__/integration.test.ts +357 -0
  371. package/packages/node/src/__tests__/plugins.test.ts +16 -0
  372. package/packages/node/src/__tests__/settings.test.ts +9 -0
  373. package/packages/node/src/__tests__/test-helpers/assert-shape/http-request-event.ts +13 -0
  374. package/packages/node/src/__tests__/test-helpers/assert-shape/index.ts +2 -0
  375. package/packages/node/src/__tests__/test-helpers/assert-shape/segment-http-api.ts +43 -0
  376. package/packages/node/src/__tests__/test-helpers/create-test-analytics.ts +42 -0
  377. package/packages/node/src/__tests__/test-helpers/factories.ts +17 -0
  378. package/packages/node/src/__tests__/test-helpers/is-valid-date.ts +6 -0
  379. package/packages/node/src/__tests__/test-helpers/resolve-ctx.ts +19 -0
  380. package/packages/node/src/__tests__/test-helpers/resolve-emitter.ts +11 -0
  381. package/packages/node/src/__tests__/test-helpers/sleep.ts +3 -0
  382. package/packages/node/src/__tests__/test-helpers/test-plugin.ts +16 -0
  383. package/packages/node/src/__tests__/typedef-tests.ts +120 -0
  384. package/packages/node/src/app/analytics-node.ts +299 -0
  385. package/packages/node/src/app/context.ts +11 -0
  386. package/packages/node/src/app/dispatch-emit.ts +42 -0
  387. package/packages/node/src/app/emitter.ts +23 -0
  388. package/packages/node/src/app/event-factory.ts +20 -0
  389. package/packages/node/src/app/event-queue.ts +23 -0
  390. package/packages/node/src/app/settings.ts +49 -0
  391. package/packages/node/src/app/types/index.ts +3 -0
  392. package/packages/node/src/app/types/params.ts +76 -0
  393. package/packages/node/src/app/types/plugin.ts +5 -0
  394. package/packages/node/src/app/types/segment-event.ts +7 -0
  395. package/packages/node/src/generated/version.ts +2 -0
  396. package/packages/node/src/index.ts +26 -0
  397. package/packages/node/src/lib/__tests__/abort.test.ts +54 -0
  398. package/packages/node/src/lib/__tests__/create-url.test.ts +35 -0
  399. package/packages/node/src/lib/__tests__/env.test.ts +52 -0
  400. package/packages/node/src/lib/__tests__/get-message-id.test.ts +21 -0
  401. package/packages/node/src/lib/abort.ts +77 -0
  402. package/packages/node/src/lib/base-64-encode.ts +8 -0
  403. package/packages/node/src/lib/create-url.ts +11 -0
  404. package/packages/node/src/lib/env.ts +45 -0
  405. package/packages/node/src/lib/extract-promise-parts.ts +21 -0
  406. package/packages/node/src/lib/fetch.ts +16 -0
  407. package/packages/node/src/lib/get-message-id.ts +10 -0
  408. package/packages/node/src/lib/http-client.ts +95 -0
  409. package/packages/node/src/lib/uuid.ts +1 -0
  410. package/packages/node/src/plugins/segmentio/__tests__/methods.test.ts +223 -0
  411. package/packages/node/src/plugins/segmentio/__tests__/publisher.test.ts +411 -0
  412. package/packages/node/src/plugins/segmentio/context-batch.ts +71 -0
  413. package/packages/node/src/plugins/segmentio/index.ts +66 -0
  414. package/packages/node/src/plugins/segmentio/publisher.ts +265 -0
  415. package/packages/node/tsconfig.build.json +9 -0
  416. package/packages/node/tsconfig.json +10 -0
  417. package/packages/test-helpers/.eslintrc.js +7 -0
  418. package/packages/test-helpers/.lintstagedrc.js +1 -0
  419. package/packages/test-helpers/jest.config.js +3 -0
  420. package/packages/test-helpers/package.json +26 -0
  421. package/packages/test-helpers/src/analytics/cdn-settings-builder.ts +79 -0
  422. package/packages/test-helpers/src/analytics/index.ts +1 -0
  423. package/packages/test-helpers/src/index.ts +2 -0
  424. package/packages/test-helpers/src/utils/index.ts +1 -0
  425. package/packages/test-helpers/src/utils/sleep.ts +4 -0
  426. package/packages/test-helpers/tsconfig.build.json +9 -0
  427. package/packages/test-helpers/tsconfig.json +11 -0
  428. package/tsconfig.json +21 -0
  429. package/turbo.json +39 -0
  430. package/typings/get-monorepo-packages.d.ts +9 -0
  431. package/typings/spawn.d.ts +10 -0
@@ -0,0 +1,1213 @@
1
+ /* eslint-disable @typescript-eslint/no-floating-promises */
2
+ import { cdnSettingsKitchenSink } from '../../test-helpers/fixtures/cdn-settings'
3
+ import { createMockFetchImplementation } from '../../test-helpers/fixtures/create-fetch-method'
4
+ import { Context } from '../../core/context'
5
+ import { Plugin } from '../../core/plugin'
6
+ import { JSDOM } from 'jsdom'
7
+ import { Analytics, InitOptions } from '../../core/analytics'
8
+ import { LegacyDestination } from '../../plugins/ajs-destination'
9
+ import { PersistedPriorityQueue } from '../../lib/priority-queue/persisted'
10
+ // @ts-ignore loadLegacySettings mocked dependency is accused as unused
11
+ import { HtEventsBrowser, loadLegacySettings } from '..'
12
+ // @ts-ignore isOffline mocked dependency is accused as unused
13
+ import { isOffline } from '../../core/connection'
14
+ import * as HightouchPlugin from '../../plugins/hightouchio'
15
+ import jar from 'js-cookie'
16
+ import { PriorityQueue } from '../../lib/priority-queue'
17
+ import { getCDN, setGlobalCDNUrl } from '../../lib/parse-cdn'
18
+ import { clearAjsBrowserStorage } from '../../test-helpers/browser-storage'
19
+ import { parseFetchCall } from '../../test-helpers/fetch-parse'
20
+ import { ActionDestination } from '../../plugins/remote-loader'
21
+ import { UADataValues } from '../../lib/client-hints/interfaces'
22
+ import {
23
+ highEntropyTestData,
24
+ lowEntropyTestData,
25
+ } from '../../test-helpers/fixtures/client-hints'
26
+ import { getGlobalAnalytics } from '../..'
27
+
28
+ let fetchCalls: ReturnType<typeof parseFetchCall>[] = []
29
+
30
+ jest.mock('unfetch', () => {
31
+ return {
32
+ __esModule: true,
33
+ default: (url: RequestInfo, body?: RequestInit) => {
34
+ const call = parseFetchCall([url, body])
35
+ fetchCalls.push(call)
36
+ return createMockFetchImplementation(cdnSettingsKitchenSink)(url, body)
37
+ },
38
+ }
39
+ })
40
+
41
+ const sleep = (time: number): Promise<void> =>
42
+ new Promise((resolve) => {
43
+ setTimeout(resolve, time)
44
+ })
45
+
46
+ const xt: Plugin = {
47
+ name: 'Test Plugin',
48
+ type: 'utility',
49
+ version: '1.0',
50
+
51
+ load(_ctx: Context): Promise<void> {
52
+ return Promise.resolve()
53
+ },
54
+
55
+ isLoaded(): boolean {
56
+ return true
57
+ },
58
+
59
+ track: async (ctx) => ctx,
60
+ identify: async (ctx) => ctx,
61
+ page: async (ctx) => ctx,
62
+ group: async (ctx) => ctx,
63
+ alias: async (ctx) => ctx,
64
+ }
65
+
66
+ const amplitude: Plugin = {
67
+ ...xt,
68
+ name: 'Amplitude',
69
+ type: 'destination',
70
+ }
71
+
72
+ const googleAnalytics: Plugin = {
73
+ ...xt,
74
+ name: 'Google Analytics',
75
+ type: 'destination',
76
+ }
77
+
78
+ const enrichBilling: Plugin = {
79
+ ...xt,
80
+ name: 'Billing Enrichment',
81
+ type: 'enrichment',
82
+
83
+ track: async (ctx) => {
84
+ ctx.event.properties = {
85
+ ...ctx.event.properties,
86
+ billingPlan: 'free-99',
87
+ }
88
+ return ctx
89
+ },
90
+ }
91
+
92
+ const writeKey = 'foo'
93
+ const amplitudeWriteKey = 'bar'
94
+
95
+ beforeEach(() => {
96
+ setGlobalCDNUrl(undefined as any)
97
+ })
98
+
99
+ describe('Initialization', () => {
100
+ beforeEach(async () => {
101
+ fetchCalls = []
102
+ jest.resetAllMocks()
103
+ jest.resetModules()
104
+ })
105
+
106
+ it('loads plugins', async () => {
107
+ await HtEventsBrowser.load({
108
+ writeKey,
109
+ plugins: [xt],
110
+ })
111
+
112
+ expect(xt.isLoaded()).toBe(true)
113
+ })
114
+
115
+ it('loads async plugins', async () => {
116
+ let pluginLoaded = false
117
+ const onLoad = jest.fn(() => {
118
+ pluginLoaded = true
119
+ })
120
+
121
+ const lazyPlugin: Plugin = {
122
+ name: 'Test 2',
123
+ type: 'utility',
124
+ version: '1.0',
125
+
126
+ load: async (_ctx) => {
127
+ setTimeout(onLoad, 300)
128
+ },
129
+ isLoaded: () => {
130
+ return pluginLoaded
131
+ },
132
+ }
133
+
134
+ jest.spyOn(lazyPlugin, 'load')
135
+ await HtEventsBrowser.load({ writeKey, plugins: [lazyPlugin] })
136
+
137
+ expect(lazyPlugin.load).toHaveBeenCalled()
138
+ expect(onLoad).not.toHaveBeenCalled()
139
+ expect(pluginLoaded).toBe(false)
140
+
141
+ await sleep(300)
142
+
143
+ expect(onLoad).toHaveBeenCalled()
144
+ expect(pluginLoaded).toBe(true)
145
+ })
146
+
147
+ it('ready method is called only when all plugins with ready have declared themselves as ready', async () => {
148
+ const ready = jest.fn()
149
+
150
+ const lazyPlugin1: Plugin = {
151
+ name: 'Test 2',
152
+ type: 'destination',
153
+ version: '1.0',
154
+
155
+ load: async (_ctx) => {},
156
+ ready: async () => {
157
+ return new Promise((resolve) => setTimeout(resolve, 300))
158
+ },
159
+ isLoaded: () => true,
160
+ }
161
+
162
+ const lazyPlugin2: Plugin = {
163
+ name: 'Test 2',
164
+ type: 'destination',
165
+ version: '1.0',
166
+
167
+ load: async (_ctx) => {},
168
+ ready: async () => {
169
+ return new Promise((resolve) => setTimeout(resolve, 100))
170
+ },
171
+ isLoaded: () => true,
172
+ }
173
+
174
+ jest.spyOn(lazyPlugin1, 'load')
175
+ jest.spyOn(lazyPlugin2, 'load')
176
+ const [analytics] = await HtEventsBrowser.load({
177
+ writeKey,
178
+ plugins: [lazyPlugin1, lazyPlugin2, xt],
179
+ })
180
+
181
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
182
+ analytics.ready(ready)
183
+ expect(lazyPlugin1.load).toHaveBeenCalled()
184
+ expect(lazyPlugin2.load).toHaveBeenCalled()
185
+ expect(ready).not.toHaveBeenCalled()
186
+
187
+ await sleep(100)
188
+ expect(ready).not.toHaveBeenCalled()
189
+
190
+ await sleep(200)
191
+ expect(ready).toHaveBeenCalled()
192
+ })
193
+
194
+ describe('cdn', () => {
195
+ it('should get the correct CDN in plugins if the CDN overridden', async () => {
196
+ const overriddenCDNUrl = 'http://cdn.hightouch-events.com' // http instead of https
197
+ await HtEventsBrowser.load({
198
+ cdnURL: overriddenCDNUrl,
199
+ writeKey,
200
+ plugins: [
201
+ {
202
+ ...xt,
203
+ load: async () => {
204
+ expect(getGlobalAnalytics()).toBeUndefined()
205
+ expect(getCDN()).toContain(overriddenCDNUrl)
206
+ },
207
+ },
208
+ ],
209
+ })
210
+
211
+ // cdn settings dont get called anymore
212
+ // expect(fetchCalls[0].url).toContain(overriddenCDNUrl)
213
+ // expect.assertions(3)
214
+ })
215
+ })
216
+
217
+ describe('globalAnalyticsKey', () => {
218
+ const overrideKey = 'myKey'
219
+ const buffer = {
220
+ foo: 'bar',
221
+ }
222
+
223
+ beforeEach(() => {
224
+ ;(window as any)[overrideKey] = buffer
225
+ })
226
+ afterEach(() => {
227
+ delete (window as any)[overrideKey]
228
+ })
229
+ it('should default to window.htevents', async () => {
230
+ const defaultObj = { original: 'default' }
231
+ ;(window as any)['htevents'] = defaultObj
232
+
233
+ await HtEventsBrowser.load({
234
+ writeKey,
235
+ plugins: [
236
+ {
237
+ ...xt,
238
+ load: async () => {
239
+ expect(getGlobalAnalytics()).toBe(defaultObj)
240
+ },
241
+ },
242
+ ],
243
+ })
244
+ expect.assertions(1)
245
+ })
246
+
247
+ it('should set the global window key for the analytics buffer with the setting option', async () => {
248
+ await HtEventsBrowser.load(
249
+ {
250
+ writeKey,
251
+ plugins: [
252
+ {
253
+ ...xt,
254
+ load: async () => {
255
+ expect(getGlobalAnalytics()).toBe(buffer)
256
+ },
257
+ },
258
+ ],
259
+ },
260
+ {
261
+ globalAnalyticsKey: overrideKey,
262
+ }
263
+ )
264
+ expect.assertions(1)
265
+ })
266
+ })
267
+
268
+ describe('Load options', () => {
269
+ it('gets high entropy client hints if set', async () => {
270
+ ;(window.navigator as any).userAgentData = {
271
+ ...lowEntropyTestData,
272
+ getHighEntropyValues: jest
273
+ .fn()
274
+ .mockImplementation((hints: string[]): Promise<UADataValues> => {
275
+ let result = {}
276
+ Object.entries(highEntropyTestData).forEach(([k, v]) => {
277
+ if (hints.includes(k)) {
278
+ result = {
279
+ ...result,
280
+ [k]: v,
281
+ }
282
+ }
283
+ })
284
+ return Promise.resolve({
285
+ ...lowEntropyTestData,
286
+ ...result,
287
+ })
288
+ }),
289
+ toJSON: jest.fn(() => lowEntropyTestData),
290
+ }
291
+
292
+ const [ajs] = await HtEventsBrowser.load(
293
+ { writeKey },
294
+ { highEntropyValuesClientHints: ['architecture'] }
295
+ )
296
+
297
+ const evt = await ajs.track('foo')
298
+ expect(evt.event.context?.userAgentData).toEqual({
299
+ ...lowEntropyTestData,
300
+ architecture: 'x86',
301
+ })
302
+ })
303
+ it('calls page if initialpageview is set', async () => {
304
+ jest.mock('../../core/analytics')
305
+ const mockPage = jest.fn().mockImplementation(() => Promise.resolve())
306
+ Analytics.prototype.page = mockPage
307
+
308
+ await HtEventsBrowser.load({ writeKey }, { initialPageview: true })
309
+
310
+ expect(mockPage).toHaveBeenCalled()
311
+ })
312
+
313
+ it('does not call page if initialpageview is not set', async () => {
314
+ jest.mock('../../core/analytics')
315
+ const mockPage = jest.fn()
316
+ Analytics.prototype.page = mockPage
317
+ await HtEventsBrowser.load({ writeKey }, { initialPageview: false })
318
+ expect(mockPage).not.toHaveBeenCalled()
319
+ })
320
+
321
+ it('does not use a persisted queue when disableClientPersistence is true', async () => {
322
+ const [ajs] = await HtEventsBrowser.load(
323
+ {
324
+ writeKey,
325
+ },
326
+ {
327
+ disableClientPersistence: true,
328
+ }
329
+ )
330
+
331
+ expect(ajs.queue.queue instanceof PriorityQueue).toBe(true)
332
+ expect(ajs.queue.queue instanceof PersistedPriorityQueue).toBe(false)
333
+ })
334
+
335
+ it('uses a persisted queue by default', async () => {
336
+ const [ajs] = await HtEventsBrowser.load({
337
+ writeKey,
338
+ })
339
+
340
+ expect(ajs.queue.queue instanceof PersistedPriorityQueue).toBe(true)
341
+ })
342
+
343
+ it('disables identity persistance when disableClientPersistence is true', async () => {
344
+ const [ajs] = await HtEventsBrowser.load(
345
+ {
346
+ writeKey,
347
+ },
348
+ {
349
+ disableClientPersistence: true,
350
+ }
351
+ )
352
+
353
+ expect(ajs.user().options.persist).toBe(false)
354
+ expect(ajs.group().options.persist).toBe(false)
355
+ })
356
+
357
+ it('doesnt fetch remote source settings by default', async () => {
358
+ await HtEventsBrowser.load({
359
+ writeKey,
360
+ })
361
+
362
+ expect(fetchCalls.length).toBe(0)
363
+ // expect(fetchCalls[0].url).toMatch(/\/settings$/)
364
+ })
365
+
366
+ it('does not fetch source settings if cdnSettings is set', async () => {
367
+ await HtEventsBrowser.load({
368
+ writeKey,
369
+ cdnSettings: { integrations: {} },
370
+ })
371
+
372
+ expect(fetchCalls.length).toBe(0)
373
+ })
374
+ })
375
+
376
+ describe('options.integrations permutations', () => {
377
+ const settings = { writeKey }
378
+
379
+ it('does not load Hightouch.io if integrations.All is false and Hightouch.io is not listed', async () => {
380
+ const options: { integrations: { [key: string]: boolean } } = {
381
+ integrations: { All: false },
382
+ }
383
+ const analyticsResponse = await HtEventsBrowser.load(settings, options)
384
+
385
+ const hightouchio = analyticsResponse[0].queue.plugins.find(
386
+ (p) => p.name === 'Hightouch.io'
387
+ )
388
+
389
+ expect(hightouchio).toBeUndefined()
390
+ })
391
+
392
+ it('does not load Hightouch.io if its set to false', async () => {
393
+ const options: { integrations?: { [key: string]: boolean } } = {
394
+ integrations: { 'Hightouch.io': false },
395
+ }
396
+ const analyticsResponse = await HtEventsBrowser.load(settings, options)
397
+
398
+ const hightouchio = analyticsResponse[0].queue.plugins.find(
399
+ (p) => p.name === 'Hightouch.io'
400
+ )
401
+
402
+ expect(hightouchio).toBeUndefined()
403
+ })
404
+
405
+ it('loads Hightouch.io if integrations.All is false and Hightouch.io is listed', async () => {
406
+ const options: { integrations: { [key: string]: boolean } } = {
407
+ integrations: { All: false, 'Hightouch.io': true },
408
+ }
409
+ const analyticsResponse = await HtEventsBrowser.load(settings, options)
410
+
411
+ const hightouchio = analyticsResponse[0].queue.plugins.find(
412
+ (p) => p.name === 'Hightouch.io'
413
+ )
414
+
415
+ expect(hightouchio).toBeDefined()
416
+ })
417
+
418
+ it('loads Hightouch.io if integrations.All is undefined', async () => {
419
+ const options: { integrations: { [key: string]: boolean } } = {
420
+ integrations: { 'Hightouch.io': true },
421
+ }
422
+ const analyticsResponse = await HtEventsBrowser.load(settings, options)
423
+
424
+ const hightouchio = analyticsResponse[0].queue.plugins.find(
425
+ (p) => p.name === 'Hightouch.io'
426
+ )
427
+
428
+ expect(hightouchio).toBeDefined()
429
+ })
430
+
431
+ it('loads Hightouch.io if integrations is undefined', async () => {
432
+ const options: { integrations?: { [key: string]: boolean } } = {
433
+ integrations: undefined,
434
+ }
435
+ const analyticsResponse = await HtEventsBrowser.load(settings, options)
436
+
437
+ const hightouchio = analyticsResponse[0].queue.plugins.find(
438
+ (p) => p.name === 'Hightouch.io'
439
+ )
440
+
441
+ expect(hightouchio).toBeDefined()
442
+ })
443
+
444
+ it('loads selected plugins when Hightouch.io is false', async () => {
445
+ const options: { integrations?: { [key: string]: boolean } } = {
446
+ integrations: {
447
+ 'Test Plugin': true,
448
+ 'Hightouch.io': false,
449
+ },
450
+ }
451
+ const analyticsResponse = await HtEventsBrowser.load(
452
+ { ...settings, plugins: [xt] },
453
+ options
454
+ )
455
+
456
+ const plugin = analyticsResponse[0].queue.plugins.find(
457
+ (p) => p.name === 'Test Plugin'
458
+ )
459
+
460
+ const hightouchio = analyticsResponse[0].queue.plugins.find(
461
+ (p) => p.name === 'Hightouch.io'
462
+ )
463
+
464
+ expect(plugin).toBeDefined()
465
+ expect(hightouchio).toBeUndefined()
466
+ })
467
+
468
+ it('loads selected plugins when Hightouch.io and All are false', async () => {
469
+ const options: { integrations?: { [key: string]: boolean } } = {
470
+ integrations: {
471
+ All: false,
472
+ 'Test Plugin': true,
473
+ 'Hightouch.io': false,
474
+ },
475
+ }
476
+ const analyticsResponse = await HtEventsBrowser.load(
477
+ { ...settings, plugins: [xt] },
478
+ options
479
+ )
480
+
481
+ const plugin = analyticsResponse[0].queue.plugins.find(
482
+ (p) => p.name === 'Test Plugin'
483
+ )
484
+
485
+ const hightouchio = analyticsResponse[0].queue.plugins.find(
486
+ (p) => p.name === 'Hightouch.io'
487
+ )
488
+
489
+ expect(plugin).toBeDefined()
490
+ expect(hightouchio).toBeUndefined()
491
+ })
492
+ })
493
+ })
494
+
495
+ describe('Dispatch', () => {
496
+ it('dispatches events to destinations', async () => {
497
+ const [ajs] = await HtEventsBrowser.load({
498
+ writeKey,
499
+ plugins: [amplitude, googleAnalytics],
500
+ })
501
+
502
+ const hightouchio = ajs.queue.plugins.find((p) => p.name === 'Hightouch.io')
503
+ expect(hightouchio).toBeDefined()
504
+
505
+ const ampSpy = jest.spyOn(amplitude, 'track')
506
+ const gaSpy = jest.spyOn(googleAnalytics, 'track')
507
+ const hightouchSpy = jest.spyOn(hightouchio!, 'track')
508
+
509
+ const boo = await ajs.track('Boo!', {
510
+ total: 25,
511
+ userId: '👻',
512
+ })
513
+
514
+ expect(ampSpy).toHaveBeenCalledWith(boo)
515
+ expect(gaSpy).toHaveBeenCalledWith(boo)
516
+ expect(hightouchSpy).toHaveBeenCalledWith(boo)
517
+ })
518
+
519
+ it('does not dispatch events to destinations on deny list', async () => {
520
+ const [ajs] = await HtEventsBrowser.load({
521
+ writeKey,
522
+ plugins: [amplitude, googleAnalytics],
523
+ })
524
+
525
+ const hightouchio = ajs.queue.plugins.find((p) => p.name === 'Hightouch.io')
526
+ expect(hightouchio).toBeDefined()
527
+
528
+ const ampSpy = jest.spyOn(amplitude, 'track')
529
+ const gaSpy = jest.spyOn(googleAnalytics, 'track')
530
+ const hightouchSpy = jest.spyOn(hightouchio!, 'track')
531
+
532
+ const boo = await ajs.track(
533
+ 'Boo!',
534
+ {
535
+ total: 25,
536
+ userId: '👻',
537
+ },
538
+ {
539
+ integrations: {
540
+ Amplitude: false,
541
+ 'Hightouch.io': false,
542
+ },
543
+ }
544
+ )
545
+
546
+ expect(gaSpy).toHaveBeenCalledWith(boo)
547
+ expect(ampSpy).not.toHaveBeenCalled()
548
+ expect(hightouchSpy).not.toHaveBeenCalled()
549
+ })
550
+
551
+ it('does dispatch events to Hightouch.io when All is false', async () => {
552
+ const [ajs] = await HtEventsBrowser.load({
553
+ writeKey,
554
+ plugins: [amplitude, googleAnalytics],
555
+ })
556
+
557
+ const hightouchio = ajs.queue.plugins.find((p) => p.name === 'Hightouch.io')
558
+ expect(hightouchio).toBeDefined()
559
+
560
+ const ampSpy = jest.spyOn(amplitude, 'track')
561
+ const gaSpy = jest.spyOn(googleAnalytics, 'track')
562
+ const hightouchSpy = jest.spyOn(hightouchio!, 'track')
563
+
564
+ const boo = await ajs.track(
565
+ 'Boo!',
566
+ {
567
+ total: 25,
568
+ userId: '👻',
569
+ },
570
+ {
571
+ integrations: {
572
+ All: false,
573
+ },
574
+ }
575
+ )
576
+
577
+ expect(gaSpy).not.toHaveBeenCalled()
578
+ expect(ampSpy).not.toHaveBeenCalled()
579
+ expect(hightouchSpy).toHaveBeenCalledWith(boo)
580
+ })
581
+
582
+ it('enriches events before dispatching', async () => {
583
+ const [ajs] = await HtEventsBrowser.load({
584
+ writeKey,
585
+ plugins: [enrichBilling, amplitude, googleAnalytics],
586
+ })
587
+
588
+ const boo = await ajs.track('Boo!', {
589
+ total: 25,
590
+ })
591
+
592
+ expect(boo.event.properties).toMatchInlineSnapshot(`
593
+ Object {
594
+ "billingPlan": "free-99",
595
+ "total": 25,
596
+ }
597
+ `)
598
+ })
599
+
600
+ it('collects metrics for every event', async () => {
601
+ const [ajs] = await HtEventsBrowser.load({
602
+ writeKey,
603
+ plugins: [amplitude],
604
+ })
605
+
606
+ const delivered = await ajs.track('Fruit Basket', {
607
+ items: ['🍌', '🍇', '🍎'],
608
+ userId: 'Healthy person',
609
+ })
610
+
611
+ const metrics = delivered.stats.metrics
612
+
613
+ expect(metrics.map((m) => m.metric)).toMatchInlineSnapshot(`
614
+ Array [
615
+ "message_dispatched",
616
+ "plugin_time",
617
+ "plugin_time",
618
+ "plugin_time",
619
+ "message_delivered",
620
+ "plugin_time",
621
+ "delivered",
622
+ ]
623
+ `)
624
+ })
625
+ })
626
+
627
+ describe('Group', () => {
628
+ it('manages Group state', async () => {
629
+ const [analytics] = await HtEventsBrowser.load({
630
+ writeKey,
631
+ })
632
+
633
+ const group = analytics.group()
634
+
635
+ const ctx = await analytics.group('coolKids', {
636
+ coolKids: true,
637
+ })
638
+
639
+ expect(ctx.event.groupId).toEqual('coolKids')
640
+ expect(ctx.event.traits).toEqual({ coolKids: true })
641
+
642
+ expect(group.id()).toEqual('coolKids')
643
+ expect(group.traits()).toEqual({ coolKids: true })
644
+ })
645
+ })
646
+
647
+ describe('Alias', () => {
648
+ it('generates alias events', async () => {
649
+ const [analytics] = await HtEventsBrowser.load({
650
+ writeKey,
651
+ plugins: [amplitude],
652
+ })
653
+
654
+ jest.spyOn(amplitude, 'alias')
655
+
656
+ const ctx = await analytics.alias('netto farah', 'netto')
657
+
658
+ expect(ctx.event.userId).toEqual('netto farah')
659
+ expect(ctx.event.previousId).toEqual('netto')
660
+
661
+ expect(amplitude.alias).toHaveBeenCalled()
662
+ })
663
+
664
+ it('falls back to userID in cookies if no id passed', async () => {
665
+ jar.set('htjs_user_id', 'dan')
666
+ const [analytics] = await HtEventsBrowser.load({
667
+ writeKey,
668
+ plugins: [amplitude],
669
+ })
670
+
671
+ jest.spyOn(amplitude, 'alias')
672
+
673
+ // @ts-ignore ajs 1.0 parity - allows empty alias calls
674
+ const ctx = await analytics.alias()
675
+
676
+ expect(ctx.event.userId).toEqual('dan')
677
+ expect(amplitude.alias).toHaveBeenCalled()
678
+ })
679
+ })
680
+
681
+ describe('pageview', () => {
682
+ it('makes a page call with the given url', async () => {
683
+ console.warn = (): void => {}
684
+ const analytics = new Analytics({ writeKey: writeKey })
685
+ const mockPage = jest.spyOn(analytics, 'page')
686
+ await analytics.pageview('www.foo.com')
687
+
688
+ expect(mockPage).toHaveBeenCalledWith({ path: 'www.foo.com' })
689
+ })
690
+ })
691
+
692
+ describe('setAnonymousId', () => {
693
+ beforeEach(() => {
694
+ clearAjsBrowserStorage()
695
+ })
696
+
697
+ it('calling setAnonymousId will set a new anonymousId and returns it', async () => {
698
+ const [analytics] = await HtEventsBrowser.load({
699
+ writeKey,
700
+ plugins: [amplitude],
701
+ })
702
+
703
+ const currentAnonymousId = analytics.user().anonymousId()
704
+ expect(currentAnonymousId).toBeDefined()
705
+ expect(currentAnonymousId).toHaveLength(36)
706
+
707
+ const newAnonymousId = analytics.setAnonymousId('🦹‍♀️')
708
+
709
+ expect(analytics.user().anonymousId()).toEqual('🦹‍♀️')
710
+ expect(newAnonymousId).toEqual('🦹‍♀️')
711
+ })
712
+ })
713
+
714
+ describe('addSourceMiddleware', () => {
715
+ it('supports registering source middlewares', async () => {
716
+ const [analytics] = await HtEventsBrowser.load({
717
+ writeKey,
718
+ })
719
+
720
+ await analytics
721
+ .addSourceMiddleware(({ next, payload }) => {
722
+ payload.obj.context = {
723
+ hello: 'from the other side',
724
+ }
725
+ next(payload)
726
+ })
727
+ .catch((err) => {
728
+ throw err
729
+ })
730
+
731
+ const ctx = await analytics.track('Hello!')
732
+
733
+ expect(ctx.event.context).toMatchObject({
734
+ hello: 'from the other side',
735
+ })
736
+ })
737
+ })
738
+
739
+ // We do not support remote integrations
740
+ describe.skip('addDestinationMiddleware', () => {
741
+ beforeEach(async () => {
742
+ jest.restoreAllMocks()
743
+ jest.resetAllMocks()
744
+
745
+ const html = `
746
+ <!DOCTYPE html>
747
+ <head>
748
+ <script>'hi'</script>
749
+ </head>
750
+ <body>
751
+ </body>
752
+ </html>
753
+ `.trim()
754
+
755
+ const jsd = new JSDOM(html, {
756
+ runScripts: 'dangerously',
757
+ resources: 'usable',
758
+ url: 'https://localhost',
759
+ })
760
+
761
+ const windowSpy = jest.spyOn(global, 'window', 'get')
762
+ windowSpy.mockImplementation(
763
+ () => jsd.window as unknown as Window & typeof globalThis
764
+ )
765
+ })
766
+
767
+ it('supports registering destination middlewares', async () => {
768
+ const [analytics] = await HtEventsBrowser.load({
769
+ writeKey,
770
+ })
771
+
772
+ const amplitude = new LegacyDestination(
773
+ 'amplitude',
774
+ 'latest',
775
+ writeKey,
776
+ {
777
+ apiKey: amplitudeWriteKey,
778
+ },
779
+ {}
780
+ )
781
+
782
+ await analytics.register(amplitude)
783
+ await amplitude.ready()
784
+
785
+ analytics
786
+ .addDestinationMiddleware('amplitude', ({ next, payload }) => {
787
+ payload.obj.properties!.hello = 'from the other side'
788
+ next(payload)
789
+ })
790
+ .catch((err) => {
791
+ throw err
792
+ })
793
+
794
+ const integrationMock = jest.spyOn(amplitude.integration!, 'track')
795
+ const ctx = await analytics.track('Hello!')
796
+
797
+ // does not modify the event
798
+ expect(ctx.event.properties).not.toEqual({
799
+ hello: 'from the other side',
800
+ })
801
+
802
+ const calledWith = integrationMock.mock.calls[0][0].properties()
803
+
804
+ // only impacted this destination
805
+ expect(calledWith).toEqual({
806
+ ...ctx.event.properties,
807
+ hello: 'from the other side',
808
+ })
809
+ })
810
+
811
+ it('supports registering action destination middlewares', async () => {
812
+ const testPlugin: Plugin = {
813
+ name: 'test',
814
+ type: 'destination',
815
+ version: '0.1.0',
816
+ load: () => Promise.resolve(),
817
+ isLoaded: () => true,
818
+ }
819
+
820
+ const [analytics] = await HtEventsBrowser.load({
821
+ writeKey,
822
+ })
823
+
824
+ const fullstory = new ActionDestination('fullstory', testPlugin)
825
+
826
+ await analytics.register(fullstory)
827
+ await fullstory.ready()
828
+
829
+ analytics
830
+ .addDestinationMiddleware('fullstory', ({ next, payload }) =>
831
+ next(payload)
832
+ )
833
+ .catch((err) => {
834
+ throw err
835
+ })
836
+
837
+ expect(analytics.queue.plugins).toContain(fullstory)
838
+ })
839
+ })
840
+
841
+ describe('use', () => {
842
+ it('registers a legacyPlugin', async () => {
843
+ const [analytics] = await HtEventsBrowser.load({
844
+ writeKey,
845
+ })
846
+
847
+ const legacyPlugin = jest.fn()
848
+ analytics.use(legacyPlugin)
849
+
850
+ expect(legacyPlugin).toHaveBeenCalledWith(analytics)
851
+ })
852
+ })
853
+
854
+ describe('timeout', () => {
855
+ it('has a default timeout value', async () => {
856
+ const [analytics] = await HtEventsBrowser.load({
857
+ writeKey,
858
+ })
859
+ //@ts-ignore
860
+ expect(analytics.settings.timeout).toEqual(300)
861
+ })
862
+
863
+ it('can set a timeout value', async () => {
864
+ const [analytics] = await HtEventsBrowser.load({
865
+ writeKey,
866
+ })
867
+ analytics.timeout(50)
868
+ //@ts-ignore
869
+ expect(analytics.settings.timeout).toEqual(50)
870
+ })
871
+ })
872
+
873
+ // We do not support remote integrations
874
+ describe.skip('deregister', () => {
875
+ beforeEach(async () => {
876
+ jest.restoreAllMocks()
877
+ jest.resetAllMocks()
878
+
879
+ const html = `
880
+ <!DOCTYPE html>
881
+ <head>
882
+ <script>'hi'</script>
883
+ </head>
884
+ <body>
885
+ </body>
886
+ </html>
887
+ `.trim()
888
+
889
+ const jsd = new JSDOM(html, {
890
+ runScripts: 'dangerously',
891
+ resources: 'usable',
892
+ url: 'https://localhost',
893
+ })
894
+
895
+ const windowSpy = jest.spyOn(global, 'window', 'get')
896
+ windowSpy.mockImplementation(
897
+ () => jsd.window as unknown as Window & typeof globalThis
898
+ )
899
+ })
900
+
901
+ it('deregisters a plugin given its name', async () => {
902
+ const unload = jest.fn((): Promise<unknown> => {
903
+ return Promise.resolve()
904
+ })
905
+ xt.unload = unload
906
+
907
+ const [analytics] = await HtEventsBrowser.load({
908
+ writeKey,
909
+ plugins: [xt],
910
+ })
911
+
912
+ await analytics.deregister('Test Plugin')
913
+ expect(xt.unload).toHaveBeenCalled()
914
+ })
915
+
916
+ it('cleans up the DOM when deregistering a legacy integration', async () => {
917
+ const amplitude = new LegacyDestination(
918
+ 'amplitude',
919
+ 'latest',
920
+ writeKey,
921
+ {
922
+ apiKey: amplitudeWriteKey,
923
+ },
924
+ {}
925
+ )
926
+
927
+ const [analytics] = await HtEventsBrowser.load({
928
+ writeKey,
929
+ plugins: [amplitude],
930
+ })
931
+
932
+ await analytics.ready()
933
+
934
+ const scriptsLength = window.document.scripts.length
935
+ expect(scriptsLength).toBeGreaterThan(1)
936
+
937
+ await analytics.deregister('amplitude')
938
+ expect(window.document.scripts.length).toBe(scriptsLength - 1)
939
+ })
940
+ })
941
+
942
+ describe('retries', () => {
943
+ const testPlugin: Plugin = {
944
+ name: 'test',
945
+ type: 'before',
946
+ version: '0.1.0',
947
+ load: () => Promise.resolve(),
948
+ isLoaded: () => true,
949
+ }
950
+
951
+ const fruitBasketEvent = new Context({
952
+ type: 'track',
953
+ event: 'Fruit Basket',
954
+ })
955
+
956
+ beforeEach(async () => {
957
+ // @ts-ignore ignore reassining function
958
+ loadLegacySettings = jest.fn().mockReturnValue(
959
+ Promise.resolve({
960
+ integrations: { 'Hightouch.io': { retryQueue: false } },
961
+ })
962
+ )
963
+ })
964
+
965
+ it('does not retry errored events if retryQueue setting is set to false', async () => {
966
+ const [ajs] = await HtEventsBrowser.load(
967
+ { writeKey: writeKey },
968
+ { retryQueue: false }
969
+ )
970
+
971
+ expect(ajs.queue.queue instanceof PersistedPriorityQueue).toBeTruthy()
972
+ expect(ajs.queue.queue.maxAttempts).toBe(1)
973
+
974
+ await ajs.queue.register(
975
+ Context.system(),
976
+ {
977
+ ...testPlugin,
978
+ track: (_ctx) => {
979
+ throw new Error('aaay')
980
+ },
981
+ },
982
+ ajs
983
+ )
984
+
985
+ // Dispatching an event will push it into the priority queue.
986
+ await ajs.queue.dispatch(fruitBasketEvent).catch(() => {})
987
+
988
+ // we make sure the queue is flushed and there are no events queued up.
989
+ expect(ajs.queue.queue.length).toBe(0)
990
+ const flushed = await ajs.queue.flush()
991
+ expect(flushed).toStrictEqual([])
992
+
993
+ // as maxAttempts === 1, only one attempt was made.
994
+ // getAttempts(fruitBasketEvent) === 2 means the event's attemp was incremented,
995
+ // but the condition "(getAttempts(event) > maxAttempts) { return false }"
996
+ // aborted the retry
997
+ expect(ajs.queue.queue.getAttempts(fruitBasketEvent)).toEqual(2)
998
+ })
999
+
1000
+ it('does not queue events / dispatch when offline if retryQueue setting is set to false', async () => {
1001
+ const [ajs] = await HtEventsBrowser.load(
1002
+ { writeKey },
1003
+ { retryQueue: false }
1004
+ )
1005
+
1006
+ const trackSpy = jest.fn().mockImplementation((ctx) => ctx)
1007
+ await ajs.queue.register(
1008
+ Context.system(),
1009
+ {
1010
+ ...testPlugin,
1011
+ ready: () => Promise.resolve(true),
1012
+ track: trackSpy,
1013
+ },
1014
+ ajs
1015
+ )
1016
+
1017
+ // @ts-ignore ignore reassining function
1018
+ isOffline = jest.fn().mockReturnValue(true)
1019
+
1020
+ await ajs.track('event')
1021
+
1022
+ expect(trackSpy).toBeCalledTimes(0)
1023
+ })
1024
+
1025
+ it('enqueues events / dispatches if the client is currently offline and retries are *enabled* for the main event queue', async () => {
1026
+ const [ajs] = await HtEventsBrowser.load({ writeKey }, { retryQueue: true })
1027
+
1028
+ const trackSpy = jest.fn().mockImplementation((ctx) => ctx)
1029
+ await ajs.queue.register(
1030
+ Context.system(),
1031
+ {
1032
+ ...testPlugin,
1033
+ ready: () => Promise.resolve(true),
1034
+ track: trackSpy,
1035
+ },
1036
+ ajs
1037
+ )
1038
+
1039
+ // @ts-ignore ignore reassining function
1040
+ isOffline = jest.fn().mockReturnValue(true)
1041
+
1042
+ expect(trackSpy).toBeCalledTimes(0)
1043
+
1044
+ await ajs.track('event')
1045
+
1046
+ expect(trackSpy).toBeCalledTimes(1)
1047
+ })
1048
+ })
1049
+
1050
+ describe('Hightouch.io overrides', () => {
1051
+ it('allows for overriding Hightouch.io settings', async () => {
1052
+ jest.spyOn(HightouchPlugin, 'hightouchio')
1053
+
1054
+ await HtEventsBrowser.load(
1055
+ { writeKey },
1056
+ {
1057
+ integrations: {
1058
+ 'Hightouch.io': {
1059
+ apiHost: 'https://my.endpoint.com',
1060
+ anotherSettings: '👻',
1061
+ },
1062
+ },
1063
+ }
1064
+ )
1065
+
1066
+ expect(HightouchPlugin.hightouchio).toHaveBeenCalledWith(
1067
+ expect.anything(),
1068
+ expect.objectContaining({
1069
+ apiHost: 'https://my.endpoint.com',
1070
+ anotherSettings: '👻',
1071
+ }),
1072
+ expect.anything()
1073
+ )
1074
+ })
1075
+ })
1076
+
1077
+ // We do not support remote integrations
1078
+ describe.skip('Options', () => {
1079
+ beforeEach(async () => {
1080
+ jest.restoreAllMocks()
1081
+ jest.resetAllMocks()
1082
+
1083
+ const html = `
1084
+ <!DOCTYPE html>
1085
+ <head>
1086
+ <script>'hi'</script>
1087
+ </head>
1088
+ <body>
1089
+ </body>
1090
+ </html>
1091
+ `.trim()
1092
+
1093
+ const jsd = new JSDOM(html, {
1094
+ runScripts: 'dangerously',
1095
+ resources: 'usable',
1096
+ url: 'https://localhost',
1097
+ })
1098
+
1099
+ const windowSpy = jest.spyOn(global, 'window', 'get')
1100
+ windowSpy.mockImplementation(
1101
+ () => jsd.window as unknown as Window & typeof globalThis
1102
+ )
1103
+ })
1104
+
1105
+ describe('disableAutoISOConversion', () => {
1106
+ it('converts iso strings to dates be default', async () => {
1107
+ const [analytics] = await HtEventsBrowser.load({
1108
+ writeKey,
1109
+ })
1110
+
1111
+ const amplitude = new LegacyDestination(
1112
+ 'amplitude',
1113
+ 'latest',
1114
+ writeKey,
1115
+ {
1116
+ apiKey: amplitudeWriteKey,
1117
+ },
1118
+ {}
1119
+ )
1120
+
1121
+ await analytics.register(amplitude)
1122
+ await amplitude.ready()
1123
+
1124
+ const integrationMock = jest.spyOn(amplitude.integration!, 'track')
1125
+ await analytics.track('Hello!', {
1126
+ date: new Date(),
1127
+ iso: '2020-10-10',
1128
+ })
1129
+
1130
+ const [integrationEvent] = integrationMock.mock.lastCall
1131
+
1132
+ expect(integrationEvent.properties()).toEqual({
1133
+ date: expect.any(Date),
1134
+ iso: expect.any(Date),
1135
+ })
1136
+ expect(integrationEvent.timestamp()).toBeInstanceOf(Date)
1137
+ })
1138
+
1139
+ it('does not convert iso strings to dates be default if disableAutoISOConversion is false', async () => {
1140
+ const initOptions: InitOptions = { disableAutoISOConversion: false }
1141
+ const [analytics] = await HtEventsBrowser.load(
1142
+ {
1143
+ writeKey,
1144
+ },
1145
+ initOptions
1146
+ )
1147
+
1148
+ const amplitude = new LegacyDestination(
1149
+ 'amplitude',
1150
+ 'latest',
1151
+ writeKey,
1152
+ {
1153
+ apiKey: amplitudeWriteKey,
1154
+ },
1155
+ initOptions
1156
+ )
1157
+
1158
+ await analytics.register(amplitude)
1159
+ await amplitude.ready()
1160
+
1161
+ const integrationMock = jest.spyOn(amplitude.integration!, 'track')
1162
+ await analytics.track('Hello!', {
1163
+ date: new Date(),
1164
+ iso: '2020-10-10',
1165
+ })
1166
+
1167
+ const [integrationEvent] = integrationMock.mock.lastCall
1168
+
1169
+ expect(integrationEvent.properties()).toEqual({
1170
+ date: expect.any(Date),
1171
+ iso: expect.any(Date),
1172
+ })
1173
+ expect(integrationEvent.timestamp()).toBeInstanceOf(Date)
1174
+ })
1175
+
1176
+ it('does not convert iso strings to dates when `true`', async () => {
1177
+ const initOptions: InitOptions = { disableAutoISOConversion: true }
1178
+ const [analytics] = await HtEventsBrowser.load(
1179
+ {
1180
+ writeKey,
1181
+ },
1182
+ initOptions
1183
+ )
1184
+
1185
+ const amplitude = new LegacyDestination(
1186
+ 'amplitude',
1187
+ 'latest',
1188
+ writeKey,
1189
+ {
1190
+ apiKey: amplitudeWriteKey,
1191
+ },
1192
+ initOptions
1193
+ )
1194
+
1195
+ await analytics.register(amplitude)
1196
+ await amplitude.ready()
1197
+
1198
+ const integrationMock = jest.spyOn(amplitude.integration!, 'track')
1199
+ await analytics.track('Hello!', {
1200
+ date: new Date(),
1201
+ iso: '2020-10-10',
1202
+ })
1203
+
1204
+ const [integrationEvent] = integrationMock.mock.lastCall
1205
+
1206
+ expect(integrationEvent.properties()).toEqual({
1207
+ date: expect.any(Date),
1208
+ iso: '2020-10-10',
1209
+ })
1210
+ expect(integrationEvent.timestamp()).toBeInstanceOf(Date)
1211
+ })
1212
+ })
1213
+ })