Skip to content

Commit c6e9dd5

Browse files
[FSSDK-9082] [React] Handle Null and Empty Values in sendOdpEvent method (#200)
* Add sendOdpEvent * Update copyright * Add comma * Revert package json for linux env * Update cp * Fix tests * Update copyright * Update copyright * Update vuid * Add missing access-modifiers * Add sendOdpEvent tests
1 parent 215d3fe commit c6e9dd5

File tree

2 files changed

+66
-38
lines changed

2 files changed

+66
-38
lines changed

src/client.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,4 +1558,27 @@ describe('ReactSDKClient', () => {
15581558
});
15591559
});
15601560
});
1561+
1562+
describe('sendOdpEvent', () => {
1563+
let instance: ReactSDKClient;
1564+
beforeEach(() => {
1565+
instance = createInstance(config);
1566+
});
1567+
1568+
it('should throw error when action param is falsy', async () => {
1569+
const badValues = ['', ' '];
1570+
badValues.forEach(item => {
1571+
instance.sendOdpEvent(item);
1572+
});
1573+
1574+
expect(logger.error).toHaveBeenCalledTimes(badValues.length);
1575+
expect(logger.error).toBeCalledWith('ODP action is not valid (cannot be empty).');
1576+
});
1577+
1578+
it('should call sendOdpEvent once', async () => {
1579+
instance.sendOdpEvent('test');
1580+
1581+
expect(mockInnerClient.sendOdpEvent).toHaveBeenCalledTimes(1);
1582+
});
1583+
});
15611584
});

src/client.ts

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,6 @@ export interface ReactSDKClient extends Omit<optimizely.Client, 'createUserConte
177177
export const DEFAULT_ON_READY_TIMEOUT = 5000;
178178

179179
class OptimizelyReactSDKClient implements ReactSDKClient {
180-
public initialConfig: optimizely.Config;
181-
public user: UserInfo = {
182-
id: null,
183-
attributes: {},
184-
};
185180
private userContext: optimizely.OptimizelyUserContext | null = null;
186181
private userPromiseResolver: (user: UserInfo) => void;
187182
private userPromise: Promise<OnReadyResult>;
@@ -207,6 +202,12 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
207202
// promise keeping track of async requests for initializing client instance
208203
private dataReadyPromise: Promise<OnReadyResult>;
209204

205+
public initialConfig: optimizely.Config;
206+
public user: UserInfo = {
207+
id: null,
208+
attributes: {},
209+
};
210+
210211
/**
211212
* Creates an instance of OptimizelyReactSDKClient.
212213
* @param {optimizely.Config} [config={}]
@@ -258,15 +259,29 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
258259
}
259260
}
260261

261-
getIsReadyPromiseFulfilled(): boolean {
262+
protected getUserContextWithOverrides(
263+
overrideUserId?: string,
264+
overrideAttributes?: optimizely.UserAttributes
265+
): UserInfo {
266+
const finalUserId: string | null = overrideUserId === undefined ? this.user.id : overrideUserId;
267+
const finalUserAttributes: optimizely.UserAttributes | undefined =
268+
overrideAttributes === undefined ? this.user.attributes : overrideAttributes;
269+
270+
return {
271+
id: finalUserId,
272+
attributes: finalUserAttributes,
273+
};
274+
}
275+
276+
public getIsReadyPromiseFulfilled(): boolean {
262277
return this.isReadyPromiseFulfilled;
263278
}
264279

265-
getIsUsingSdkKey(): boolean {
280+
public getIsUsingSdkKey(): boolean {
266281
return this.isUsingSdkKey;
267282
}
268283

269-
onReady(config: { timeout?: number } = {}): Promise<OnReadyResult> {
284+
public onReady(config: { timeout?: number } = {}): Promise<OnReadyResult> {
270285
let timeoutId: number | undefined;
271286
let timeout: number = DEFAULT_ON_READY_TIMEOUT;
272287
if (config && config.timeout !== undefined) {
@@ -291,7 +306,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
291306
});
292307
}
293308

294-
getUserContextInstance(userInfo: UserInfo): optimizely.OptimizelyUserContext | null {
309+
public getUserContextInstance(userInfo: UserInfo): optimizely.OptimizelyUserContext | null {
295310
if (!this._client) {
296311
logger.warn(
297312
'Unable to get user context for user id "%s" because Optimizely client failed to initialize.',
@@ -323,7 +338,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
323338
return null;
324339
}
325340

326-
async fetchQualifiedSegments(): Promise<boolean> {
341+
public async fetchQualifiedSegments(): Promise<boolean> {
327342
if (!this.userContext) {
328343
logger.warn('Unable to fetch qualified segments for user because Optimizely client failed to initialize.');
329344
return false;
@@ -332,7 +347,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
332347
return await this.userContext.fetchQualifiedSegments();
333348
}
334349

335-
setUser(userInfo: UserInfo): void {
350+
public setUser(userInfo: UserInfo): void {
336351
// TODO add check for valid user
337352
if (userInfo.id) {
338353
this.user.id = userInfo.id;
@@ -360,7 +375,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
360375
this.onUserUpdateHandlers.forEach(handler => handler(this.user));
361376
}
362377

363-
onUserUpdate(handler: OnUserUpdateHandler): DisposeFn {
378+
public onUserUpdate(handler: OnUserUpdateHandler): DisposeFn {
364379
this.onUserUpdateHandlers.push(handler);
365380

366381
return () => {
@@ -377,7 +392,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
377392
* @param {OnForcedVariationsUpdateHandler} handler
378393
* @returns {DisposeFn}
379394
*/
380-
onForcedVariationsUpdate(handler: OnForcedVariationsUpdateHandler): DisposeFn {
395+
public onForcedVariationsUpdate(handler: OnForcedVariationsUpdateHandler): DisposeFn {
381396
this.onForcedVariationsUpdateHandlers.push(handler);
382397

383398
return (): void => {
@@ -388,7 +403,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
388403
};
389404
}
390405

391-
isReady(): boolean {
406+
public isReady(): boolean {
392407
// React SDK Instance only becomes ready when both JS SDK client and the user info is ready.
393408
return this.isUserReady && this.isClientReady;
394409
}
@@ -952,7 +967,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
952967
* @returns {(unknown | null)}
953968
* @memberof OptimizelyReactSDKClient
954969
*/
955-
getFeatureVariable(
970+
public getFeatureVariable(
956971
featureKey: string,
957972
variableKey: string,
958973
overrideUserId: string,
@@ -989,7 +1004,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
9891004
* @returns {({ [variableKey: string]: unknown } | null)}
9901005
* @memberof OptimizelyReactSDKClient
9911006
*/
992-
getAllFeatureVariables(
1007+
public getAllFeatureVariables(
9931008
featureKey: string,
9941009
overrideUserId: string,
9951010
overrideAttributes?: optimizely.UserAttributes
@@ -1174,33 +1189,23 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
11741189
return this._client.notificationCenter;
11751190
}
11761191

1177-
protected getUserContextWithOverrides(
1178-
overrideUserId?: string,
1179-
overrideAttributes?: optimizely.UserAttributes
1180-
): UserInfo {
1181-
const finalUserId: string | null = overrideUserId === undefined ? this.user.id : overrideUserId;
1182-
const finalUserAttributes: optimizely.UserAttributes | undefined =
1183-
overrideAttributes === undefined ? this.user.attributes : overrideAttributes;
1184-
1185-
return {
1186-
id: finalUserId,
1187-
attributes: finalUserAttributes,
1188-
};
1189-
}
1190-
1191-
// TODO: discuss if we want to expose these method and provide implementation
1192-
getVuid(): string | undefined {
1192+
// TODO: this is tobe removed in future once the js-sdk gets updated
1193+
public getVuid(): string | undefined {
11931194
return undefined;
11941195
}
11951196

1196-
// TODO: discuss if we want to expose these method and provide implementation
1197-
sendOdpEvent(
1197+
public sendOdpEvent(
11981198
action: string,
1199-
type: string | undefined,
1200-
identifiers: Map<string, string> | undefined,
1201-
data: Map<string, unknown> | undefined
1199+
type?: string,
1200+
identifiers?: Map<string, string>,
1201+
data?: Map<string, unknown>
12021202
): void {
1203-
// no-op
1203+
if (!action || !action.trim()) {
1204+
logger.error('ODP action is not valid (cannot be empty).');
1205+
return;
1206+
}
1207+
1208+
this.client?.sendOdpEvent(action, type, identifiers, data);
12041209
}
12051210
}
12061211

0 commit comments

Comments
 (0)