diff --git a/packages/analytics-browser/src/browser-client.ts b/packages/analytics-browser/src/browser-client.ts index 36deb064c..3c95589d5 100644 --- a/packages/analytics-browser/src/browser-client.ts +++ b/packages/analytics-browser/src/browser-client.ts @@ -239,7 +239,9 @@ export class AmplitudeBrowser extends AmplitudeCore implements BrowserClient, An // Step 7: Add the event receiver after running remaining queued functions. connector.eventBridge.setEventReceiver((event) => { - void this.track(event.eventType, event.eventProperties); + const { time, ...cleanEventProperties } = event.eventProperties || {}; + const eventOptions = typeof time === 'number' ? { time } : undefined; + void this.track(event.eventType, cleanEventProperties, eventOptions); }); } diff --git a/packages/analytics-browser/test/browser-client.test.ts b/packages/analytics-browser/test/browser-client.test.ts index 469b270c7..667cd61e2 100644 --- a/packages/analytics-browser/test/browser-client.test.ts +++ b/packages/analytics-browser/test/browser-client.test.ts @@ -387,6 +387,102 @@ describe('browser-client', () => { expect(track).toHaveBeenCalledTimes(1); }); + test('should handle event bridge events with time property in eventProperties', async () => { + await client.init(apiKey, userId, { + optOut: false, + defaultTracking, + }).promise; + const track = jest.spyOn(client, 'track').mockReturnValueOnce({ + promise: Promise.resolve({ + code: 200, + message: '', + event: { + event_type: 'custom_event', + }, + }), + }); + + const customTime = 12345; + getAnalyticsConnector().eventBridge.logEvent({ + eventType: 'custom_event', + eventProperties: { + property1: 'value1', + property2: 123, + time: customTime, + property3: true, + }, + }); + + expect(track).toHaveBeenCalledTimes(1); + expect(track).toHaveBeenCalledWith( + 'custom_event', + { + property1: 'value1', + property2: 123, + property3: true, + }, + { time: customTime }, + ); + }); + + test('should handle event bridge events with null time property', async () => { + await client.init(apiKey, userId, { + optOut: false, + defaultTracking, + }).promise; + const track = jest.spyOn(client, 'track').mockReturnValueOnce({ + promise: Promise.resolve({ + code: 200, + message: '', + event: { + event_type: 'null_time_event', + }, + }), + }); + + getAnalyticsConnector().eventBridge.logEvent({ + eventType: 'null_time_event', + eventProperties: { + property1: 'value1', + time: null, + property2: 'value2', + }, + }); + + expect(track).toHaveBeenCalledTimes(1); + expect(track).toHaveBeenCalledWith( + 'null_time_event', + { + property1: 'value1', + property2: 'value2', + }, + undefined, + ); + }); + + test('should handle event bridge events with no eventProperties', async () => { + await client.init(apiKey, userId, { + optOut: false, + defaultTracking, + }).promise; + const track = jest.spyOn(client, 'track').mockReturnValueOnce({ + promise: Promise.resolve({ + code: 200, + message: '', + event: { + event_type: 'no_props_event', + }, + }), + }); + + getAnalyticsConnector().eventBridge.logEvent({ + eventType: 'no_props_event', + }); + + expect(track).toHaveBeenCalledTimes(1); + expect(track).toHaveBeenCalledWith('no_props_event', {}, undefined); + }); + test('should add file download and form interaction tracking plugins', async () => { const fileDownloadTrackingPlugin = jest.spyOn(fileDownloadTracking, 'fileDownloadTracking'); const formInteractionTrackingPlugin = jest.spyOn(formInteractionTracking, 'formInteractionTracking');