diff --git a/src/internal/base-component/__tests__/metrics.test.ts b/src/internal/base-component/__tests__/metrics.test.ts index 9b24743..c449175 100644 --- a/src/internal/base-component/__tests__/metrics.test.ts +++ b/src/internal/base-component/__tests__/metrics.test.ts @@ -55,10 +55,20 @@ describe('Client Metrics support', () => { }); test('does nothing when window.AWSC.Clog is undefined', () => { - window.AWSC = undefined; + window.AWSC = {}; metrics.sendMetric('name', 0); // only proves no exception thrown }); + test('uses panorama API as fallback when AWSC.Clog.log is unavailable', () => { + delete window.AWSC; + metrics.sendMetric('name', 0); + expect(window.panorama).toHaveBeenCalledWith('trackCustomEvent', { + eventName: 'name', + eventValue: '0', + timestamp: expect.any(Number), + }); + }); + test('does nothing when window.AWSC.Clog.log is undefined', () => { window.AWSC = { Clog: undefined, @@ -68,10 +78,15 @@ describe('Client Metrics support', () => { describe('within an iframe', () => { mockConsoleError(); + const originalWindowParent = Object.getOwnPropertyDescriptor(window, 'parent')!; + + afterEach(() => { + Object.defineProperty(window, 'parent', originalWindowParent); + expect(window.parent.AWSC).toBeUndefined(); + }); + const setupIframe = () => { - const parentWindow = { ...window }; - Object.defineProperty(window, 'parent', { value: parentWindow }); - Object.defineProperty(parentWindow, 'parent', { value: parentWindow }); + Object.defineProperty(window, 'parent', { configurable: true, writable: true, value: { parent: {} } }); }; test('does nothing when AWSC is not defined in the parent iframe', () => { @@ -91,6 +106,8 @@ describe('Client Metrics support', () => { }, }; jest.spyOn(window.parent.AWSC.Clog, 'log'); + expect(window.AWSC).toBeUndefined(); + expect(window.parent.AWSC).toBeDefined(); metrics.sendMetric('name', 0, undefined); expect(window.parent.AWSC.Clog.log).toHaveBeenCalledWith('name', 0, undefined); @@ -173,6 +190,17 @@ describe('Client Metrics support', () => { }); describe('sendMetricObject', () => { + test('uses panorama API as fallback when AWSC.Clog.log is unavailable', () => { + window.AWSC = undefined; + metrics.sendMetricObject({ source: 'pkg', action: 'used', version: '5.0' }, 1); + expect(window.panorama).toHaveBeenCalledWith('trackCustomEvent', { + eventDetail: '{"o":"main","s":"pkg","t":"default","a":"used","f":"react","v":"5.0"}', + eventName: 'awsui_pkg_d50', + eventValue: '1', + timestamp: expect.any(Number), + }); + }); + describe('correctly maps input object to metric name', () => { test('applies default values for theme (default) and framework (react)', () => { metrics.sendMetricObject( diff --git a/src/internal/base-component/__tests__/panorama-metrics.test.ts b/src/internal/base-component/__tests__/panorama-metrics.test.ts index dd59cd6..318bdc5 100644 --- a/src/internal/base-component/__tests__/panorama-metrics.test.ts +++ b/src/internal/base-component/__tests__/panorama-metrics.test.ts @@ -56,6 +56,14 @@ describe('PanoramaClient', () => { expect(consoleSpy).toHaveBeenCalledWith(`Event type for metric is too long: ${eventType}`); }); + test('prints an error when event name is too long', () => { + const eventName = 'a'.repeat(1001); + panorama.sendMetric({ eventName }); + + expect(window.panorama).not.toHaveBeenCalled(); + expect(consoleSpy).toHaveBeenCalledWith(`Event name for metric is too long: ${eventName}`); + }); + test('prints an error when event value is too long', () => { const eventValue = 'a'.repeat(4001); panorama.sendMetric({ eventValue }); diff --git a/src/internal/base-component/metrics/log-clients.ts b/src/internal/base-component/metrics/log-clients.ts index 0b3cb80..647a7af 100644 --- a/src/internal/base-component/metrics/log-clients.ts +++ b/src/internal/base-component/metrics/log-clients.ts @@ -11,6 +11,7 @@ interface MetricsWindow extends Window { } export interface MetricsV2EventItem { + eventName?: string; eventType?: string; eventContext?: string; eventDetail?: string | Record; @@ -45,6 +46,13 @@ export class CLogClient { const AWSC = this.findAWSC(window); if (typeof AWSC === 'object' && typeof AWSC.Clog === 'object' && typeof AWSC.Clog.log === 'function') { AWSC.Clog.log(metricName, value, detail); + } else { + new PanoramaClient().sendMetric({ + eventName: metricName, + eventDetail: detail, + eventValue: `${value}`, + timestamp: Date.now(), + }); } } @@ -81,6 +89,10 @@ export class PanoramaClient { if (typeof metric.eventValue === 'object') { metric.eventValue = JSON.stringify(metric.eventValue); } + if (!validateLength(metric.eventName, 1000)) { + console.error(`Event name for metric is too long: ${metric.eventName}`); + return; + } if (!validateLength(metric.eventDetail, 4000)) { console.error(`Event detail for metric is too long: ${metric.eventDetail}`); return;