Skip to content

Commit fae169f

Browse files
mikechu-optimizelyMike Chu
and
Mike Chu
authored
[FSSDK-9984] fix: initialization and setUser errors (#255)
* fix: remove successful fetch requirement for onReady * Revert "fix: remove successful fetch requirement for onReady" This reverts commit 566daaf. * fix: error with OnReadyResult being undefined * fix: setUser should use VUID if possible * revert: timeout of undefined * docs: update copyright year * revert: Provider.tsx copyright since no code change * build: bump JS SDK version * refactor: `res` should never be `undefined` * docs: add clarifying comment * revert: retrieval & use of current user context * wip: partial solution; needs collab * refactor: setUser logic updated * revert: move setUser back to Provider constructor * style: remove commented code * fix: fetchQualifiedSegments under SSR/sync scenario * ci: VS Code jest settings to run via extension * test: use NotReadyReason enum * test: use NotReadyReason & add missing getUserId in mock user context * fix: add onInitStateChange for default ready result * fix: logic in Promise.all user & client readiness * refactor: isReady() to isReactClientReady() * test: fixes for uses of getUserId() in setUser() * wip: fixing tests * wip: fixed more tests * revert: refactor of isReactClientReady() * docs: Update copyrights * fix: later setUser not getting new usercontext (manual testing) * fix: PR review changes * test: add initial OptimizelyProvider tests * fix: PR review changes * docs: add clarification inline comments * build: bump underlying JS SDK version to 5.3.0 * fix: add missing getProjectConfig() from JS SDK * refactor: omit getProjectConfig instead of implementing it * style: remove unused import --------- Co-authored-by: Mike Chu <[email protected]>
1 parent a87fe08 commit fae169f

10 files changed

+347
-123
lines changed

.vscode/launch.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"type": "node",
6+
"name": "vscode-jest-tests.v2.react-sdk",
7+
"request": "launch",
8+
"args": [
9+
"--runInBand",
10+
"--watchAll=false",
11+
"--testNamePattern",
12+
"${jest.testNamePattern}",
13+
"--runTestsByPath",
14+
"${jest.testFile}"
15+
],
16+
"cwd": "${workspaceFolder}",
17+
"console": "integratedTerminal",
18+
"internalConsoleOptions": "neverOpen",
19+
"program": "${workspaceFolder}/node_modules/.bin/jest",
20+
"windows": {
21+
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
22+
}
23+
}
24+
]
25+
}

.vscode/settings.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{
2-
"jest.autoRun": {
3-
"onStartup": ["all-tests"]
4-
}
2+
"jest.runMode": "on-demand",
3+
"jest.jestCommandLine": "~/.nvm/nvm-exec yarn test"
54
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"access": "public"
3535
},
3636
"dependencies": {
37-
"@optimizely/optimizely-sdk": "^5.2.0",
37+
"@optimizely/optimizely-sdk": "^5.3.0",
3838
"hoist-non-react-statics": "^3.3.0",
3939
"prop-types": "^15.6.2",
4040
"utility-types": "^2.1.0 || ^3.0.0"

src/Feature.spec.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2018-2019, 2023 Optimizely
2+
* Copyright 2018-2019, 2023-2024 Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import { render, screen, waitFor } from '@testing-library/react';
2222
import '@testing-library/jest-dom/extend-expect';
2323

2424
import { OptimizelyProvider } from './Provider';
25-
import { ReactSDKClient, VariableValuesObject } from './client';
25+
import { NotReadyReason, ReactSDKClient, VariableValuesObject } from './client';
2626
import { OptimizelyFeature } from './Feature';
2727

2828
describe('<OptimizelyFeature>', () => {
@@ -298,7 +298,7 @@ describe('<OptimizelyFeature>', () => {
298298

299299
// while it's waiting for onReady()
300300
expect(container.innerHTML).toBe('');
301-
resolver.resolve({ success: false, reason: 'fail', dataReadyPromise: Promise.resolve() });
301+
resolver.resolve({ success: false, reason: NotReadyReason.TIMEOUT, dataReadyPromise: Promise.resolve() });
302302

303303
// Simulate config update notification firing after datafile fetched
304304
await optimizelyMock.onReady().then(res => res.dataReadyPromise);

src/Provider.spec.tsx

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* Copyright 2024 Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/// <reference types="jest" />
18+
19+
//jest.mock('./client');
20+
21+
import React from 'react';
22+
import { render, act } from '@testing-library/react';
23+
import { OptimizelyProvider } from './Provider';
24+
import { DefaultUser, ReactSDKClient, createInstance } from './client';
25+
26+
describe('OptimizelyProvider', () => {
27+
let mockReactClient: ReactSDKClient;
28+
const config = {
29+
datafile: {},
30+
};
31+
32+
beforeEach(() => {
33+
mockReactClient = ({
34+
user: {
35+
id: 'test-id',
36+
attributes: {},
37+
},
38+
setUser: jest.fn().mockResolvedValue(undefined),
39+
} as unknown) as ReactSDKClient;
40+
});
41+
42+
it('should render successfully with user provided', () => {
43+
act(() => {
44+
render(<OptimizelyProvider optimizely={mockReactClient} user={{ id: 'user1' }} />);
45+
});
46+
47+
expect(mockReactClient.setUser).toHaveBeenCalledWith({
48+
id: 'user1',
49+
attributes: {},
50+
});
51+
});
52+
53+
it('should render successfully with userId provided', () => {
54+
act(() => {
55+
render(<OptimizelyProvider optimizely={mockReactClient} userId="user1" />);
56+
});
57+
58+
expect(mockReactClient.setUser).toHaveBeenCalledWith({
59+
id: 'user1',
60+
attributes: {},
61+
});
62+
});
63+
64+
it('should render successfully without user or userId provided', () => {
65+
act(() => {
66+
render(<OptimizelyProvider optimizely={mockReactClient} />);
67+
});
68+
69+
expect(mockReactClient.setUser).toHaveBeenCalledWith(DefaultUser);
70+
});
71+
72+
it('should render successfully with user id & attributes provided', () => {
73+
act(() => {
74+
render(
75+
<OptimizelyProvider optimizely={mockReactClient} user={{ id: 'user1', attributes: { attr1: 'value1' } }} />
76+
);
77+
});
78+
79+
expect(mockReactClient.setUser).toHaveBeenCalledWith({
80+
id: 'user1',
81+
attributes: { attr1: 'value1' },
82+
});
83+
});
84+
85+
it('should succeed just userAttributes provided', () => {
86+
act(() => {
87+
render(<OptimizelyProvider optimizely={mockReactClient} userAttributes={{ attr1: 'value1' }} />);
88+
});
89+
90+
expect(mockReactClient.setUser).toHaveBeenCalledWith({
91+
id: DefaultUser.id,
92+
attributes: { attr1: 'value1' },
93+
});
94+
});
95+
});

src/Provider.tsx

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2022-2023, Optimizely
2+
* Copyright 2022-2024, Optimizely
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,9 +43,7 @@ interface OptimizelyProviderState {
4343
export class OptimizelyProvider extends React.Component<OptimizelyProviderProps, OptimizelyProviderState> {
4444
constructor(props: OptimizelyProviderProps) {
4545
super(props);
46-
}
4746

48-
componentDidMount(): void {
4947
this.setUserInOptimizely();
5048
}
5149

@@ -78,12 +76,15 @@ export class OptimizelyProvider extends React.Component<OptimizelyProviderProps,
7876
// deprecation warning
7977
logger.warn('Passing userId and userAttributes as props is deprecated, please switch to using `user` prop');
8078
} else {
81-
finalUser = DefaultUser;
79+
finalUser = {
80+
id: DefaultUser.id,
81+
attributes: userAttributes || DefaultUser.attributes,
82+
};
8283
}
8384

85+
// if user is a promise, setUser occurs in the then block above
8486
if (finalUser) {
8587
try {
86-
await optimizely.onReady();
8788
await optimizely.setUser(finalUser);
8889
} catch {
8990
logger.error('Error while trying to set user.');

0 commit comments

Comments
 (0)