From 20059524b05522364c9f5d7a43cee3f2f0175011 Mon Sep 17 00:00:00 2001 From: Matus Tomlein Date: Wed, 5 Jun 2024 11:07:00 +0200 Subject: [PATCH] Add an option to generate the page view ID according to changes in the page URL to account for events tracked before page views in SPAs (close #1307 and #1125) PR #1308 * Add an option to generate the page view ID according to changes in the page URL to account for events tracked before page views in SPAs (close #1307) * Generate a new page view ID on the second page view tracked on the same page regardless of whether preservePageViewIdForUrl is enabled * Handle multiple trackers with shared state such that they share the page view IDs for events tracked after each other --- .bundlemonrc.json | 4 +- .../browser-tracker/browser-tracker.api.md | 5 + ...ue-1307-page_view_id_2024-05-02-13-51.json | 10 + ...ue-1307-page_view_id_2024-05-02-14-18.json | 10 + libraries/browser-tracker-core/src/state.ts | 2 + .../browser-tracker-core/src/tracker/index.ts | 54 ++- .../browser-tracker-core/src/tracker/types.ts | 25 ++ .../test/helpers/index.ts | 4 +- .../test/tracker/page_view_id.test.ts | 359 ++++++++++++++++++ trackers/browser-tracker/src/index.ts | 2 + 10 files changed, 464 insertions(+), 11 deletions(-) create mode 100644 common/changes/@snowplow/browser-tracker-core/issue-1307-page_view_id_2024-05-02-13-51.json create mode 100644 common/changes/@snowplow/browser-tracker/issue-1307-page_view_id_2024-05-02-14-18.json create mode 100644 libraries/browser-tracker-core/test/tracker/page_view_id.test.ts diff --git a/.bundlemonrc.json b/.bundlemonrc.json index 466289b96..57965c60b 100644 --- a/.bundlemonrc.json +++ b/.bundlemonrc.json @@ -7,7 +7,7 @@ }, { "path": "./trackers/browser-tracker/dist/index.umd.min.js", - "maxSize": "15.5kb", + "maxSize": "16kb", "maxPercentIncrease": 10 }, { @@ -22,7 +22,7 @@ }, { "path": "./libraries/browser-tracker-core/dist/index.module.js", - "maxSize": "27kb", + "maxSize": "28kb", "maxPercentIncrease": 10 }, { diff --git a/api-docs/docs/browser-tracker/browser-tracker.api.md b/api-docs/docs/browser-tracker/browser-tracker.api.md index 12d8b1a63..5660e9f38 100644 --- a/api-docs/docs/browser-tracker/browser-tracker.api.md +++ b/api-docs/docs/browser-tracker/browser-tracker.api.md @@ -83,6 +83,7 @@ export interface BrowserTracker { namespace: string; newSession: () => void; preservePageViewId: () => void; + preservePageViewIdForUrl: (preserve: PreservePageViewIdForUrl) => void; setBufferSize: (newBufferSize: number) => void; setCollectorUrl: (collectorUrl: string) => void; setCookiePath: (path: string) => void; @@ -291,6 +292,9 @@ export type PostBatch = Record[]; // @public export function preservePageViewId(trackers?: Array): void; +// @public (undocumented) +export type PreservePageViewIdForUrl = boolean | "full" | "pathname" | "pathnameAndSearch"; + // @public export function removeGlobalContexts(contexts: Array, trackers?: Array): void; @@ -417,6 +421,7 @@ export type TrackerConfiguration = { retryFailedRequests?: boolean; onRequestSuccess?: (data: EventBatch) => void; onRequestFailure?: (data: RequestFailure) => void; + preservePageViewIdForUrl?: PreservePageViewIdForUrl; }; // @public diff --git a/common/changes/@snowplow/browser-tracker-core/issue-1307-page_view_id_2024-05-02-13-51.json b/common/changes/@snowplow/browser-tracker-core/issue-1307-page_view_id_2024-05-02-13-51.json new file mode 100644 index 000000000..56d2a4010 --- /dev/null +++ b/common/changes/@snowplow/browser-tracker-core/issue-1307-page_view_id_2024-05-02-13-51.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-tracker-core", + "comment": "Add an option to generate the page view ID according to changes in the page URL to account for events tracked before page views in SPAs (#1307 and #1125)", + "type": "none" + } + ], + "packageName": "@snowplow/browser-tracker-core" +} \ No newline at end of file diff --git a/common/changes/@snowplow/browser-tracker/issue-1307-page_view_id_2024-05-02-14-18.json b/common/changes/@snowplow/browser-tracker/issue-1307-page_view_id_2024-05-02-14-18.json new file mode 100644 index 000000000..a1acbb772 --- /dev/null +++ b/common/changes/@snowplow/browser-tracker/issue-1307-page_view_id_2024-05-02-14-18.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-tracker", + "comment": "Add an option to generate the page view ID according to changes in the page URL to account for events tracked before page views in SPAs (#1307 and #1125)", + "type": "none" + } + ], + "packageName": "@snowplow/browser-tracker" +} \ No newline at end of file diff --git a/libraries/browser-tracker-core/src/state.ts b/libraries/browser-tracker-core/src/state.ts index 75164e25d..d53a5ceba 100644 --- a/libraries/browser-tracker-core/src/state.ts +++ b/libraries/browser-tracker-core/src/state.ts @@ -52,6 +52,8 @@ export class SharedState { /* pageViewId, which can changed by other trackers on page; * initialized by tracker sent first event */ pageViewId?: string; + /* URL of the page view which the `pageViewId` was generated for */ + pageViewUrl?: string; } export function createSharedState(): SharedState { diff --git a/libraries/browser-tracker-core/src/tracker/index.ts b/libraries/browser-tracker-core/src/tracker/index.ts index 37e504fa2..c5e7d01de 100755 --- a/libraries/browser-tracker-core/src/tracker/index.ts +++ b/libraries/browser-tracker-core/src/tracker/index.ts @@ -48,6 +48,7 @@ import { ClientSession, ExtendedCrossDomainLinkerOptions, ParsedIdCookie, + PreservePageViewIdForUrl, } from './types'; import { parseIdCookie, @@ -292,8 +293,10 @@ export function Tracker( ), // Whether pageViewId should be regenerated after each trackPageView. Affect web_page context preservePageViewId = false, - // Whether first trackPageView was fired and pageViewId should not be changed anymore until reload - pageViewSent = false, + // Whether pageViewId should be kept the same until the page URL changes. Affects web_page context + preservePageViewIdForUrl = trackerConfiguration.preservePageViewIdForUrl ?? false, + // The pageViewId of the last page view event or undefined if no page view tracked yet. Used to determine if pageViewId should be regenerated for a new page view. + lastSentPageViewId: string | undefined = undefined, // Activity tracking config for callback and page ping variants activityTrackingConfig: ActivityTrackingConfig = { enabled: false, @@ -719,6 +722,7 @@ export function Tracker( function resetPageView() { if (!preservePageViewId || state.pageViewId == null) { state.pageViewId = uuid(); + state.pageViewUrl = configCustomUrl || locationHrefAlias; } } @@ -727,10 +731,42 @@ export function Tracker( * Generates it if it wasn't initialized by other tracker */ function getPageViewId() { - if (state.pageViewId == null) { + if (shouldGenerateNewPageViewId()) { state.pageViewId = uuid(); + state.pageViewUrl = configCustomUrl || locationHrefAlias; + } + return state.pageViewId!; + } + + function shouldGenerateNewPageViewId() { + // If pageViewId is not initialized, generate it + if (state.pageViewId == null) { + return true; + } + // If pageViewId should be preserved regardless of the URL, don't generate a new one + if (preservePageViewId || !preservePageViewIdForUrl) { + return false; } - return state.pageViewId; + // If doesn't have previous URL in state, generate a new pageViewId + if (state.pageViewUrl === undefined) { + return true; + } + const current = configCustomUrl || locationHrefAlias; + // If full preserve is enabled, compare the full URL + if (preservePageViewIdForUrl === true || preservePageViewIdForUrl == 'full' || !('URL' in window)) { + return state.pageViewUrl != current; + } + const currentUrl = new URL(current); + const previousUrl = new URL(state.pageViewUrl); + // If pathname preserve is enabled, compare the pathname + if (preservePageViewIdForUrl == 'pathname') { + return currentUrl.pathname != previousUrl.pathname; + } + // If pathname and search preserve is enabled, compare the pathname and search + if (preservePageViewIdForUrl == 'pathnameAndSearch') { + return currentUrl.pathname != previousUrl.pathname || currentUrl.search != previousUrl.search; + } + return false; } /** @@ -943,11 +979,11 @@ export function Tracker( function logPageView({ title, context, timestamp, contextCallback }: PageViewEvent & CommonEventProperties) { refreshUrl(); - if (pageViewSent) { - // Do not reset pageViewId if previous events were not page_view + if (lastSentPageViewId && lastSentPageViewId == getPageViewId()) { + // Do not reset pageViewId if a page view was not tracked yet or a different page view ID was used (in order to support multiple trackers with shared state) resetPageView(); } - pageViewSent = true; + lastSentPageViewId = getPageViewId(); // So we know what document.title was at the time of trackPageView lastDocumentTitle = document.title; @@ -1291,6 +1327,10 @@ export function Tracker( preservePageViewId = true; }, + preservePageViewIdForUrl: function (preserve: PreservePageViewIdForUrl) { + preservePageViewIdForUrl = preserve; + }, + disableAnonymousTracking: function (configuration?: DisableAnonymousTrackingConfiguration) { trackerConfiguration.anonymousTracking = false; diff --git a/libraries/browser-tracker-core/src/tracker/types.ts b/libraries/browser-tracker-core/src/tracker/types.ts index d6ce73c0f..a93973bd6 100755 --- a/libraries/browser-tracker-core/src/tracker/types.ts +++ b/libraries/browser-tracker-core/src/tracker/types.ts @@ -46,6 +46,9 @@ export type ExtendedCrossDomainLinkerAttributes = { export type ExtendedCrossDomainLinkerOptions = boolean | ExtendedCrossDomainLinkerAttributes; +/* Setting for the `preservePageViewIdForUrl` configuration that decides how to preserve the pageViewId on URL changes. */ +export type PreservePageViewIdForUrl = boolean | 'full' | 'pathname' | 'pathnameAndSearch'; + /** * The configuration object for initialising the tracker * @example @@ -266,6 +269,17 @@ export type TrackerConfiguration = { * @param data - The data associated with the event(s) that failed to send */ onRequestFailure?: (data: RequestFailure) => void; + + /** + * Decide how the `pageViewId` should be preserved based on the URL. + * If set to `false`, the `pageViewId` will be regenerated on the second and each following page view event (first page view doesn't change the page view ID since tracker initialization). + * If set to `true` or `'full'`, the `pageViewId` will be kept the same for all page views with that exact URL (even for events tracked before the page view event). + * If set to `'pathname'`, the `pageViewId` will be kept the same for all page views with the same pathname (search params or fragment may change). + * If set to `'pathnameAndSearch'`, the `pageViewId` will be kept the same for all page views with the same pathname and search params (fragment may change). + * If `preservePageViewId` is enabled, the `preservePageViewIdForUrl` setting is ignored. + * Defaults to `false`. + */ + preservePageViewIdForUrl?: PreservePageViewIdForUrl; }; /** @@ -603,6 +617,17 @@ export interface BrowserTracker { */ preservePageViewId: () => void; + /** + * Decide how the `pageViewId` should be preserved based on the URL. + * If set to `false`, the `pageViewId` will be regenerated on the second and each following page view event (first page view doesn't change the page view ID since tracker initialization). + * If set to `true` or `'full'`, the `pageViewId` will be kept the same for all page views with that exact URL (even for events tracked before the page view event). + * If set to `'pathname'`, the `pageViewId` will be kept the same for all page views with the same pathname (search params or fragment may change). + * If set to `'pathnameAndSearch'`, the `pageViewId` will be kept the same for all page views with the same pathname and search params (fragment may change). + * If `preservePageViewId` is enabled, the `preservePageViewIdForUrl` setting is ignored. + * Defaults to `false`. + */ + preservePageViewIdForUrl: (preserve: PreservePageViewIdForUrl) => void; + /** * Log visit to this page * diff --git a/libraries/browser-tracker-core/test/helpers/index.ts b/libraries/browser-tracker-core/test/helpers/index.ts index b2a617fc3..b2a3acff3 100644 --- a/libraries/browser-tracker-core/test/helpers/index.ts +++ b/libraries/browser-tracker-core/test/helpers/index.ts @@ -75,7 +75,7 @@ export function createTestSessionIdCookie(params?: CreateTestSessionIdCookie) { return `_sp_ses.${domainHash}=*; Expires=; Path=/; SameSite=None; Secure;`; } -export function createTracker(configuration?: TrackerConfiguration) { +export function createTracker(configuration?: TrackerConfiguration, sharedState?: SharedState) { let id = 'sp-' + Math.random(); - return addTracker(id, id, '', '', new SharedState(), configuration); + return addTracker(id, id, '', '', sharedState ?? new SharedState(), configuration); } diff --git a/libraries/browser-tracker-core/test/tracker/page_view_id.test.ts b/libraries/browser-tracker-core/test/tracker/page_view_id.test.ts new file mode 100644 index 000000000..e573a5fd2 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/page_view_id.test.ts @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { createTracker } from '../helpers'; + +describe('Tracker API: page view IDs', () => { + it('Keeps the page view ID when URL changes', () => { + const tracker = createTracker(); + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + describe('preservePageViewIdForUrl: false', () => { + it('Generates new page view ID on second page view', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl(false); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + const pageView3 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView4 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).toEqual(pageView3); + expect(pageView3).not.toEqual(pageView4); + }); + + it("Doesn't generate new page view ID when URL is changed", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl(false); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + }); + + describe('preservePageViewIdForUrl: full', () => { + it("Generates new page view ID on second page view on the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView3 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).not.toEqual(pageView3); + }); + + it("Doesn't generate new page view ID for the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it('Generates new page view ID when URL changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Generates new page view ID when hash param changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Generates new page view ID when search param changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Works the same way if set to true', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl(true); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Works the same way if configured through createTracker', () => { + const tracker = createTracker({ preservePageViewIdForUrl: 'full' }); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + }); + + describe('preservePageViewIdForUrl: pathname', () => { + it("Generates new page view ID on second page view on the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView3 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).not.toEqual(pageView3); + }); + + it("Doesn't generate new page view ID for the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it("Doesn't generate new page view ID when hash param changes", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it("Doesn't generate new page view ID when search param changes", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it('Generates a new page view ID when the path changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + }); + + describe('preservePageViewIdForUrl: pathnameAndSearch', () => { + it("Generates new page view ID on second page view on the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView3 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).not.toEqual(pageView3); + }); + + it("Doesn't generate new page view ID for the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it("Doesn't generate new page view ID when hash param changes", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it('Generates new page view ID when search param changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Generates a new page view ID when the path changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + }); + + describe('Multiple trackers with a shared state', () => { + it('Keeps the page view ID for each page view pairs', () => { + const tracker1 = createTracker(); + const tracker2 = createTracker(undefined, tracker1?.sharedState); + + tracker1?.setCustomUrl('http://example.com/1'); + tracker1?.trackPageView(); + const pageView1 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView2 = tracker2?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + + tracker1?.trackPageView(); + const pageView3 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView4 = tracker2?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView3); + expect(pageView3).toEqual(pageView4); + }); + + it("Doesn't keep the page view ID for multiple calls to one tracker", () => { + const tracker1 = createTracker(); + const tracker2 = createTracker(undefined, tracker1?.sharedState); + + tracker1?.setCustomUrl('http://example.com/1'); + tracker1?.trackPageView(); + const pageView1 = tracker1?.getPageViewId(); + tracker1?.trackPageView(); + const pageView2 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView3 = tracker2?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + expect(pageView2).toEqual(pageView3); + + tracker1?.trackPageView(); + const pageView4 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView5 = tracker2?.getPageViewId(); + + expect(pageView3).not.toEqual(pageView4); + expect(pageView4).toEqual(pageView5); + }); + }); +}); diff --git a/trackers/browser-tracker/src/index.ts b/trackers/browser-tracker/src/index.ts index 874cb58d5..dfe3701b9 100644 --- a/trackers/browser-tracker/src/index.ts +++ b/trackers/browser-tracker/src/index.ts @@ -43,6 +43,7 @@ import { GetBatch, PostBatch, ParsedIdCookie, + PreservePageViewIdForUrl, } from '@snowplow/browser-tracker-core'; import { version } from '@snowplow/tracker-core'; @@ -91,6 +92,7 @@ export { GetBatch, PostBatch, ParsedIdCookie, + PreservePageViewIdForUrl, }; export { version }; export * from './api';