Skip to content

Commit

Permalink
Merge pull request #1869 from GoogleChrome/gtm
Browse files Browse the repository at this point in the history
Cache gtm.js runtime caching
  • Loading branch information
philipwalton authored Jan 30, 2019
2 parents 5f08e81 + 5b90f25 commit 70ae962
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 25 deletions.
18 changes: 18 additions & 0 deletions packages/workbox-google-analytics/initialize.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
GTM_HOST,
ANALYTICS_JS_PATH,
GTAG_JS_PATH,
GTM_JS_PATH,
COLLECT_PATHS_REGEX,
} from './utils/constants.mjs';
import './_version.mjs';
Expand Down Expand Up @@ -157,6 +158,22 @@ const createGtagJsRoute = (cacheName) => {
return new Route(match, handler, 'GET');
};

/**
* Creates a route with a network first strategy for the gtm.js script.
*
* @param {string} cacheName
* @return {Route} The created route.
*
* @private
*/
const createGtmJsRoute = (cacheName) => {
const match = ({url}) => url.hostname === GTM_HOST &&
url.pathname === GTM_JS_PATH;
const handler = new NetworkFirst({cacheName});

return new Route(match, handler, 'GET');
};

/**
* @param {Object=} [options]
* @param {Object} [options.cacheName] The cache name to store and retrieve
Expand All @@ -182,6 +199,7 @@ const initialize = (options = {}) => {
});

const routes = [
createGtmJsRoute(cacheName),
createAnalyticsJsRoute(cacheName),
createGtagJsRoute(cacheName),
...createCollectRoutes(queuePlugin),
Expand Down
1 change: 1 addition & 0 deletions packages/workbox-google-analytics/utils/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const GOOGLE_ANALYTICS_HOST = 'www.google-analytics.com';
export const GTM_HOST = 'www.googletagmanager.com';
export const ANALYTICS_JS_PATH = '/analytics.js';
export const GTAG_JS_PATH = '/gtag/js';
export const GTM_JS_PATH = '/gtm.js';
export const COLLECT_DEFAULT_PATH = '/collect';

// This RegExp matches all known Measurement Protocol single-hit collect
Expand Down
22 changes: 12 additions & 10 deletions test/workbox-google-analytics/integration/basic-example.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const expect = require('chai').expect;
const qs = require('qs');
const {By} = require('selenium-webdriver');
const activateAndControlSW = require('../../../infra/testing/activate-and-control');
const waitUntil = require('../../../infra/testing/wait-until');


describe(`[workbox-google-analytics] Load and use Google Analytics`, function() {
const driver = global.__workbox.webdriver;
Expand Down Expand Up @@ -101,6 +103,7 @@ describe(`[workbox-google-analytics] Load and use Google Analytics`, function()
event_callback: () => done(),
});
});
// This request should not match GA routes, so it shouldn't be replayed.
await driver.executeAsyncScript((done) => {
fetch('https://httpbin.org/get').then(() => done());
});
Expand All @@ -112,17 +115,17 @@ describe(`[workbox-google-analytics] Load and use Google Analytics`, function()
});
expect(requests).to.have.lengthOf(0);

// Uncheck the "simulate offline" checkbox and then trigger a sync.
// Uncheck the "simulate offline" checkbox, which should let queued
// requests start to replay successfully.
await simulateOfflineEl.click();
await driver.executeAsyncScript(messageSW, {
action: 'dispatch-sync-event',
});

// Ensure only 2 requests have replayed, since only 2 of them were to GA.
requests = await driver.executeAsyncScript(messageSW, {
action: 'get-spied-requests',
});
expect(requests).to.have.lengthOf(2);
// Wait until all expected requests have replayed.
await waitUntil(async () => {
requests = await driver.executeAsyncScript(messageSW, {
action: 'get-spied-requests',
});
return requests.length === 2;
}, 25, 200);

// Parse the request bodies to set the params as an object and convert the
// qt param to a number.
Expand All @@ -132,7 +135,6 @@ describe(`[workbox-google-analytics] Load and use Google Analytics`, function()
request.originalTime = request.timestamp - request.params.qt;
}


expect(requests[0].params.ea).to.equal('beacon');
expect(requests[1].params.ea).to.equal('pixel');

Expand Down
16 changes: 16 additions & 0 deletions test/workbox-google-analytics/node/test-index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
GTM_HOST,
ANALYTICS_JS_PATH,
GTAG_JS_PATH,
GTM_JS_PATH,
} from '../../../packages/workbox-google-analytics/utils/constants.mjs';

const PAYLOAD = 'v=1&t=pageview&tid=UA-12345-1&cid=1&dp=%2F';
Expand Down Expand Up @@ -73,6 +74,21 @@ describe(`[workbox-google-analytics] initialize`, function() {
expect(NetworkFirst.prototype.handle.calledOnce).to.be.true;
});

it(`should register a handler to cache the gtm.js script`, function() {
sandbox.spy(NetworkFirst.prototype, 'handle');

initialize();

self.dispatchEvent(new FetchEvent('fetch', {
request: new Request(
`https://${GTM_HOST}${GTM_JS_PATH}?id=GTM-XXXX`, {
mode: 'no-cors',
}),
}));

expect(NetworkFirst.prototype.handle.calledOnce).to.be.true;
});

it(`should accept an optional cache name`, async function() {
initialize({cacheName: 'foobar'});

Expand Down
23 changes: 8 additions & 15 deletions test/workbox-google-analytics/static/basic-example/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@ importScripts('/infra/testing/comlink/sw-interface.js');

workbox.setConfig({modulePathPrefix: '/__WORKBOX/buildFile/'});

const sleep = async (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};

// Spy on .fetch() calls from inside the service worker.
// If `simulateOffline` is set to true, throw a network error.
let simulateOffline = false;
let spiedRequests = [];
const originalFetch = self.fetch;
self.fetch = async (...args) => {
if (simulateOffline) {
throw Response.error();
// Simulate network latency, so the sync event doesn't just fire
// in an endless loop.
await sleep(100);
throw new Error('Simulated network error');
}
const clone = args[0] instanceof Request ?
args[0].clone() : new Request(args[0]);
Expand All @@ -45,20 +52,6 @@ self.addEventListener('message', (evt) => {
case 'get-spied-requests':
evt.ports[0].postMessage(spiedRequests);
break;
case 'dispatch-sync-event':
{
// Override `.waitUntil` so we can signal when the sync is done.
const originalSyncEventWaitUntil = SyncEvent.prototype.waitUntil;
SyncEvent.prototype.waitUntil = (promise) => {
return promise.then(() => evt.ports[0].postMessage(null));
};

self.dispatchEvent(new SyncEvent('sync', {
tag: 'workbox-background-sync:workbox-google-analytics',
}));
SyncEvent.prototype.waitUntil = originalSyncEventWaitUntil;
}
break;
}
});

Expand Down

0 comments on commit 70ae962

Please sign in to comment.