Skip to content

Commit

Permalink
Add web vitals monitoring and integrate with GA4 (#33277)
Browse files Browse the repository at this point in the history
* Add web vitals monitoring and integrate with GA4

* de-duplicate internal-slot package

* de-duplicate internal-slot package

* Update event name to meet gtm reqs

* Exclude production envs to allow testing in staging

* Add unit tests
  • Loading branch information
acrollet authored Dec 4, 2024
1 parent 2f16961 commit a1376d9
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 298 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@
"url-search-params-polyfill": "^8.1.1",
"uswds": "1.6.10",
"vanilla-lazyload": "^16.1.0",
"vets-json-schema": "https://github.com/department-of-veterans-affairs/vets-json-schema.git#d100b223e002a2a4eea12544a9b9d539b0d2242f"
"vets-json-schema": "https://github.com/department-of-veterans-affairs/vets-json-schema.git#d100b223e002a2a4eea12544a9b9d539b0d2242f",
"web-vitals": "^4.2.4"
},
"resolutions": {
"**/lodash": "4.17.21",
Expand Down
76 changes: 76 additions & 0 deletions src/platform/monitoring/tests/web-vitals.unit.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* eslint-disable camelcase */
import { expect } from 'chai';
import sinon from 'sinon';
import * as recordEventModule from 'platform/monitoring/record-event';
import { recordWebVitalsEvent } from '../web-vitals';

describe('recordWebVitalsEvent', () => {
let recordEventStub;

beforeEach(() => {
recordEventStub = sinon.stub(recordEventModule, 'default');
});

afterEach(() => {
recordEventStub.restore();
});

it('should record a web vitals event with correct properties for CLS', () => {
const event = {
name: 'CLS',
delta: 0.123,
id: 'v1',
};
recordWebVitalsEvent(event);
expect(recordEventStub.calledOnce).to.be.true;
const recordedEvent = recordEventStub.getCall(0).args[0];
expect(recordedEvent).to.deep.equal({
event: 'web_vitals',
event_category: 'Performance',
event_action: 'CLS',
event_value: 123,
event_label: 'v1',
app_name: 'unknown',
});
});

it('should record a web vitals event with correct properties for non-CLS events', () => {
const event = {
name: 'LCP',
delta: 2500,
id: 'v2',
};
recordWebVitalsEvent(event);
expect(recordEventStub.calledOnce).to.be.true;
const recordedEvent = recordEventStub.getCall(0).args[0];
expect(recordedEvent).to.deep.equal({
event: 'web_vitals',
event_category: 'Performance',
event_action: 'LCP',
event_value: 2500,
event_label: 'v2',
app_name: 'unknown',
});
});

it('should use window.appName if available', () => {
window.appName = 'testApp';
const event = {
name: 'TTFB',
delta: 100,
id: 'v3',
};
recordWebVitalsEvent(event);
expect(recordEventStub.calledOnce).to.be.true;
const recordedEvent = recordEventStub.getCall(0).args[0];
expect(recordedEvent).to.deep.equal({
event: 'web_vitals',
event_category: 'Performance',
event_action: 'TTFB',
event_value: 100,
event_label: 'v3',
app_name: 'testApp',
});
delete window.appName;
});
});
37 changes: 37 additions & 0 deletions src/platform/monitoring/web-vitals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* eslint-disable camelcase */
/**
* Initializes web vitals reporting to GA4 on non-localhost environments.
*/
import environment from '@department-of-veterans-affairs/platform-utilities/environment';
import { recordEvent } from '@department-of-veterans-affairs/platform-monitoring/exports';

import { onCLS, onINP, onLCP, onTTFB } from 'web-vitals';

const recordWebVitalsEvent = event => {
const webVitalsEvent = {
event: 'web_vitals',
event_category: 'Performance',
event_action: event.name,
event_value: Math.round(
event.name === 'CLS' ? event.delta * 1000 : event.delta,
),
event_label: event.id,
app_name: window.appName || 'unknown',
};
recordEvent(webVitalsEvent);
};

const trackWebVitals =
// Exclude production for now.
!environment.isProduction &&
// Exclude cypress containers and localhost from tracking web vitals.
environment.BASE_URL.indexOf('localhost') < 0;

if (trackWebVitals) {
onCLS(recordWebVitalsEvent);
onINP(recordWebVitalsEvent);
onLCP(recordWebVitalsEvent);
onTTFB(recordWebVitalsEvent);
}

export { recordWebVitalsEvent };
5 changes: 3 additions & 2 deletions src/platform/site-wide/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Node modules.
import '@department-of-veterans-affairs/formation/dist/formation';
// Relative imports.
import '../monitoring/sentry.js';
import '../monitoring/sentry';
import '../monitoring/web-vitals';
import './component-library-analytics-setup';
import './medallia-feedback-button';
import './moment-setup';
Expand All @@ -28,7 +29,7 @@ import { addOverlayTriggers } from './legacy/menu';
export default function startSitewideComponents(commonStore) {
// New navigation menu
if (document.querySelector('#vetnav')) {
require('./legacy/mega-menu.js');
require('./legacy/mega-menu');
}

// Prevent some browsers from changing the value when scrolling while hovering
Expand Down
Loading

0 comments on commit a1376d9

Please sign in to comment.