Skip to content

Commit 46c91e6

Browse files
fix: Update BatchUploader to include integration attributes and custom flags in AST events (#1058)
1 parent c450215 commit 46c91e6

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

src/batchUploader.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Batch } from '@mparticle/event-models';
22
import Constants from './constants';
3-
import { SDKEvent, SDKLoggerApi } from './sdkRuntimeModels';
3+
import { SDKEvent, SDKEventCustomFlags, SDKLoggerApi } from './sdkRuntimeModels';
44
import { convertEvents } from './sdkToEventsApiConverter';
55
import { MessageType, EventType } from './types';
66
import { getRampNumber, isEmpty } from './utils';
@@ -14,6 +14,7 @@ import {
1414
import { IMParticleUser } from './identity-user-interfaces';
1515
import { IMParticleWebSDKInstance } from './mp-instance';
1616
import { appendUserInfo } from './user-utils';
17+
import { IntegrationAttributes } from './store';
1718
/**
1819
* BatchUploader contains all the logic to store/retrieve events and batches
1920
* to/from persistence, and upload batches to mParticle.
@@ -147,7 +148,7 @@ export class BatchUploader {
147148
const now = Date.now();
148149
const { _Store, Identity, _timeOnSiteTimer, _Helpers } = this.mpInstance;
149150
const { sessionId, deviceId, sessionStartDate, SDKConfig } = _Store;
150-
const { generateUniqueId } = _Helpers;
151+
const { generateUniqueId, getFeatureFlag } = _Helpers;
151152
const { getCurrentUser } = Identity;
152153

153154
const event = {
@@ -169,7 +170,28 @@ export class BatchUploader {
169170
IsBackgroundAST: true
170171
} as SDKEvent;
171172

173+
174+
let customFlags: SDKEventCustomFlags = {...event.CustomFlags};
175+
let integrationAttributes: IntegrationAttributes = _Store.integrationAttributes;
176+
177+
// https://go.mparticle.com/work/SQDSDKS-5053
178+
if (getFeatureFlag && getFeatureFlag(Constants.FeatureFlags.CaptureIntegrationSpecificIds)) {
179+
180+
// Attempt to recapture click IDs in case a third party integration
181+
// has added or updated new click IDs since the last event was sent.
182+
this.mpInstance._IntegrationCapture.capture();
183+
const transformedClickIDs = this.mpInstance._IntegrationCapture.getClickIdsAsCustomFlags();
184+
customFlags = {...transformedClickIDs, ...customFlags};
185+
186+
const transformedIntegrationAttributes = this.mpInstance._IntegrationCapture.getClickIdsAsIntegrationAttributes();
187+
integrationAttributes = {...transformedIntegrationAttributes, ...integrationAttributes};
188+
}
189+
190+
event.CustomFlags = customFlags;
191+
event.IntegrationAttributes = integrationAttributes;
192+
172193
appendUserInfo(getCurrentUser(), event);
194+
173195
return event;
174196
}
175197

test/src/tests-batchUploader.ts

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,129 @@ describe('batch uploader', () => {
374374
delete window.mParticle.config.appVersion;
375375
delete window.mParticle.config.package;
376376
});
377+
378+
it('should add integration attributes to AST event', async () => {
379+
window.mParticle.config.appName = 'Test App';
380+
window.mParticle.config.appVersion = '1.0.0';
381+
window.mParticle.config.package = 'com.test.app';
382+
383+
window.mParticle.config.identifyRequest = {
384+
userIdentities: {
385+
386+
}
387+
};
388+
389+
window.mParticle.config.flags.captureIntegrationSpecificIds = "True";
390+
391+
const consentState = window.mParticle.Consent.createConsentState();
392+
const timestamp = new Date().getTime();
393+
const ccpaConsent = window.mParticle.Consent.createCCPAConsent(
394+
true,
395+
timestamp,
396+
'consentDoc',
397+
'location',
398+
'hardware'
399+
);
400+
const gdprConsent = window.mParticle.Consent.createGDPRConsent(
401+
false,
402+
timestamp,
403+
'consentDoc',
404+
'location',
405+
'hardware'
406+
);
407+
consentState.setCCPAConsentState(ccpaConsent);
408+
consentState.addGDPRConsentState('test purpose', gdprConsent);
409+
410+
// Mock the query params capture function because we cannot mock window.location.href
411+
sinon.stub(window.mParticle.getInstance()._IntegrationCapture, 'getQueryParams').returns({
412+
rtid: 'test-click-id',
413+
});
414+
415+
window.mParticle.init(apiKey, window.mParticle.config);
416+
await waitForCondition(hasIdentifyReturned);
417+
window.mParticle.Identity.getCurrentUser().setUserAttribute('foo', 'value');
418+
const user = window.mParticle.Identity.getCurrentUser();
419+
user.setConsentState(consentState);
420+
421+
const now = Date.now();
422+
clock = sinon.useFakeTimers({
423+
now: now,
424+
shouldAdvanceTime: true
425+
});
426+
427+
// Mock navigator.sendBeacon
428+
beaconSpy = sinon.spy(navigator, 'sendBeacon');
429+
430+
// Trigger visibility change
431+
Object.defineProperty(document, 'visibilityState', {
432+
configurable: true,
433+
get: () => 'hidden'
434+
});
435+
document.dispatchEvent(new Event('visibilitychange'));
436+
437+
// Run all pending promises
438+
await Promise.resolve();
439+
clock.runAll();
440+
441+
// Verify that beacon was called
442+
expect(beaconSpy.calledOnce, 'Expected beacon to be called once').to.be.true;
443+
444+
// Get the beacon call data
445+
const beaconCall = beaconSpy.getCall(0);
446+
expect(beaconCall, 'Expected beacon call to exist').to.exist;
447+
448+
// Get the Blob from the beacon call
449+
const blob = beaconCall.args[1];
450+
expect(blob).to.be.instanceof(Blob);
451+
452+
// Read the Blob content
453+
const reader = new FileReader();
454+
const blobContent = await new Promise((resolve) => {
455+
reader.onload = () => resolve(reader.result);
456+
reader.readAsText(blob);
457+
});
458+
459+
// Parse the beacon data which is a batch
460+
const batch = JSON.parse(blobContent as string);
461+
expect(batch.user_identities.email).to.equal('[email protected]');
462+
expect(batch.user_attributes.foo).to.equal('value');
463+
expect(batch.application_info.application_name).to.equal('Test App');
464+
expect(batch.application_info.application_version).to.equal('1.0.0');
465+
expect(batch.application_info.package).to.equal('com.test.app');
466+
expect(batch.consent_state).to.have.property('ccpa');
467+
expect(batch.consent_state.ccpa).to.have.property('data_sale_opt_out');
468+
expect(batch.consent_state.ccpa.data_sale_opt_out).to.have.property('consented');
469+
expect(batch.consent_state.ccpa.data_sale_opt_out.consented).to.equal(true);
470+
expect(batch.consent_state.ccpa.data_sale_opt_out).to.have.property('timestamp_unixtime_ms');
471+
expect(batch.consent_state.ccpa.data_sale_opt_out).to.have.property('document');
472+
expect(batch.consent_state.gdpr).to.have.property('test purpose');
473+
expect(batch.consent_state.gdpr['test purpose']).to.have.property('consented');
474+
expect(batch.consent_state.gdpr['test purpose'].consented).to.equal(false);
475+
expect(batch.consent_state.gdpr['test purpose']).to.have.property('timestamp_unixtime_ms');
476+
expect(batch.consent_state.gdpr['test purpose']).to.have.property('document');
477+
expect(batch.integration_attributes).to.exist;
478+
expect(batch.integration_attributes['1277']).to.exist;
479+
expect(batch.integration_attributes['1277'].passbackconversiontrackingid).to.equal('test-click-id');
480+
481+
const astEvent = batch.events[batch.events.length - 1];
482+
483+
expect(astEvent.event_type).to.equal('application_state_transition');
484+
expect(astEvent.data.active_time_on_site_ms).to.be.a('number');
485+
expect(astEvent.data.application_transition_type).to.equal('application_background');
486+
expect(astEvent.data.custom_attributes).to.exist;
487+
expect(astEvent.data.is_first_run).to.be.a('boolean');
488+
expect(astEvent.data.is_upgrade).to.be.a('boolean');
489+
expect(astEvent.data.location).to.equal(null);
490+
expect(astEvent.data.session_start_unixtime_ms).to.be.a('number');
491+
expect(astEvent.data.session_uuid).to.exist;
492+
expect(astEvent.data.source_message_id).to.be.a('string');
493+
expect(astEvent.data.timestamp_unixtime_ms).to.be.a('number');
494+
495+
// reset to prevent other tests from potentially failing
496+
delete window.mParticle.config.appName;
497+
delete window.mParticle.config.appVersion;
498+
delete window.mParticle.config.package;
499+
});
377500
});
378501
});
379502

0 commit comments

Comments
 (0)