Skip to content

Commit

Permalink
[FSSDK-9984] fix: initialization and setUser errors (#255)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
mikechu-optimizely and Mike Chu authored Apr 9, 2024
1 parent a87fe08 commit fae169f
Show file tree
Hide file tree
Showing 10 changed files with 347 additions and 123 deletions.
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"name": "vscode-jest-tests.v2.react-sdk",
"request": "launch",
"args": [
"--runInBand",
"--watchAll=false",
"--testNamePattern",
"${jest.testNamePattern}",
"--runTestsByPath",
"${jest.testFile}"
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}
]
}
5 changes: 2 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"jest.autoRun": {
"onStartup": ["all-tests"]
}
"jest.runMode": "on-demand",
"jest.jestCommandLine": "~/.nvm/nvm-exec yarn test"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"access": "public"
},
"dependencies": {
"@optimizely/optimizely-sdk": "^5.2.0",
"@optimizely/optimizely-sdk": "^5.3.0",
"hoist-non-react-statics": "^3.3.0",
"prop-types": "^15.6.2",
"utility-types": "^2.1.0 || ^3.0.0"
Expand Down
6 changes: 3 additions & 3 deletions src/Feature.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2018-2019, 2023 Optimizely
* Copyright 2018-2019, 2023-2024 Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,7 +22,7 @@ import { render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';

import { OptimizelyProvider } from './Provider';
import { ReactSDKClient, VariableValuesObject } from './client';
import { NotReadyReason, ReactSDKClient, VariableValuesObject } from './client';
import { OptimizelyFeature } from './Feature';

describe('<OptimizelyFeature>', () => {
Expand Down Expand Up @@ -298,7 +298,7 @@ describe('<OptimizelyFeature>', () => {

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

// Simulate config update notification firing after datafile fetched
await optimizelyMock.onReady().then(res => res.dataReadyPromise);
Expand Down
95 changes: 95 additions & 0 deletions src/Provider.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Copyright 2024 Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/// <reference types="jest" />

//jest.mock('./client');

import React from 'react';
import { render, act } from '@testing-library/react';
import { OptimizelyProvider } from './Provider';
import { DefaultUser, ReactSDKClient, createInstance } from './client';

describe('OptimizelyProvider', () => {
let mockReactClient: ReactSDKClient;
const config = {
datafile: {},
};

beforeEach(() => {
mockReactClient = ({
user: {
id: 'test-id',
attributes: {},
},
setUser: jest.fn().mockResolvedValue(undefined),
} as unknown) as ReactSDKClient;
});

it('should render successfully with user provided', () => {
act(() => {
render(<OptimizelyProvider optimizely={mockReactClient} user={{ id: 'user1' }} />);
});

expect(mockReactClient.setUser).toHaveBeenCalledWith({
id: 'user1',
attributes: {},
});
});

it('should render successfully with userId provided', () => {
act(() => {
render(<OptimizelyProvider optimizely={mockReactClient} userId="user1" />);
});

expect(mockReactClient.setUser).toHaveBeenCalledWith({
id: 'user1',
attributes: {},
});
});

it('should render successfully without user or userId provided', () => {
act(() => {
render(<OptimizelyProvider optimizely={mockReactClient} />);
});

expect(mockReactClient.setUser).toHaveBeenCalledWith(DefaultUser);
});

it('should render successfully with user id & attributes provided', () => {
act(() => {
render(
<OptimizelyProvider optimizely={mockReactClient} user={{ id: 'user1', attributes: { attr1: 'value1' } }} />
);
});

expect(mockReactClient.setUser).toHaveBeenCalledWith({
id: 'user1',
attributes: { attr1: 'value1' },
});
});

it('should succeed just userAttributes provided', () => {
act(() => {
render(<OptimizelyProvider optimizely={mockReactClient} userAttributes={{ attr1: 'value1' }} />);
});

expect(mockReactClient.setUser).toHaveBeenCalledWith({
id: DefaultUser.id,
attributes: { attr1: 'value1' },
});
});
});
11 changes: 6 additions & 5 deletions src/Provider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2022-2023, Optimizely
* Copyright 2022-2024, Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,9 +43,7 @@ interface OptimizelyProviderState {
export class OptimizelyProvider extends React.Component<OptimizelyProviderProps, OptimizelyProviderState> {
constructor(props: OptimizelyProviderProps) {
super(props);
}

componentDidMount(): void {
this.setUserInOptimizely();
}

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

// if user is a promise, setUser occurs in the then block above
if (finalUser) {
try {
await optimizely.onReady();
await optimizely.setUser(finalUser);
} catch {
logger.error('Error while trying to set user.');
Expand Down
Loading

0 comments on commit fae169f

Please sign in to comment.