Skip to content

Commit 72b3e09

Browse files
committed
added tests for roktManager.hashAttributes in roktManager.spec.ts
1 parent e76cc77 commit 72b3e09

File tree

1 file changed

+94
-102
lines changed

1 file changed

+94
-102
lines changed

test/jest/roktManager.spec.ts

Lines changed: 94 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { IKitConfigs } from "../../src/configAPIClient";
22
import { IMParticleUser } from "../../src/identity-user-interfaces";
33
import { SDKIdentityApi } from "../../src/identity.interfaces";
44
import { IMParticleWebSDKInstance } from "../../src/mp-instance";
5-
import RoktManager, { IRoktKit, IRoktSelectPlacementsOptions } from "../../src/roktManager";
5+
import RoktManager, { IRoktKit, IRoktSelectPlacementsOptions, IRoktPartnerAttributes, IRoktLauncher, IRoktSelection } from "../../src/roktManager";
66
import { testMPID } from '../src/config/constants';
77

88
const resolvePromise = () => new Promise(resolve => setTimeout(resolve, 0));
@@ -76,82 +76,68 @@ describe('RoktManager', () => {
7676
});
7777

7878
describe('#hashAttributes', () => {
79+
interface Hasher {
80+
sha256Hex(input: string): Promise<string>
81+
}
82+
7983
beforeEach(() => {
8084
roktManager['currentUser'] = currentUser;
8185
});
8286

83-
it('should call kit.hashAttributes with empty attributes', () => {
84-
const kit: IRoktKit = {
85-
launcher: {
86-
selectPlacements: jest.fn(),
87-
hashAttributes: jest.fn(),
88-
use: jest.fn(),
89-
},
90-
filters: undefined,
91-
filteredUser: undefined,
92-
hashAttributes: jest.fn(),
93-
selectPlacements: jest.fn(),
94-
setExtensionData: jest.fn(),
95-
use: jest.fn(),
96-
userAttributes: undefined,
97-
};
98-
99-
roktManager.attachKit(kit);
87+
it('should not hash when calling roktManager.hashAttributes with empty attributes and no kit', async () => {
88+
const shaSpy = jest.spyOn(roktManager as unknown as Hasher, 'sha256Hex');
89+
const attributes: IRoktPartnerAttributes = {};
90+
const messageQueueSizeBefore = roktManager['messageQueue'].size;
91+
await roktManager.hashAttributes(attributes);
92+
const messageQueueSizeAfter = roktManager['messageQueue'].size;
93+
expect(messageQueueSizeAfter).toBe(messageQueueSizeBefore);
94+
expect(shaSpy).not.toHaveBeenCalled();
95+
shaSpy.mockRestore();
96+
});
10097

101-
const attributes = {};
98+
it('should hash when calling roktManager.hashAttributes without kit', async () => {
99+
const nodeCrypto = require('crypto');
100+
const shaSpy = jest.spyOn(roktManager as unknown as Hasher, 'sha256Hex');
101+
shaSpy.mockImplementation((s: any) =>
102+
Promise.resolve(nodeCrypto.createHash('sha256').update(String(s)).digest('hex')),
103+
);
102104

103-
roktManager.hashAttributes(attributes);
104-
expect(kit.hashAttributes).toHaveBeenCalledWith(attributes);
105-
});
105+
const attributes: IRoktPartnerAttributes = { email: '[email protected]', phone: ' 1234567890 ' };
106+
const messageQueueSizeBefore = roktManager['messageQueue'].size;
106107

107-
it('should call kit.hashAttributes with passed in attributes', () => {
108-
const kit: IRoktKit = {
109-
launcher: {
110-
selectPlacements: jest.fn(),
111-
hashAttributes: jest.fn(),
112-
use: jest.fn(),
113-
},
114-
filters: undefined,
115-
filteredUser: undefined,
116-
hashAttributes: jest.fn(),
117-
selectPlacements: jest.fn(),
118-
setExtensionData: jest.fn(),
119-
use: jest.fn(),
120-
userAttributes: undefined,
121-
};
108+
await roktManager.hashAttributes(attributes);
122109

123-
roktManager.attachKit(kit);
110+
const messageQueueSizeAfter = roktManager['messageQueue'].size;
111+
expect(messageQueueSizeAfter).toBe(messageQueueSizeBefore);
124112

125-
const attributes = {
126-
127-
phone: '1234567890'
128-
};
113+
expect(shaSpy).toHaveBeenCalledWith('[email protected]');
114+
expect(shaSpy).toHaveBeenCalledWith('1234567890');
115+
expect(shaSpy).toHaveBeenCalledTimes(2);
129116

130-
roktManager.hashAttributes(attributes);
131-
expect(kit.hashAttributes).toHaveBeenCalledWith(attributes);
117+
shaSpy.mockRestore();
132118
});
133119

134-
it('should queue the hashAttributes method if no launcher or kit is attached', () => {
135-
const attributes = {
136-
137-
};
120+
it('should not queue when calling roktManager.hashAttributes with no kit attached', async () => {
121+
const shaSpy = jest.spyOn(roktManager as unknown as Hasher, 'sha256Hex').mockResolvedValue('deadbeef');
138122

139-
roktManager.hashAttributes(attributes);
123+
const attributes: IRoktPartnerAttributes = { email: '[email protected]' };
124+
const messageQueueSizeBefore = roktManager['messageQueue'].size;
125+
await roktManager.hashAttributes(attributes);
126+
const messageQueueSizeAfter = roktManager['messageQueue'].size;
127+
expect(messageQueueSizeAfter).toBe(messageQueueSizeBefore);
140128

141-
expect(roktManager['kit']).toBeNull();
142-
expect(roktManager['messageQueue'].size).toBe(1);
143-
const queuedMessage = Array.from(roktManager['messageQueue'].values())[0];
144-
expect(queuedMessage.methodName).toBe('hashAttributes');
145-
expect(queuedMessage.payload).toBe(attributes);
129+
shaSpy.mockRestore();
146130
});
147131

148-
it('should process queued hashAttributes calls once the launcher and kit are attached', () => {
132+
it('should remain non-deferred before and after attaching kit', async () => {
133+
const nodeCrypto = require('crypto');
134+
const shaSpy = jest.spyOn(roktManager as unknown as Hasher, 'sha256Hex');
135+
shaSpy.mockImplementation((s: any) =>
136+
Promise.resolve(nodeCrypto.createHash('sha256').update(String(s)).digest('hex')),
137+
);
138+
149139
const kit: IRoktKit = {
150-
launcher: {
151-
selectPlacements: jest.fn(),
152-
hashAttributes: jest.fn(),
153-
use: jest.fn(),
154-
},
140+
launcher: { selectPlacements: jest.fn(), hashAttributes: jest.fn(), use: jest.fn() },
155141
filters: undefined,
156142
filteredUser: undefined,
157143
hashAttributes: jest.fn(),
@@ -161,52 +147,55 @@ describe('RoktManager', () => {
161147
userAttributes: undefined,
162148
};
163149

164-
const attributes = {
165-
166-
};
150+
const attributes: IRoktPartnerAttributes = { email: '[email protected]' };
167151

168-
roktManager.hashAttributes(attributes);
169-
expect(roktManager['kit']).toBeNull();
170-
expect(roktManager['messageQueue'].size).toBe(1);
171-
const queuedMessage = Array.from(roktManager['messageQueue'].values())[0];
172-
expect(queuedMessage.methodName).toBe('hashAttributes');
173-
expect(queuedMessage.payload).toBe(attributes);
174-
expect(kit.hashAttributes).not.toHaveBeenCalled();
152+
const sizeBefore = roktManager['messageQueue'].size;
153+
await roktManager.hashAttributes(attributes);
154+
expect(roktManager['messageQueue'].size).toBe(sizeBefore);
175155

176156
roktManager.attachKit(kit);
177-
expect(roktManager['kit']).not.toBeNull();
178-
expect(roktManager['messageQueue'].size).toBe(0);
179-
expect(kit.hashAttributes).toHaveBeenCalledWith(attributes);
157+
const sizeAfterAttach = roktManager['messageQueue'].size;
158+
await roktManager.hashAttributes(attributes);
159+
expect(roktManager['messageQueue'].size).toBe(sizeAfterAttach);
160+
161+
shaSpy.mockRestore();
180162
});
181163

182-
it('should pass through the correct attributes to kit.launcher.hashAttributes', async () => {
164+
it('should allow calling launcher.hashAttributes directly when kit is attached', async () => {
165+
const launcher: IRoktLauncher = {
166+
selectPlacements: jest.fn().mockResolvedValue({ close: jest.fn(), getPlacements: jest.fn().mockResolvedValue([]) } as unknown as IRoktSelection),
167+
hashAttributes: jest.fn(),
168+
use: jest.fn().mockResolvedValue(undefined as unknown as never),
169+
};
183170
const kit: Partial<IRoktKit> = {
184-
launcher: {
185-
selectPlacements: jest.fn(),
186-
hashAttributes: jest.fn(),
187-
use: jest.fn(),
188-
},
189-
190-
// We are mocking the hashAttributes method to return the
191-
// launcher's hashAttributes method and verify that
192-
// both the kit's and the launcher's methods
193-
// are called with the correct attributes.
194-
// This will happen through the Web Kit's hashAttributes method
195-
hashAttributes: jest.fn().mockImplementation((attributes) => {
196-
return kit.launcher.hashAttributes(attributes);
197-
})
171+
launcher,
172+
hashAttributes: jest.fn(),
198173
};
199-
200174
roktManager.attachKit(kit as IRoktKit);
175+
const attributes: IRoktPartnerAttributes = { email: '[email protected]', phone: '1234567890' };
176+
await launcher.hashAttributes(attributes);
177+
expect(launcher.hashAttributes).toHaveBeenCalledWith(attributes);
178+
});
201179

202-
const attributes = {
203-
204-
phone: '1234567890'
205-
};
206-
207-
roktManager.hashAttributes(attributes);
208-
expect(kit.hashAttributes).toHaveBeenCalledWith(attributes);
209-
expect(kit.launcher.hashAttributes).toHaveBeenCalledWith(attributes);
180+
it('should match node crypto output', async () => {
181+
const nodeCrypto = require('crypto');
182+
const shaSpy = jest.spyOn(roktManager as unknown as Hasher, 'sha256Hex');
183+
shaSpy.mockImplementation((s: any) =>
184+
Promise.resolve(nodeCrypto.createHash('sha256').update(String(s)).digest('hex')),
185+
);
186+
const attributes: IRoktPartnerAttributes = {
187+
email: ' [email protected] ',
188+
phone: ' 1234567890 ',
189+
blank: ' ',
190+
};
191+
const fromManager = await roktManager.hashAttributes(attributes);
192+
const expected = {
193+
emailsha256: nodeCrypto.createHash('sha256').update('[email protected]').digest('hex'),
194+
phonesha256: nodeCrypto.createHash('sha256').update('1234567890').digest('hex'),
195+
blanksha256: nodeCrypto.createHash('sha256').update('').digest('hex'),
196+
};
197+
expect(fromManager).toStrictEqual(expected);
198+
shaSpy.mockRestore();
210199
});
211200
});
212201

@@ -543,22 +532,20 @@ describe('RoktManager', () => {
543532
expect(kit.selectPlacements).toHaveBeenCalledTimes(3);
544533
});
545534

546-
it('should call RoktManager methods (not kit methods directly) when processing queue', () => {
535+
it('should call RoktManager methods (not kit methods directly) when processing queue', async () => {
547536
// Queue some calls before kit is ready (these will be deferred)
548537
const selectOptions = { attributes: { test: 'value' } } as IRoktSelectPlacementsOptions;
549538
const hashAttrs = { email: '[email protected]' };
550539
const extensionData = { 'test-ext': { config: true } };
551540
const useName = 'TestExtension';
552541

553542
roktManager.selectPlacements(selectOptions);
554-
roktManager.hashAttributes(hashAttrs);
555543
roktManager.setExtensionData(extensionData);
556544
roktManager.use(useName);
557545

558546
// Verify calls were queued
559-
expect(roktManager['messageQueue'].size).toBe(4);
547+
expect(roktManager['messageQueue'].size).toBe(3);
560548
expect(kit.selectPlacements).not.toHaveBeenCalled(); // Kit methods not called yet
561-
expect(kit.hashAttributes).not.toHaveBeenCalled(); // Kit methods not called yet
562549
expect(kit.setExtensionData).not.toHaveBeenCalled(); // Kit methods not called yet
563550
expect(kit.use).not.toHaveBeenCalled(); // Kit methods not called yet
564551

@@ -568,6 +555,8 @@ describe('RoktManager', () => {
568555
const setExtensionDataSpy = jest.spyOn(roktManager, 'setExtensionData');
569556
const useSpy = jest.spyOn(roktManager, 'use');
570557

558+
const shaSpy = jest.spyOn(roktManager as any, 'sha256Hex').mockResolvedValue('deadbeef');
559+
await roktManager.hashAttributes(hashAttrs);
571560
// Attach kit (triggers processMessageQueue)
572561
roktManager.attachKit(kit);
573562

@@ -577,7 +566,7 @@ describe('RoktManager', () => {
577566

578567
expect(hashAttributesSpy).toHaveBeenCalledTimes(1);
579568
expect(hashAttributesSpy).toHaveBeenCalledWith(hashAttrs);
580-
569+
581570
expect(setExtensionDataSpy).toHaveBeenCalledTimes(1);
582571
expect(setExtensionDataSpy).toHaveBeenCalledWith(extensionData);
583572

@@ -592,6 +581,7 @@ describe('RoktManager', () => {
592581
hashAttributesSpy.mockRestore();
593582
setExtensionDataSpy.mockRestore();
594583
useSpy.mockRestore();
584+
shaSpy.mockRestore();
595585
});
596586

597587
it('should preserve RoktManager preprocessing logic when processing deferred selectPlacements calls', () => {
@@ -747,6 +737,7 @@ describe('RoktManager', () => {
747737
});
748738

749739
it('should process queued selectPlacements calls once the launcher and kit are attached', async () => {
740+
const shaSpy = jest.spyOn(roktManager as any, 'sha256Hex').mockResolvedValue('deadbeef');
750741
const expectedResult = { placements: ['placement1', 'placement2'] };
751742
const kit: IRoktKit = {
752743
launcher: {
@@ -793,6 +784,7 @@ describe('RoktManager', () => {
793784
expect(roktManager['messageQueue'].size).toBe(0);
794785
expect(kit.selectPlacements).toHaveBeenCalledWith(options);
795786
expect(result).toEqual(expectedResult);
787+
shaSpy.mockRestore();
796788
});
797789

798790
it('should pass through the correct attributes to kit.selectPlacements', () => {

0 commit comments

Comments
 (0)