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.
- package/.editorconfig +10 -0
- package/.eslintrc.isomorphic.js +26 -0
- package/.eslintrc.js +86 -0
- package/.gitattributes +1 -0
- package/.github/workflows/ci.yml +33 -0
- package/.github/workflows/deploy-browser-cdn-candidate.yml +51 -0
- package/.github/workflows/deploy-releases.yml +178 -0
- package/.nvmrc +1 -0
- package/.prettierrc +7 -0
- package/.vscode/extensions.json +3 -0
- package/.vscode/launch.json +81 -0
- package/.vscode/settings.json +41 -0
- package/.yarn/plugins/@yarnpkg/plugin-constraints.cjs +52 -0
- package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +546 -0
- package/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +9 -0
- package/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +28 -0
- package/.yarn/releases/yarn-3.4.1.cjs +873 -0
- package/.yarnrc.yml +15 -0
- package/jest.config.js +18 -0
- package/package.json +59 -0
- package/packages/browser/.eslintrc.js +9 -0
- package/packages/browser/.lintstagedrc.js +1 -0
- package/packages/browser/ARCHITECTURE.md +48 -0
- package/packages/browser/LICENSE.MD +45 -0
- package/packages/browser/Makefile +64 -0
- package/packages/browser/README.md +227 -0
- package/packages/browser/e2e-tests/local-server.ts +28 -0
- package/packages/browser/e2e-tests/performance/ajs-perf-browser.test.ts +75 -0
- package/packages/browser/jest.config.js +15 -0
- package/packages/browser/jest.setup.js +10 -0
- package/packages/browser/package.json +106 -0
- package/packages/browser/qa/README.md +41 -0
- package/packages/browser/qa/__fixtures__/snippets.ts +148 -0
- package/packages/browser/qa/__tests__/backwards-compatibility.test.ts +180 -0
- package/packages/browser/qa/__tests__/destinations.test.ts +101 -0
- package/packages/browser/qa/__tests__/smoke.test.ts +170 -0
- package/packages/browser/qa/lib/benchmark.ts +36 -0
- package/packages/browser/qa/lib/browser.ts +28 -0
- package/packages/browser/qa/lib/jest-reporter.js +57 -0
- package/packages/browser/qa/lib/runner.ts +142 -0
- package/packages/browser/qa/lib/schema.ts +59 -0
- package/packages/browser/qa/lib/server.ts +54 -0
- package/packages/browser/qa/lib/stats.ts +52 -0
- package/packages/browser/scripts/build-prep.sh +7 -0
- package/packages/browser/scripts/ci.sh +15 -0
- package/packages/browser/scripts/release.js +121 -0
- package/packages/browser/scripts/release.sh +9 -0
- package/packages/browser/scripts/run.sh +8 -0
- package/packages/browser/src/browser/__tests__/analytics-lazy-init.integration.test.ts +51 -0
- package/packages/browser/src/browser/__tests__/analytics-pre-init.integration.test.ts +440 -0
- package/packages/browser/src/browser/__tests__/anon-id-and-reset.integration.test.ts +73 -0
- package/packages/browser/src/browser/__tests__/cdn.test.ts +53 -0
- package/packages/browser/src/browser/__tests__/csp-detection.test.ts +140 -0
- package/packages/browser/src/browser/__tests__/inspector.integration.test.ts +121 -0
- package/packages/browser/src/browser/__tests__/integration.test.ts +1213 -0
- package/packages/browser/src/browser/__tests__/integrations.integration.test.ts +260 -0
- package/packages/browser/src/browser/__tests__/page-enrichment.integration.test.ts +216 -0
- package/packages/browser/src/browser/__tests__/query-string.integration.test.ts +116 -0
- package/packages/browser/src/browser/__tests__/standalone-analytics.test.ts +303 -0
- package/packages/browser/src/browser/__tests__/standalone-errors.test.ts +136 -0
- package/packages/browser/src/browser/__tests__/standalone.test.ts +97 -0
- package/packages/browser/src/browser/__tests__/typedef-tests/analytics-browser.ts +150 -0
- package/packages/browser/src/browser/__tests__/update-cdn-settings.test.ts +71 -0
- package/packages/browser/src/browser/browser-umd.ts +19 -0
- package/packages/browser/src/browser/index.ts +486 -0
- package/packages/browser/src/browser/standalone-analytics.ts +62 -0
- package/packages/browser/src/browser/standalone-interface.ts +11 -0
- package/packages/browser/src/browser/standalone.ts +92 -0
- package/packages/browser/src/core/__tests__/track-form.test.ts +193 -0
- package/packages/browser/src/core/__tests__/track-link.test.ts +252 -0
- package/packages/browser/src/core/analytics/__tests__/integration.test.ts +334 -0
- package/packages/browser/src/core/analytics/__tests__/test-plugins.ts +94 -0
- package/packages/browser/src/core/analytics/index.ts +672 -0
- package/packages/browser/src/core/analytics/interfaces.ts +100 -0
- package/packages/browser/src/core/arguments-resolver/__tests__/index.test.ts +524 -0
- package/packages/browser/src/core/arguments-resolver/index.ts +200 -0
- package/packages/browser/src/core/auto-track.ts +152 -0
- package/packages/browser/src/core/buffer/__tests__/index.test.ts +455 -0
- package/packages/browser/src/core/buffer/index.ts +371 -0
- package/packages/browser/src/core/callback/index.ts +1 -0
- package/packages/browser/src/core/connection/__tests__/index.test.ts +25 -0
- package/packages/browser/src/core/connection/index.ts +13 -0
- package/packages/browser/src/core/constants/index.ts +1 -0
- package/packages/browser/src/core/context/__tests__/index.test.ts +201 -0
- package/packages/browser/src/core/context/index.ts +21 -0
- package/packages/browser/src/core/environment/index.ts +7 -0
- package/packages/browser/src/core/events/__tests__/index.test.ts +450 -0
- package/packages/browser/src/core/events/index.ts +280 -0
- package/packages/browser/src/core/events/interfaces.ts +36 -0
- package/packages/browser/src/core/inspector/index.ts +14 -0
- package/packages/browser/src/core/page/__tests__/index.test.ts +130 -0
- package/packages/browser/src/core/page/add-page-context.ts +33 -0
- package/packages/browser/src/core/page/get-page-context.ts +140 -0
- package/packages/browser/src/core/page/index.ts +2 -0
- package/packages/browser/src/core/plugin/index.ts +12 -0
- package/packages/browser/src/core/query-string/__tests__/gracefulDecodeURIComponent.test.ts +17 -0
- package/packages/browser/src/core/query-string/__tests__/index.test.ts +149 -0
- package/packages/browser/src/core/query-string/__tests__/pickPrefix.test.ts +31 -0
- package/packages/browser/src/core/query-string/__tests__/useQueryString.test.ts +60 -0
- package/packages/browser/src/core/query-string/gracefulDecodeURIComponent.ts +16 -0
- package/packages/browser/src/core/query-string/index.ts +64 -0
- package/packages/browser/src/core/query-string/pickPrefix.ts +20 -0
- package/packages/browser/src/core/queue/__tests__/event-queue.test.ts +82 -0
- package/packages/browser/src/core/queue/event-queue.ts +22 -0
- package/packages/browser/src/core/session/__tests__/index.test.ts +41 -0
- package/packages/browser/src/core/session/index.ts +107 -0
- package/packages/browser/src/core/stats/__tests__/index.test.ts +15 -0
- package/packages/browser/src/core/stats/__tests__/remote-metrics.test.ts +189 -0
- package/packages/browser/src/core/stats/index.ts +15 -0
- package/packages/browser/src/core/stats/remote-metrics.ts +144 -0
- package/packages/browser/src/core/storage/__tests__/cookieStorage.test.ts +58 -0
- package/packages/browser/src/core/storage/__tests__/localStorage.test.ts +70 -0
- package/packages/browser/src/core/storage/__tests__/test-helpers.ts +26 -0
- package/packages/browser/src/core/storage/__tests__/universalStorage.test.ts +167 -0
- package/packages/browser/src/core/storage/cookieStorage.ts +80 -0
- package/packages/browser/src/core/storage/index.ts +64 -0
- package/packages/browser/src/core/storage/localStorage.ts +45 -0
- package/packages/browser/src/core/storage/memoryStorage.ts +22 -0
- package/packages/browser/src/core/storage/settings.ts +23 -0
- package/packages/browser/src/core/storage/types.ts +49 -0
- package/packages/browser/src/core/storage/universalStorage.ts +78 -0
- package/packages/browser/src/core/user/__tests__/index.test.ts +922 -0
- package/packages/browser/src/core/user/__tests__/migrate.test.ts +101 -0
- package/packages/browser/src/core/user/__tests__/session.test.ts +136 -0
- package/packages/browser/src/core/user/__tests__/tld.test.ts +36 -0
- package/packages/browser/src/core/user/index.ts +399 -0
- package/packages/browser/src/core/user/migrate.ts +126 -0
- package/packages/browser/src/core/user/tld.ts +65 -0
- package/packages/browser/src/core/user/vendor/crypto-es/LICENSE +53 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/aes.ts +302 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/cipher-core.ts +922 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/core.ts +806 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/enc-base64.ts +110 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/evpkdf.ts +110 -0
- package/packages/browser/src/core/user/vendor/crypto-es/lib/md5.ts +238 -0
- package/packages/browser/src/core/user/vendor/readme.md +7 -0
- package/packages/browser/src/generated/__tests__/version.test.ts +18 -0
- package/packages/browser/src/generated/version.ts +2 -0
- package/packages/browser/src/index.ts +13 -0
- package/packages/browser/src/lib/__tests__/embedded-write-key.test.ts +15 -0
- package/packages/browser/src/lib/__tests__/fetch.test.ts +35 -0
- package/packages/browser/src/lib/__tests__/get-process-env.test.ts +5 -0
- package/packages/browser/src/lib/__tests__/group-by.test.ts +96 -0
- package/packages/browser/src/lib/__tests__/is-plan-event-enabled.test.ts +36 -0
- package/packages/browser/src/lib/__tests__/is-thenable.test.ts +39 -0
- package/packages/browser/src/lib/__tests__/merged-options.test.ts +123 -0
- package/packages/browser/src/lib/__tests__/on-page-change.test.ts +74 -0
- package/packages/browser/src/lib/__tests__/parse-cdn.test.ts +88 -0
- package/packages/browser/src/lib/__tests__/pick.test.ts +34 -0
- package/packages/browser/src/lib/__tests__/pick.typedef.ts +39 -0
- package/packages/browser/src/lib/bind-all.ts +19 -0
- package/packages/browser/src/lib/browser-polyfill.ts +23 -0
- package/packages/browser/src/lib/client-hints/__tests__/index.test.ts +66 -0
- package/packages/browser/src/lib/client-hints/index.ts +16 -0
- package/packages/browser/src/lib/client-hints/interfaces.ts +42 -0
- package/packages/browser/src/lib/create-deferred.ts +16 -0
- package/packages/browser/src/lib/csp-detection.ts +8 -0
- package/packages/browser/src/lib/embedded-write-key.ts +24 -0
- package/packages/browser/src/lib/fetch.ts +10 -0
- package/packages/browser/src/lib/get-global.ts +16 -0
- package/packages/browser/src/lib/get-process-env.ts +11 -0
- package/packages/browser/src/lib/global-analytics-helper.ts +31 -0
- package/packages/browser/src/lib/group-by.ts +30 -0
- package/packages/browser/src/lib/is-plan-event-enabled.ts +20 -0
- package/packages/browser/src/lib/is-thenable.ts +9 -0
- package/packages/browser/src/lib/load-script.ts +66 -0
- package/packages/browser/src/lib/merged-options.ts +46 -0
- package/packages/browser/src/lib/on-page-change.ts +29 -0
- package/packages/browser/src/lib/p-while.ts +12 -0
- package/packages/browser/src/lib/parse-cdn.ts +56 -0
- package/packages/browser/src/lib/pick.ts +28 -0
- package/packages/browser/src/lib/priority-queue/__tests__/backoff.test.ts +23 -0
- package/packages/browser/src/lib/priority-queue/__tests__/index.test.ts +158 -0
- package/packages/browser/src/lib/priority-queue/__tests__/persisted.test.ts +228 -0
- package/packages/browser/src/lib/priority-queue/backoff.ts +24 -0
- package/packages/browser/src/lib/priority-queue/index.ts +6 -0
- package/packages/browser/src/lib/priority-queue/persisted.ts +127 -0
- package/packages/browser/src/lib/sleep.ts +4 -0
- package/packages/browser/src/lib/to-facade.ts +53 -0
- package/packages/browser/src/lib/version-type.ts +10 -0
- package/packages/browser/src/node/__tests__/node-integration.test.ts +19 -0
- package/packages/browser/src/node/index.ts +36 -0
- package/packages/browser/src/node/node.browser.ts +7 -0
- package/packages/browser/src/plugins/ajs-destination/__tests__/index.test.ts +834 -0
- package/packages/browser/src/plugins/ajs-destination/index.ts +392 -0
- package/packages/browser/src/plugins/ajs-destination/loader.ts +129 -0
- package/packages/browser/src/plugins/ajs-destination/types.ts +44 -0
- package/packages/browser/src/plugins/ajs-destination/utils.ts +32 -0
- package/packages/browser/src/plugins/analytics-node/__tests__/index.test.ts +69 -0
- package/packages/browser/src/plugins/analytics-node/index.ts +67 -0
- package/packages/browser/src/plugins/env-enrichment/__tests__/index.test.ts +421 -0
- package/packages/browser/src/plugins/env-enrichment/index.ts +208 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/batched-dispatcher.test.ts +299 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/index.test.ts +317 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/normalize.test.ts +181 -0
- package/packages/browser/src/plugins/hightouchio/__tests__/retries.test.ts +82 -0
- package/packages/browser/src/plugins/hightouchio/batched-dispatcher.ts +127 -0
- package/packages/browser/src/plugins/hightouchio/fetch-dispatcher.ts +27 -0
- package/packages/browser/src/plugins/hightouchio/index.ts +147 -0
- package/packages/browser/src/plugins/hightouchio/normalize.ts +71 -0
- package/packages/browser/src/plugins/hightouchio/schedule-flush.ts +58 -0
- package/packages/browser/src/plugins/legacy-video-plugins/__tests__/index.test.ts +48 -0
- package/packages/browser/src/plugins/legacy-video-plugins/index.ts +16 -0
- package/packages/browser/src/plugins/middleware/__tests__/index.test.ts +268 -0
- package/packages/browser/src/plugins/middleware/index.ts +131 -0
- package/packages/browser/src/plugins/remote-loader/__tests__/index.test.ts +943 -0
- package/packages/browser/src/plugins/remote-loader/index.ts +256 -0
- package/packages/browser/src/plugins/remote-middleware/__tests__/index.test.ts +116 -0
- package/packages/browser/src/plugins/remote-middleware/index.ts +44 -0
- package/packages/browser/src/plugins/routing-middleware/__tests__/index.test.ts +64 -0
- package/packages/browser/src/plugins/routing-middleware/index.ts +37 -0
- package/packages/browser/src/plugins/schema-filter/__tests__/index.test.ts +520 -0
- package/packages/browser/src/plugins/schema-filter/index.ts +90 -0
- package/packages/browser/src/plugins/validation/__tests__/index.test.ts +78 -0
- package/packages/browser/src/plugins/validation/index.ts +44 -0
- package/packages/browser/src/test-helpers/browser-storage.ts +75 -0
- package/packages/browser/src/test-helpers/factories.ts +18 -0
- package/packages/browser/src/test-helpers/fetch-parse.ts +8 -0
- package/packages/browser/src/test-helpers/fixtures/cdn-settings.ts +301 -0
- package/packages/browser/src/test-helpers/fixtures/classic-destination.ts +25 -0
- package/packages/browser/src/test-helpers/fixtures/client-hints.ts +28 -0
- package/packages/browser/src/test-helpers/fixtures/create-fetch-method.ts +30 -0
- package/packages/browser/src/test-helpers/fixtures/index.ts +4 -0
- package/packages/browser/src/test-helpers/fixtures/page-context.ts +11 -0
- package/packages/browser/src/test-helpers/test-writekeys.ts +5 -0
- package/packages/browser/src/test-helpers/type-assertions.ts +11 -0
- package/packages/browser/src/tester/__fixtures__/hightouch-snippet.ts +64 -0
- package/packages/browser/src/tester/__fixtures__/index.html +8 -0
- package/packages/browser/src/tester/ajs-perf.ts +30 -0
- package/packages/browser/src/tester/ajs-tester.ts +119 -0
- package/packages/browser/src/tester/server.js +16 -0
- package/packages/browser/tsconfig.build.json +9 -0
- package/packages/browser/tsconfig.json +13 -0
- package/packages/browser/webpack.config.js +106 -0
- package/packages/config/package.json +10 -0
- package/packages/config/src/index.js +4 -0
- package/packages/config/src/jest/config.js +50 -0
- package/packages/config/src/jest/get-module-map.js +34 -0
- package/packages/config/src/lint-staged/config.js +4 -0
- package/packages/config-webpack/package.json +20 -0
- package/packages/config-webpack/webpack.config.common.js +75 -0
- package/packages/consent/consent-tools/.eslintrc.js +7 -0
- package/packages/consent/consent-tools/.lintstagedrc.js +1 -0
- package/packages/consent/consent-tools/LICENSE +45 -0
- package/packages/consent/consent-tools/README.md +104 -0
- package/packages/consent/consent-tools/jest.config.js +6 -0
- package/packages/consent/consent-tools/jest.setup.js +4 -0
- package/packages/consent/consent-tools/package.json +48 -0
- package/packages/consent/consent-tools/src/domain/__tests__/assertions/integrations-assertions.ts +37 -0
- package/packages/consent/consent-tools/src/domain/__tests__/consent-stamping.test.ts +45 -0
- package/packages/consent/consent-tools/src/domain/__tests__/create-wrapper.test.ts +816 -0
- package/packages/consent/consent-tools/src/domain/__tests__/typedef-tests.ts +21 -0
- package/packages/consent/consent-tools/src/domain/consent-changed.ts +51 -0
- package/packages/consent/consent-tools/src/domain/consent-stamping.ts +19 -0
- package/packages/consent/consent-tools/src/domain/create-wrapper.ts +238 -0
- package/packages/consent/consent-tools/src/domain/get-initialized-analytics.ts +25 -0
- package/packages/consent/consent-tools/src/domain/load-cancellation.ts +31 -0
- package/packages/consent/consent-tools/src/domain/validation/__tests__/options-validators.test.ts +77 -0
- package/packages/consent/consent-tools/src/domain/validation/__tests__/validation-error.test.ts +15 -0
- package/packages/consent/consent-tools/src/domain/validation/common-validators.ts +19 -0
- package/packages/consent/consent-tools/src/domain/validation/index.ts +1 -0
- package/packages/consent/consent-tools/src/domain/validation/options-validators.ts +74 -0
- package/packages/consent/consent-tools/src/domain/validation/validation-error.ts +11 -0
- package/packages/consent/consent-tools/src/index.ts +16 -0
- package/packages/consent/consent-tools/src/types/errors.ts +14 -0
- package/packages/consent/consent-tools/src/types/index.ts +3 -0
- package/packages/consent/consent-tools/src/types/settings.ts +121 -0
- package/packages/consent/consent-tools/src/types/wrapper.ts +107 -0
- package/packages/consent/consent-tools/src/utils/index.ts +4 -0
- package/packages/consent/consent-tools/src/utils/pick.ts +18 -0
- package/packages/consent/consent-tools/src/utils/pipe.ts +14 -0
- package/packages/consent/consent-tools/src/utils/resolve-when.ts +32 -0
- package/packages/consent/consent-tools/src/utils/uniq.ts +4 -0
- package/packages/consent/consent-tools/tsconfig.build.json +9 -0
- package/packages/consent/consent-tools/tsconfig.json +12 -0
- package/packages/consent/consent-wrapper-onetrust/.eslintrc.js +7 -0
- package/packages/consent/consent-wrapper-onetrust/.lintstagedrc.js +1 -0
- package/packages/consent/consent-wrapper-onetrust/LICENSE +45 -0
- package/packages/consent/consent-wrapper-onetrust/README.md +125 -0
- package/packages/consent/consent-wrapper-onetrust/img/onetrust-cat-id.jpg +0 -0
- package/packages/consent/consent-wrapper-onetrust/img/onetrust-popup.jpg +0 -0
- package/packages/consent/consent-wrapper-onetrust/jest.config.js +6 -0
- package/packages/consent/consent-wrapper-onetrust/jest.setup.js +4 -0
- package/packages/consent/consent-wrapper-onetrust/package.json +60 -0
- package/packages/consent/consent-wrapper-onetrust/src/domain/__tests__/wrapper.test.ts +151 -0
- package/packages/consent/consent-wrapper-onetrust/src/domain/wrapper.ts +61 -0
- package/packages/consent/consent-wrapper-onetrust/src/index.ts +6 -0
- package/packages/consent/consent-wrapper-onetrust/src/index.umd.ts +11 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/__tests__/onetrust-api.test.ts +181 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/onetrust-api.ts +155 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/validation/index.ts +1 -0
- package/packages/consent/consent-wrapper-onetrust/src/lib/validation/onetrust-api-error.ts +11 -0
- package/packages/consent/consent-wrapper-onetrust/src/test-helpers/mocks.ts +23 -0
- package/packages/consent/consent-wrapper-onetrust/src/test-helpers/onetrust-globals.d.ts +11 -0
- package/packages/consent/consent-wrapper-onetrust/src/test-helpers/utils.ts +3 -0
- package/packages/consent/consent-wrapper-onetrust/tsconfig.build.json +9 -0
- package/packages/consent/consent-wrapper-onetrust/tsconfig.json +11 -0
- package/packages/consent/consent-wrapper-onetrust/webpack.config.js +25 -0
- package/packages/core/.eslintrc.js +4 -0
- package/packages/core/.lintstagedrc.js +1 -0
- package/packages/core/LICENSE.MD +45 -0
- package/packages/core/README.md +3 -0
- package/packages/core/jest.config.js +5 -0
- package/packages/core/jest.setup.js +10 -0
- package/packages/core/package.json +40 -0
- package/packages/core/src/analytics/__tests__/dispatch.test.ts +95 -0
- package/packages/core/src/analytics/dispatch.ts +58 -0
- package/packages/core/src/analytics/index.ts +11 -0
- package/packages/core/src/callback/__tests__/index.test.ts +85 -0
- package/packages/core/src/callback/index.ts +51 -0
- package/packages/core/src/context/index.ts +123 -0
- package/packages/core/src/emitter/__tests__/emitter.test.ts +74 -0
- package/packages/core/src/emitter/index.ts +65 -0
- package/packages/core/src/emitter/interface.ts +31 -0
- package/packages/core/src/events/__tests__/index.test.ts +394 -0
- package/packages/core/src/events/index.ts +280 -0
- package/packages/core/src/events/interfaces.ts +475 -0
- package/packages/core/src/index.ts +19 -0
- package/packages/core/src/logger/__tests__/index.test.ts +66 -0
- package/packages/core/src/logger/index.ts +74 -0
- package/packages/core/src/plugins/index.ts +43 -0
- package/packages/core/src/priority-queue/__tests__/backoff.test.ts +23 -0
- package/packages/core/src/priority-queue/__tests__/index.test.ts +158 -0
- package/packages/core/src/priority-queue/backoff.ts +24 -0
- package/packages/core/src/priority-queue/index.ts +103 -0
- package/packages/core/src/queue/__tests__/event-queue.test.ts +678 -0
- package/packages/core/src/queue/__tests__/extension-flushing.test.ts +416 -0
- package/packages/core/src/queue/delivery.ts +73 -0
- package/packages/core/src/queue/event-queue.ts +318 -0
- package/packages/core/src/stats/__tests__/index.test.ts +103 -0
- package/packages/core/src/stats/index.ts +88 -0
- package/packages/core/src/task/__tests__/task-group.test.ts +26 -0
- package/packages/core/src/task/task-group.ts +31 -0
- package/packages/core/src/user/index.ts +7 -0
- package/packages/core/src/utils/__tests__/group-by.test.ts +96 -0
- package/packages/core/src/utils/__tests__/is-plain-object.test.ts +27 -0
- package/packages/core/src/utils/__tests__/is-thenable.test.ts +39 -0
- package/packages/core/src/utils/bind-all.ts +19 -0
- package/packages/core/src/utils/get-global.ts +17 -0
- package/packages/core/src/utils/group-by.ts +30 -0
- package/packages/core/src/utils/has-properties.ts +7 -0
- package/packages/core/src/utils/is-plain-object.ts +26 -0
- package/packages/core/src/utils/is-thenable.ts +9 -0
- package/packages/core/src/utils/p-while.ts +12 -0
- package/packages/core/src/utils/pick.ts +8 -0
- package/packages/core/src/utils/ts-helpers.ts +13 -0
- package/packages/core/src/validation/__tests__/assertions.test.ts +155 -0
- package/packages/core/src/validation/assertions.ts +72 -0
- package/packages/core/src/validation/errors.ts +8 -0
- package/packages/core/src/validation/helpers.ts +23 -0
- package/packages/core/test-helpers/index.ts +2 -0
- package/packages/core/test-helpers/test-ctx.ts +7 -0
- package/packages/core/test-helpers/test-event-queue.ts +7 -0
- package/packages/core/tsconfig.build.json +9 -0
- package/packages/core/tsconfig.json +11 -0
- package/packages/node/.eslintrc.js +7 -0
- package/packages/node/.lintstagedrc.js +1 -0
- package/packages/node/LICENSE +45 -0
- package/packages/node/README.md +138 -0
- package/packages/node/jest.config.js +5 -0
- package/packages/node/jest.setup.js +4 -0
- package/packages/node/package.json +50 -0
- package/packages/node/scripts/version.sh +11 -0
- package/packages/node/src/__tests__/callback.test.ts +47 -0
- package/packages/node/src/__tests__/disable.integration.test.ts +42 -0
- package/packages/node/src/__tests__/emitter.integration.test.ts +45 -0
- package/packages/node/src/__tests__/graceful-shutdown-integration.test.ts +244 -0
- package/packages/node/src/__tests__/http-client.integration.test.ts +69 -0
- package/packages/node/src/__tests__/http-integration.test.ts +362 -0
- package/packages/node/src/__tests__/integration.test.ts +357 -0
- package/packages/node/src/__tests__/plugins.test.ts +16 -0
- package/packages/node/src/__tests__/settings.test.ts +9 -0
- package/packages/node/src/__tests__/test-helpers/assert-shape/http-request-event.ts +13 -0
- package/packages/node/src/__tests__/test-helpers/assert-shape/index.ts +2 -0
- package/packages/node/src/__tests__/test-helpers/assert-shape/segment-http-api.ts +43 -0
- package/packages/node/src/__tests__/test-helpers/create-test-analytics.ts +42 -0
- package/packages/node/src/__tests__/test-helpers/factories.ts +17 -0
- package/packages/node/src/__tests__/test-helpers/is-valid-date.ts +6 -0
- package/packages/node/src/__tests__/test-helpers/resolve-ctx.ts +19 -0
- package/packages/node/src/__tests__/test-helpers/resolve-emitter.ts +11 -0
- package/packages/node/src/__tests__/test-helpers/sleep.ts +3 -0
- package/packages/node/src/__tests__/test-helpers/test-plugin.ts +16 -0
- package/packages/node/src/__tests__/typedef-tests.ts +120 -0
- package/packages/node/src/app/analytics-node.ts +299 -0
- package/packages/node/src/app/context.ts +11 -0
- package/packages/node/src/app/dispatch-emit.ts +42 -0
- package/packages/node/src/app/emitter.ts +23 -0
- package/packages/node/src/app/event-factory.ts +20 -0
- package/packages/node/src/app/event-queue.ts +23 -0
- package/packages/node/src/app/settings.ts +49 -0
- package/packages/node/src/app/types/index.ts +3 -0
- package/packages/node/src/app/types/params.ts +76 -0
- package/packages/node/src/app/types/plugin.ts +5 -0
- package/packages/node/src/app/types/segment-event.ts +7 -0
- package/packages/node/src/generated/version.ts +2 -0
- package/packages/node/src/index.ts +26 -0
- package/packages/node/src/lib/__tests__/abort.test.ts +54 -0
- package/packages/node/src/lib/__tests__/create-url.test.ts +35 -0
- package/packages/node/src/lib/__tests__/env.test.ts +52 -0
- package/packages/node/src/lib/__tests__/get-message-id.test.ts +21 -0
- package/packages/node/src/lib/abort.ts +77 -0
- package/packages/node/src/lib/base-64-encode.ts +8 -0
- package/packages/node/src/lib/create-url.ts +11 -0
- package/packages/node/src/lib/env.ts +45 -0
- package/packages/node/src/lib/extract-promise-parts.ts +21 -0
- package/packages/node/src/lib/fetch.ts +16 -0
- package/packages/node/src/lib/get-message-id.ts +10 -0
- package/packages/node/src/lib/http-client.ts +95 -0
- package/packages/node/src/lib/uuid.ts +1 -0
- package/packages/node/src/plugins/segmentio/__tests__/methods.test.ts +223 -0
- package/packages/node/src/plugins/segmentio/__tests__/publisher.test.ts +411 -0
- package/packages/node/src/plugins/segmentio/context-batch.ts +71 -0
- package/packages/node/src/plugins/segmentio/index.ts +66 -0
- package/packages/node/src/plugins/segmentio/publisher.ts +265 -0
- package/packages/node/tsconfig.build.json +9 -0
- package/packages/node/tsconfig.json +10 -0
- package/packages/test-helpers/.eslintrc.js +7 -0
- package/packages/test-helpers/.lintstagedrc.js +1 -0
- package/packages/test-helpers/jest.config.js +3 -0
- package/packages/test-helpers/package.json +26 -0
- package/packages/test-helpers/src/analytics/cdn-settings-builder.ts +79 -0
- package/packages/test-helpers/src/analytics/index.ts +1 -0
- package/packages/test-helpers/src/index.ts +2 -0
- package/packages/test-helpers/src/utils/index.ts +1 -0
- package/packages/test-helpers/src/utils/sleep.ts +4 -0
- package/packages/test-helpers/tsconfig.build.json +9 -0
- package/packages/test-helpers/tsconfig.json +11 -0
- package/tsconfig.json +21 -0
- package/turbo.json +39 -0
- package/typings/get-monorepo-packages.d.ts +9 -0
- 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
|
+
})
|