Skip to content

Commit 150779e

Browse files
[FSSDK-12274] user context manager + Provider adjustment (#317)
1 parent 8e43d1f commit 150779e

15 files changed

Lines changed: 2049 additions & 35 deletions

src/client/client.spec.ts

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@
1717
import { vi, describe, it, expect, beforeEach, type MockedFunction } from 'vitest';
1818
import { createInstance as jsCreateInstance } from '@optimizely/optimizely-sdk';
1919
import type { Config } from '@optimizely/optimizely-sdk';
20-
import { createInstance, CLIENT_ENGINE, CLIENT_VERSION } from './createInstance';
20+
import { createInstance, CLIENT_ENGINE, CLIENT_VERSION, REACT_CLIENT_META } from './createInstance';
21+
import type { ReactClientMeta } from './createInstance';
22+
23+
type ClientWithMeta = Record<symbol, ReactClientMeta>;
24+
25+
const mockJsClient = vi.hoisted(() => ({
26+
onReady: vi.fn().mockResolvedValue(undefined),
27+
createUserContext: vi.fn(),
28+
close: vi.fn(),
29+
}));
2130

2231
vi.mock('@optimizely/optimizely-sdk', () => ({
23-
createInstance: vi.fn().mockReturnValue({
24-
onReady: vi.fn().mockResolvedValue(undefined),
25-
createUserContext: vi.fn(),
26-
close: vi.fn(),
27-
}),
32+
createInstance: vi.fn().mockReturnValue(mockJsClient),
2833
}));
2934

3035
const mockedJsCreateInstance = jsCreateInstance as MockedFunction<typeof jsCreateInstance>;
@@ -51,4 +56,51 @@ describe('createInstance', () => {
5156
);
5257
});
5358
});
59+
60+
describe('prototype delegation', () => {
61+
it('should return an object that delegates to the JS SDK client', () => {
62+
const client = createInstance(createTestConfig());
63+
// Methods from the JS client should be accessible via prototype chain
64+
expect(client.onReady).toBe(mockJsClient.onReady);
65+
expect(client.createUserContext).toBe(mockJsClient.createUserContext);
66+
expect(client.close).toBe(mockJsClient.close);
67+
});
68+
69+
it('should have the JS SDK client as its prototype', () => {
70+
const client = createInstance(createTestConfig());
71+
expect(Object.getPrototypeOf(client)).toBe(mockJsClient);
72+
});
73+
});
74+
75+
describe('REACT_CLIENT_META', () => {
76+
it('should set hasOdpManager to false when odpManager is not provided', () => {
77+
const client = createInstance(createTestConfig());
78+
const meta = (client as unknown as ClientWithMeta)[REACT_CLIENT_META];
79+
expect(meta.hasOdpManager).toBe(false);
80+
});
81+
82+
it('should set hasOdpManager to true when odpManager is provided', () => {
83+
const client = createInstance(createTestConfig({ odpManager: {} as Config['odpManager'] }));
84+
const meta = (client as unknown as ClientWithMeta)[REACT_CLIENT_META];
85+
expect(meta.hasOdpManager).toBe(true);
86+
});
87+
88+
it('should set hasVuidManager to false when vuidManager is not provided', () => {
89+
const client = createInstance(createTestConfig());
90+
const meta = (client as unknown as ClientWithMeta)[REACT_CLIENT_META];
91+
expect(meta.hasVuidManager).toBe(false);
92+
});
93+
94+
it('should set hasVuidManager to true when vuidManager is provided', () => {
95+
const client = createInstance(createTestConfig({ vuidManager: {} as Config['vuidManager'] }));
96+
const meta = (client as unknown as ClientWithMeta)[REACT_CLIENT_META];
97+
expect(meta.hasVuidManager).toBe(true);
98+
});
99+
100+
it('should store meta on the react client, not on the prototype', () => {
101+
const client = createInstance(createTestConfig());
102+
expect(Object.prototype.hasOwnProperty.call(client, REACT_CLIENT_META)).toBe(true);
103+
expect(Object.prototype.hasOwnProperty.call(mockJsClient, REACT_CLIENT_META)).toBe(false);
104+
});
105+
});
54106
});

src/client/createInstance.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,35 @@ import type { Config, Client } from '@optimizely/optimizely-sdk';
2020
export const CLIENT_ENGINE = 'react-sdk';
2121
export const CLIENT_VERSION = '4.0.0';
2222

23+
export const REACT_CLIENT_META = Symbol('react-client-meta');
24+
25+
export interface ReactClientMeta {
26+
hasOdpManager: boolean;
27+
hasVuidManager: boolean;
28+
}
29+
2330
/**
2431
* Creates an Optimizely client instance for use with React SDK.
2532
*
33+
* Uses prototype delegation so the returned object inherits all methods
34+
* from the JS SDK client while carrying React-specific metadata.
35+
*
2636
* @param config - Configuration object for the Optimizely client
27-
* @returns An OptimizelyClient instance
37+
* @returns An OptimizelyClient instance with React SDK metadata
2838
*/
2939
export function createInstance(config: Config): Client {
30-
return jsCreateInstance({
40+
const jsClient = jsCreateInstance({
3141
...config,
3242
clientEngine: CLIENT_ENGINE,
3343
clientVersion: CLIENT_VERSION,
3444
});
45+
46+
const reactClient = Object.create(jsClient);
47+
48+
reactClient[REACT_CLIENT_META] = {
49+
hasOdpManager: !!config.odpManager,
50+
hasVuidManager: !!config.vuidManager,
51+
} satisfies ReactClientMeta;
52+
53+
return reactClient;
3554
}

src/client/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17-
export { createInstance } from './createInstance';
17+
export { createInstance, REACT_CLIENT_META } from './createInstance';
18+
export type { ReactClientMeta } from './createInstance';
1819

1920
export type * from '@optimizely/optimizely-sdk';
2021

src/index.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,21 @@
1414
* limitations under the License.
1515
*/
1616

17-
// Client - re-export everything
18-
export * from './client';
17+
export {
18+
createInstance,
19+
createPollingProjectConfigManager,
20+
createStaticProjectConfigManager,
21+
createBatchEventProcessor,
22+
createForwardingEventProcessor,
23+
createOdpManager,
24+
createVuidManager,
25+
createErrorNotifier,
26+
createLogger
27+
} from './client/index';
28+
29+
export type * from "@optimizely/optimizely-sdk";
1930

2031
// Provider
32+
// Todo: Remove OptimizelyContext export in future
2133
export { OptimizelyProvider } from './provider/index';
2234
export type { UserInfo, OptimizelyProviderProps } from './provider/index';

0 commit comments

Comments
 (0)