diff --git a/.changeset/slow-forks-tease.md b/.changeset/slow-forks-tease.md new file mode 100644 index 00000000000..24b8cb953e9 --- /dev/null +++ b/.changeset/slow-forks-tease.md @@ -0,0 +1,5 @@ +--- +'@firebase/analytics': patch +--- + +Update to allow for multiple instance of gtag with different datalayer names diff --git a/packages/analytics/src/helpers.test.ts b/packages/analytics/src/helpers.test.ts index 0a67fafcf60..1175ff0f61e 100644 --- a/packages/analytics/src/helpers.test.ts +++ b/packages/analytics/src/helpers.test.ts @@ -29,6 +29,7 @@ import { import { GtagCommand } from './constants'; import { Deferred } from '@firebase/util'; import { ConsentSettings } from './public-types'; +import { removeGtagScripts } from '../testing/gtag-script-util'; const fakeMeasurementId = 'abcd-efgh-ijkl'; const fakeAppId = 'my-test-app-1234'; @@ -46,6 +47,10 @@ const fakeDynamicConfig: DynamicConfig = { const fakeDynamicConfigPromises = [Promise.resolve(fakeDynamicConfig)]; describe('Gtag wrapping functions', () => { + afterEach(() => { + removeGtagScripts(); + }); + it('getOrCreateDataLayer is able to create a new data layer if none exists', () => { delete window['dataLayer']; expect(getOrCreateDataLayer('dataLayer')).to.deep.equal([]); @@ -57,14 +62,24 @@ describe('Gtag wrapping functions', () => { }); it('insertScriptIfNeeded inserts script tag', () => { - expect(findGtagScriptOnPage()).to.be.null; - insertScriptTag('customDataLayerName', fakeMeasurementId); - const scriptTag = findGtagScriptOnPage(); + const customDataLayerName = 'customDataLayerName'; + expect(findGtagScriptOnPage(customDataLayerName)).to.be.null; + insertScriptTag(customDataLayerName, fakeMeasurementId); + const scriptTag = findGtagScriptOnPage(customDataLayerName); expect(scriptTag).to.not.be.null; expect(scriptTag!.src).to.contain(`l=customDataLayerName`); expect(scriptTag!.src).to.contain(`id=${fakeMeasurementId}`); }); + // The test above essentially already touches this functionality but it is still valuable + it('findGtagScriptOnPage returns gtag instance with matching data layer name', () => { + const defaultDataLayerName = 'dataLayer'; + insertScriptTag(defaultDataLayerName, fakeMeasurementId); + const scriptTag = findGtagScriptOnPage(defaultDataLayerName); + expect(scriptTag!.src).to.contain(`l=${defaultDataLayerName}`); + expect(findGtagScriptOnPage('NON_EXISTENT_DATA_LAYER_ID')).to.be.null; + }); + describe('wrapOrCreateGtag() when user has not previously inserted a gtag script tag on this page', () => { afterEach(() => { delete window['gtag']; diff --git a/packages/analytics/src/helpers.ts b/packages/analytics/src/helpers.ts index be713c2c8a0..1fb8a38319c 100644 --- a/packages/analytics/src/helpers.ts +++ b/packages/analytics/src/helpers.ts @@ -318,12 +318,19 @@ export function wrapOrCreateGtag( } /** - * Returns first script tag in DOM matching our gtag url pattern. + * Returns the script tag in the DOM matching both the gtag url pattern + * and the provided data layer name. */ -export function findGtagScriptOnPage(): HTMLScriptElement | null { +export function findGtagScriptOnPage( + dataLayerName: string +): HTMLScriptElement | null { const scriptTags = window.document.getElementsByTagName('script'); for (const tag of Object.values(scriptTags)) { - if (tag.src && tag.src.includes(GTAG_URL)) { + if ( + tag.src && + tag.src.includes(GTAG_URL) && + tag.src.includes(dataLayerName) + ) { return tag; } } diff --git a/packages/analytics/src/index.test.ts b/packages/analytics/src/index.test.ts index 607c2e74a5d..e83eb7f9a77 100644 --- a/packages/analytics/src/index.test.ts +++ b/packages/analytics/src/index.test.ts @@ -26,7 +26,7 @@ import { import { FirebaseApp } from '@firebase/app'; import { GtagCommand } from './constants'; import { findGtagScriptOnPage } from './helpers'; -import { removeGtagScript } from '../testing/gtag-script-util'; +import { removeGtagScripts } from '../testing/gtag-script-util'; import { Deferred } from '@firebase/util'; import { AnalyticsError } from './errors'; import { logEvent } from './api'; @@ -150,7 +150,7 @@ describe('FirebaseAnalytics instance tests', () => { after(() => { delete window['gtag']; delete window['dataLayer']; - removeGtagScript(); + removeGtagScripts(); fetchStub.restore(); clock.restore(); idbOpenStub.restore(); @@ -208,7 +208,7 @@ describe('FirebaseAnalytics instance tests', () => { afterEach(() => { delete window['gtag']; delete window['dataLayer']; - removeGtagScript(); + removeGtagScripts(); fetchStub.restore(); clock.restore(); warnStub.restore(); @@ -304,7 +304,7 @@ describe('FirebaseAnalytics instance tests', () => { after(() => { delete window[customGtagName]; delete window[customDataLayerName]; - removeGtagScript(); + removeGtagScripts(); fetchStub.restore(); clock.restore(); idbOpenStub.restore(); @@ -349,13 +349,13 @@ describe('FirebaseAnalytics instance tests', () => { // Successfully resolves fake IDB open request. fakeRequest.onsuccess(); await initializationPromisesMap[fakeAppParams.appId]; - expect(findGtagScriptOnPage()).to.not.be.null; + expect(findGtagScriptOnPage('dataLayer')).to.not.be.null; expect(typeof window['gtag']).to.equal('function'); expect(Array.isArray(window['dataLayer'])).to.be.true; delete window['gtag']; delete window['dataLayer']; - removeGtagScript(); + removeGtagScripts(); fetchStub.restore(); idbOpenStub.restore(); }); diff --git a/packages/analytics/src/initialize-analytics.test.ts b/packages/analytics/src/initialize-analytics.test.ts index da2c8f964b6..8760a63b2f1 100644 --- a/packages/analytics/src/initialize-analytics.test.ts +++ b/packages/analytics/src/initialize-analytics.test.ts @@ -28,7 +28,7 @@ import { DynamicConfig } from './types'; import { FirebaseApp } from '@firebase/app'; import { Deferred } from '@firebase/util'; import { _FirebaseInstallationsInternal } from '@firebase/installations'; -import { removeGtagScript } from '../testing/gtag-script-util'; +import { removeGtagScripts } from '../testing/gtag-script-util'; import { setDefaultEventParameters } from './api'; import { defaultConsentSettingsForInit, @@ -68,7 +68,7 @@ describe('initializeAnalytics()', () => { }); afterEach(() => { fetchStub.restore(); - removeGtagScript(); + removeGtagScripts(); }); it('gets FID and measurement ID and calls gtag config with them', async () => { stubFetch(); diff --git a/packages/analytics/src/initialize-analytics.ts b/packages/analytics/src/initialize-analytics.ts index f89fcf1ddf7..da79ad9108b 100644 --- a/packages/analytics/src/initialize-analytics.ts +++ b/packages/analytics/src/initialize-analytics.ts @@ -119,8 +119,9 @@ export async function _initializeAnalytics( fidPromise ]); - // Detect if user has already put the gtag