Skip to content

Commit

Permalink
Update to allow for multiple instance of gtag with different datalaye…
Browse files Browse the repository at this point in the history
…r names (#6655)

* Update to look for datalayer of gtag script

* Update tests and remove console.logs

* Update doc string to reflect function changes

* Update function name to more accurately reflect usage

* Adding changeset
  • Loading branch information
dwyfrequency committed Oct 10, 2022
1 parent 63f4eca commit 1fbc4c4
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/slow-forks-tease.md
@@ -0,0 +1,5 @@
---
'@firebase/analytics': patch
---

Update to allow for multiple instance of gtag with different datalayer names
21 changes: 18 additions & 3 deletions packages/analytics/src/helpers.test.ts
Expand Up @@ -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';
Expand All @@ -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([]);
Expand All @@ -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'];
Expand Down
13 changes: 10 additions & 3 deletions packages/analytics/src/helpers.ts
Expand Up @@ -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;
}
}
Expand Down
12 changes: 6 additions & 6 deletions packages/analytics/src/index.test.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -150,7 +150,7 @@ describe('FirebaseAnalytics instance tests', () => {
after(() => {
delete window['gtag'];
delete window['dataLayer'];
removeGtagScript();
removeGtagScripts();
fetchStub.restore();
clock.restore();
idbOpenStub.restore();
Expand Down Expand Up @@ -208,7 +208,7 @@ describe('FirebaseAnalytics instance tests', () => {
afterEach(() => {
delete window['gtag'];
delete window['dataLayer'];
removeGtagScript();
removeGtagScripts();
fetchStub.restore();
clock.restore();
warnStub.restore();
Expand Down Expand Up @@ -304,7 +304,7 @@ describe('FirebaseAnalytics instance tests', () => {
after(() => {
delete window[customGtagName];
delete window[customDataLayerName];
removeGtagScript();
removeGtagScripts();
fetchStub.restore();
clock.restore();
idbOpenStub.restore();
Expand Down Expand Up @@ -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();
});
Expand Down
4 changes: 2 additions & 2 deletions packages/analytics/src/initialize-analytics.test.ts
Expand Up @@ -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,
Expand Down Expand Up @@ -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();
Expand Down
5 changes: 3 additions & 2 deletions packages/analytics/src/initialize-analytics.ts
Expand Up @@ -119,8 +119,9 @@ export async function _initializeAnalytics(
fidPromise
]);

// Detect if user has already put the gtag <script> tag on this page.
if (!findGtagScriptOnPage()) {
// Detect if user has already put the gtag <script> tag on this page with the passed in
// data layer name.
if (!findGtagScriptOnPage(dataLayerName)) {
insertScriptTag(dataLayerName, dynamicConfig.measurementId);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/analytics/testing/gtag-script-util.ts
Expand Up @@ -16,7 +16,7 @@
*/
import { GTAG_URL } from '../src/constants';

export function removeGtagScript(): void {
export function removeGtagScripts(): void {
const scriptTags = window.document.getElementsByTagName('script');
for (const tag of Object.values(scriptTags)) {
if (tag.src) {
Expand Down

0 comments on commit 1fbc4c4

Please sign in to comment.