From b1f9118cede2d1b8a0abe023c32e7727e57cada0 Mon Sep 17 00:00:00 2001 From: Christopher Radek Date: Fri, 21 Oct 2022 12:17:49 -0700 Subject: [PATCH 1/3] adds disableAutoISOConversion load option --- .../src/browser/__tests__/integration.test.ts | 136 +++++++++++++++++- packages/browser/src/core/analytics/index.ts | 7 + packages/browser/src/lib/klona.ts | 4 - .../src/plugins/ajs-destination/index.ts | 6 +- .../browser/src/plugins/middleware/index.ts | 6 +- 5 files changed, 151 insertions(+), 8 deletions(-) delete mode 100644 packages/browser/src/lib/klona.ts diff --git a/packages/browser/src/browser/__tests__/integration.test.ts b/packages/browser/src/browser/__tests__/integration.test.ts index b03740945..1d582f340 100644 --- a/packages/browser/src/browser/__tests__/integration.test.ts +++ b/packages/browser/src/browser/__tests__/integration.test.ts @@ -2,7 +2,7 @@ import { Context } from '@/core/context' import { Plugin } from '@/core/plugin' import { JSDOM } from 'jsdom' -import { Analytics } from '../../core/analytics' +import { Analytics, InitOptions } from '../../core/analytics' import { LegacyDestination } from '../../plugins/ajs-destination' import { PersistedPriorityQueue } from '../../lib/priority-queue/persisted' // @ts-ignore loadLegacySettings mocked dependency is accused as unused @@ -998,3 +998,137 @@ describe('.Integrations', () => { `) }) }) + +describe('Options', () => { + beforeEach(async () => { + jest.restoreAllMocks() + jest.resetAllMocks() + + const html = ` + + + + + + + + `.trim() + + const jsd = new JSDOM(html, { + runScripts: 'dangerously', + resources: 'usable', + url: 'https://localhost', + }) + + const windowSpy = jest.spyOn(global, 'window', 'get') + windowSpy.mockImplementation( + () => jsd.window as unknown as Window & typeof globalThis + ) + }) + + describe('disableAutoISOConversion', () => { + it('converts iso strings to dates be default', async () => { + const [analytics] = await AnalyticsBrowser.load({ + writeKey, + }) + + const amplitude = new LegacyDestination( + 'amplitude', + 'latest', + { + apiKey: AMPLITUDE_WRITEKEY, + }, + {} + ) + + await analytics.register(amplitude) + await amplitude.ready() + + const integrationMock = jest.spyOn(amplitude.integration!, 'track') + await analytics.track('Hello!', { + date: new Date(), + iso: '2020-10-10', + }) + + const [integrationEvent] = integrationMock.mock.lastCall + + expect(integrationEvent.properties()).toEqual({ + date: expect.any(Date), + iso: expect.any(Date), + }) + expect(integrationEvent.timestamp()).toBeInstanceOf(Date) + }) + + it('converts iso strings to dates be default', async () => { + const initOptions: InitOptions = { disableAutoISOConversion: false } + const [analytics] = await AnalyticsBrowser.load( + { + writeKey, + }, + initOptions + ) + + const amplitude = new LegacyDestination( + 'amplitude', + 'latest', + { + apiKey: AMPLITUDE_WRITEKEY, + }, + initOptions + ) + + await analytics.register(amplitude) + await amplitude.ready() + + const integrationMock = jest.spyOn(amplitude.integration!, 'track') + await analytics.track('Hello!', { + date: new Date(), + iso: '2020-10-10', + }) + + const [integrationEvent] = integrationMock.mock.lastCall + + expect(integrationEvent.properties()).toEqual({ + date: expect.any(Date), + iso: expect.any(Date), + }) + expect(integrationEvent.timestamp()).toBeInstanceOf(Date) + }) + + it('does not convert iso strings to dates when `true`', async () => { + const initOptions: InitOptions = { disableAutoISOConversion: true } + const [analytics] = await AnalyticsBrowser.load( + { + writeKey, + }, + initOptions + ) + + const amplitude = new LegacyDestination( + 'amplitude', + 'latest', + { + apiKey: AMPLITUDE_WRITEKEY, + }, + initOptions + ) + + await analytics.register(amplitude) + await amplitude.ready() + + const integrationMock = jest.spyOn(amplitude.integration!, 'track') + await analytics.track('Hello!', { + date: new Date(), + iso: '2020-10-10', + }) + + const [integrationEvent] = integrationMock.mock.lastCall + + expect(integrationEvent.properties()).toEqual({ + date: expect.any(Date), + iso: '2020-10-10', + }) + expect(integrationEvent.timestamp()).toBeInstanceOf(Date) + }) + }) +}) diff --git a/packages/browser/src/core/analytics/index.ts b/packages/browser/src/core/analytics/index.ts index cd501e45e..875b23a3a 100644 --- a/packages/browser/src/core/analytics/index.ts +++ b/packages/browser/src/core/analytics/index.ts @@ -67,6 +67,13 @@ export interface InitOptions { * */ disableClientPersistence?: boolean + /** + * Disables automatically converting ISO string event properties into Dates. + * ISO string to Date conversions occur right before sending events to a classic device mode integration, + * after any destination middleware have been ran. + * Defaults to `false`. + */ + disableAutoISOConversion?: boolean initialPageview?: boolean cookie?: CookieOptions user?: UserOptions diff --git a/packages/browser/src/lib/klona.ts b/packages/browser/src/lib/klona.ts deleted file mode 100644 index 4a325be7b..000000000 --- a/packages/browser/src/lib/klona.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { SegmentEvent } from '../core/events' - -export const klona = (evt: SegmentEvent): SegmentEvent => - JSON.parse(JSON.stringify(evt)) diff --git a/packages/browser/src/plugins/ajs-destination/index.ts b/packages/browser/src/plugins/ajs-destination/index.ts index 441f30408..6bf2e8d99 100644 --- a/packages/browser/src/plugins/ajs-destination/index.ts +++ b/packages/browser/src/plugins/ajs-destination/index.ts @@ -65,6 +65,7 @@ export class LegacyDestination implements Plugin { private _initialized = false private onReady: Promise | undefined private onInitialize: Promise | undefined + private disableAutoISOConversion: boolean integration: LegacyIntegration | undefined @@ -80,6 +81,7 @@ export class LegacyDestination implements Plugin { this.name = name this.version = version this.settings = { ...settings } + this.disableAutoISOConversion = options.disableAutoISOConversion || false // AJS-Renderer sets an extraneous `type` setting that clobbers // existing type defaults. We need to remove it if it's present @@ -228,7 +230,9 @@ export class LegacyDestination implements Plugin { return ctx } - const event = new clz(afterMiddleware, {}) + const event = new clz(afterMiddleware, { + traverse: !this.disableAutoISOConversion, + }) ctx.stats.increment('analytics_js.integration.invoke', 1, [ `method:${eventType}`, diff --git a/packages/browser/src/plugins/middleware/index.ts b/packages/browser/src/plugins/middleware/index.ts index 3a89953c1..eee6fbb26 100644 --- a/packages/browser/src/plugins/middleware/index.ts +++ b/packages/browser/src/plugins/middleware/index.ts @@ -3,7 +3,6 @@ import { SegmentEvent } from '../../core/events' import { Plugin } from '../../core/plugin' import { asPromise } from '../../lib/as-promise' import { SegmentFacade, toFacade } from '../../lib/to-facade' -import { klona } from '../../lib/klona' export interface MiddlewareParams { payload: SegmentFacade @@ -28,7 +27,10 @@ export async function applyDestinationMiddleware( evt: SegmentEvent, middleware: DestinationMiddlewareFunction[] ): Promise { - let modifiedEvent = klona(evt) + let modifiedEvent = toFacade(evt, { + clone: true, + traverse: false, + }).rawEvent() as SegmentEvent async function applyMiddleware( event: SegmentEvent, fn: DestinationMiddlewareFunction From ba3c65e672709ed56d58539d65c1320c63e5a249 Mon Sep 17 00:00:00 2001 From: Christopher Radek Date: Fri, 21 Oct 2022 12:57:30 -0700 Subject: [PATCH 2/3] add comment --- packages/browser/src/plugins/middleware/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/browser/src/plugins/middleware/index.ts b/packages/browser/src/plugins/middleware/index.ts index eee6fbb26..2771492c7 100644 --- a/packages/browser/src/plugins/middleware/index.ts +++ b/packages/browser/src/plugins/middleware/index.ts @@ -27,6 +27,7 @@ export async function applyDestinationMiddleware( evt: SegmentEvent, middleware: DestinationMiddlewareFunction[] ): Promise { + // Clone the event so mutations are localized to a single destination. let modifiedEvent = toFacade(evt, { clone: true, traverse: false, From 88cb9c2efadd701ec9578789cb95b8f3e40d14e5 Mon Sep 17 00:00:00 2001 From: Christopher Radek Date: Fri, 21 Oct 2022 13:29:27 -0700 Subject: [PATCH 3/3] add changelog entry --- .changeset/khaki-mayflies-punch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/khaki-mayflies-punch.md diff --git a/.changeset/khaki-mayflies-punch.md b/.changeset/khaki-mayflies-punch.md new file mode 100644 index 000000000..2a9da8977 --- /dev/null +++ b/.changeset/khaki-mayflies-punch.md @@ -0,0 +1,5 @@ +--- +'@segment/analytics-next': minor +--- + +Adds a new load option `disableAutoISOConversions` that turns off converting ISO strings in event fields to Dates for integrations.