Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions lib/odp/odp_manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ describe('DefaultOdpManager', () => {
expect(identifiers).toEqual(new Map([['fs_user_id', 'user'], ['vuid', 'vuid_a']]));
});

it('sends identified event when called with just fs_user_id in first parameter', async () => {
it('does not send identified event when called with just fs_user_id and no stored vuid', async () => {
const eventManager = getMockOdpEventManager();
eventManager.onRunning.mockReturnValue(Promise.resolve());

Expand All @@ -634,12 +634,10 @@ describe('DefaultOdpManager', () => {
await odpManager.onRunning();

odpManager.identifyUser('user');
expect(mockSendEvents).toHaveBeenCalledOnce();
const { identifiers } = mockSendEvents.mock.calls[0][0];
expect(identifiers).toEqual(new Map([['fs_user_id', 'user']]));
expect(mockSendEvents).not.toHaveBeenCalled();
});

it('sends identified event when called with just vuid in first parameter', async () => {
it('does not send identified event when called with just vuid in first parameter and no stored vuid', async () => {
const eventManager = getMockOdpEventManager();
eventManager.onRunning.mockReturnValue(Promise.resolve());

Expand All @@ -655,9 +653,73 @@ describe('DefaultOdpManager', () => {
await odpManager.onRunning();

odpManager.identifyUser('vuid_a');
expect(mockSendEvents).not.toHaveBeenCalled();
});

it('sends identified event when called with fs_user_id and stored vuid is available', async () => {
const eventManager = getMockOdpEventManager();
eventManager.onRunning.mockReturnValue(Promise.resolve());

const mockSendEvents = vi.mocked(eventManager.sendEvent as OdpEventManager['sendEvent']);

const odpManager = new DefaultOdpManager({
segmentManager: getMockOdpSegmentManager(),
eventManager,
});

odpManager.start();
odpManager.updateConfig({ integrated: true, odpConfig: config });
await odpManager.onRunning();

// Set stored vuid first so identifyUser has 2 identifiers
odpManager.setVuid('vuid_stored');

// Clear the sendEvent calls from setVuid's client_initialized event
mockSendEvents.mockClear();

odpManager.identifyUser('user');
expect(mockSendEvents).toHaveBeenCalledOnce();
const { identifiers } = mockSendEvents.mock.calls[0][0];
expect(identifiers).toEqual(new Map([['vuid', 'vuid_a']]));
expect(identifiers).toEqual(new Map([['fs_user_id', 'user'], ['vuid', 'vuid_stored']]));
});

it('does not count empty identifier values toward the minimum', async () => {
const eventManager = getMockOdpEventManager();
eventManager.onRunning.mockReturnValue(Promise.resolve());

const mockSendEvents = vi.mocked(eventManager.sendEvent as OdpEventManager['sendEvent']);

const odpManager = new DefaultOdpManager({
segmentManager: getMockOdpSegmentManager(),
eventManager,
});

odpManager.start();
odpManager.updateConfig({ integrated: true, odpConfig: config });
await odpManager.onRunning();

// Call with fs_user_id and empty vuid - should not send (only 1 valid identifier)
odpManager.identifyUser('user', '');
expect(mockSendEvents).not.toHaveBeenCalled();
});

it('logs debug message when skipping identify event due to single identifier', async () => {
const eventManager = getMockOdpEventManager();
eventManager.onRunning.mockReturnValue(Promise.resolve());

const logger = getMockLogger();
const odpManager = new DefaultOdpManager({
logger,
segmentManager: getMockOdpSegmentManager(),
eventManager,
});

odpManager.start();
odpManager.updateConfig({ integrated: true, odpConfig: config });
await odpManager.onRunning();

odpManager.identifyUser('user');
expect(logger.debug).toHaveBeenCalledWith('ODP identify event is not dispatched (only one identifier provided).');
});

it('should reject onRunning() if stopped in new state', async () => {
Expand Down
23 changes: 21 additions & 2 deletions lib/odp/odp_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export class DefaultOdpManager extends BaseService implements OdpManager {

identifyUser(userId: string, vuid?: string): void {
const identifiers = new Map<string, string>();

let finalUserId: Maybe<string> = userId;
let finalVuid: Maybe<string> = vuid;

Expand All @@ -229,7 +229,26 @@ export class DefaultOdpManager extends BaseService implements OdpManager {
identifiers.set(ODP_USER_KEY.FS_USER_ID, finalUserId);
}

const event = new OdpEvent(ODP_DEFAULT_EVENT_TYPE, ODP_EVENT_ACTION.IDENTIFIED, identifiers);
// Include stored vuid if not already present to get accurate identifier count
if (!identifiers.has(ODP_USER_KEY.VUID) && this.vuid) {
identifiers.set(ODP_USER_KEY.VUID, this.vuid);
}

// Filter out identifiers with empty/null values
const validIdentifiers = new Map<string, string>();
identifiers.forEach((value, key) => {
if (value) {
validIdentifiers.set(key, value);
}
});

// Only send identify event when there are 2+ valid identifiers to link
if (validIdentifiers.size < 2) {
this.logger?.debug('ODP identify event is not dispatched (only one identifier provided).');
return;
}

const event = new OdpEvent(ODP_DEFAULT_EVENT_TYPE, ODP_EVENT_ACTION.IDENTIFIED, validIdentifiers);
this.sendEvent(event);
}

Expand Down
Loading