Skip to content

Commit 6d4561f

Browse files
[FSSDK-10507] React SDK - Linter errors (#272)
* [FSSDK-10507] lint config update, experiment, feature, provider, client update * [FSSDK-10507] notifier and optimizely HOC update * [FSSDK-10507] hook changes, skipping some error for seperate issue * [FSSDK-10507] husky + lint-staged addition * [FSSDK-10507] copyright text addition * [FSSDK-10507] lint-staged command adjustment
1 parent 552772f commit 6d4561f

15 files changed

+348
-86
lines changed

.eslintrc.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ module.exports = {
2020
'plugin:prettier/recommended',
2121
],
2222
rules: {
23-
'@typescript-eslint/ban-ts-ignore': 'off',
23+
'@typescript-eslint/ban-ts-comment': 'warn',
2424
'@typescript-eslint/camelcase': 'off',
2525
'@typescript-eslint/no-empty-function': 'off',
26-
'no-shadow': 'error',
26+
'@typescript-eslint/no-shadow': 'error',
2727
},
2828
};

.husky/pre-commit

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env sh
2+
. "$(dirname -- "$0")/_/husky.sh"
3+
4+
npx lint-staged

package.json

+9-1
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,17 @@
2828
"lint": "tsc --noEmit && eslint 'src/**/*.{js,ts,tsx}' --quiet --fix",
2929
"test": "jest --silent",
3030
"prepublishOnly": "npm run test && npm run build",
31-
"prepare": "npm run build"
31+
"prepare": "npm run build && husky install"
3232
},
3333
"publishConfig": {
3434
"access": "public"
3535
},
36+
"lint-staged": {
37+
"**/*.{js,ts,tsx}": [
38+
"yarn run lint",
39+
"yarn run test --findRelatedTests"
40+
]
41+
},
3642
"dependencies": {
3743
"@optimizely/optimizely-sdk": "^5.3.4",
3844
"hoist-non-react-statics": "^3.3.2",
@@ -61,8 +67,10 @@
6167
"eslint-plugin-prettier": "^5.2.1",
6268
"eslint-plugin-react": "^7.35.0",
6369
"eslint-plugin-react-hooks": "^4.6.2",
70+
"husky": "8.0.3",
6471
"jest": "^29.7.0",
6572
"jest-environment-jsdom": "^29.7.0",
73+
"lint-staged": "13.2.3",
6674
"prettier": "^3.3.3",
6775
"react": "^18.2.0",
6876
"react-dom": "^18.2.0",

src/Experiment.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.
@@ -41,7 +41,7 @@ describe('<OptimizelyExperiment>', () => {
4141
};
4242
});
4343

44-
optimizelyMock = ({
44+
optimizelyMock = {
4545
onReady: jest.fn().mockImplementation(() => onReadyPromise),
4646
activate: jest.fn().mockImplementation(() => variationKey),
4747
onUserUpdate: jest.fn().mockImplementation(() => () => {}),
@@ -58,7 +58,7 @@ describe('<OptimizelyExperiment>', () => {
5858
getIsReadyPromiseFulfilled: () => true,
5959
getIsUsingSdkKey: () => true,
6060
onForcedVariationsUpdate: jest.fn().mockReturnValue(() => {}),
61-
} as unknown) as ReactSDKClient;
61+
} as unknown as ReactSDKClient;
6262
});
6363

6464
it('does not throw an error when not rendered in the context of an OptimizelyProvider', () => {

src/Experiment.tsx

+2-2
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.
@@ -36,7 +36,7 @@ export interface ExperimentProps {
3636
children: React.ReactNode | ChildrenRenderFunction;
3737
}
3838

39-
const Experiment: React.FunctionComponent<ExperimentProps> = props => {
39+
const Experiment: React.FunctionComponent<ExperimentProps> = (props) => {
4040
const { experiment, autoUpdate, timeout, overrideUserId, overrideAttributes, children } = props;
4141
const [variation, clientReady, didTimeout] = useExperiment(
4242
experiment,

src/Feature.spec.tsx

+8-9
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ describe('<OptimizelyFeature>', () => {
4343
};
4444
});
4545

46-
optimizelyMock = ({
47-
onReady: jest.fn().mockImplementation(config => onReadyPromise),
46+
optimizelyMock = {
47+
onReady: jest.fn().mockImplementation(() => onReadyPromise),
4848
getFeatureVariables: jest.fn().mockImplementation(() => featureVariables),
4949
isFeatureEnabled: jest.fn().mockImplementation(() => isEnabledMock),
50-
onUserUpdate: jest.fn().mockImplementation(handler => () => {}),
50+
onUserUpdate: jest.fn().mockImplementation(() => () => {}),
5151
getVuid: jest.fn().mockImplementation(() => 'vuid_95bf72cebc774dfd8e8e580a5a1'),
5252
notificationCenter: {
53-
addNotificationListener: jest.fn().mockImplementation((type, handler) => {}),
54-
removeNotificationListener: jest.fn().mockImplementation(id => {}),
53+
addNotificationListener: jest.fn().mockImplementation(() => {}),
54+
removeNotificationListener: jest.fn().mockImplementation(() => {}),
5555
},
5656
user: {
5757
id: 'testuser',
@@ -60,13 +60,12 @@ describe('<OptimizelyFeature>', () => {
6060
isReady: jest.fn().mockImplementation(() => isReady),
6161
getIsReadyPromiseFulfilled: () => true,
6262
getIsUsingSdkKey: () => true,
63-
} as unknown) as ReactSDKClient;
63+
} as unknown as ReactSDKClient;
6464
});
6565

6666
it('does not throw an error when not rendered in the context of an OptimizelyProvider', () => {
6767
expect(() => {
68-
// @ts-ignore
69-
mount(<OptimizelyFeature feature="feature1">{(isEnabled, variables) => isEnabled}</OptimizelyFeature>);
68+
render(<OptimizelyFeature feature="feature1">{(isEnabled, variables) => isEnabled}</OptimizelyFeature>);
7069
}).toBeDefined();
7170
});
7271

@@ -301,7 +300,7 @@ describe('<OptimizelyFeature>', () => {
301300
resolver.resolve({ success: false, reason: NotReadyReason.TIMEOUT, dataReadyPromise: Promise.resolve() });
302301

303302
// Simulate config update notification firing after datafile fetched
304-
await optimizelyMock.onReady().then(res => res.dataReadyPromise);
303+
await optimizelyMock.onReady().then((res) => res.dataReadyPromise);
305304

306305
expect(optimizelyMock.isFeatureEnabled).toHaveBeenCalledWith('feature1', undefined, undefined);
307306
expect(optimizelyMock.getFeatureVariables).toHaveBeenCalledWith('feature1', undefined, undefined);

src/Feature.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export interface FeatureProps {
3535
children: ChildrenRenderFunction;
3636
}
3737

38-
const FeatureComponent: React.FunctionComponent<FeatureProps> = props => {
38+
const FeatureComponent: React.FunctionComponent<FeatureProps> = (props) => {
3939
const { feature, timeout, autoUpdate, children, overrideUserId, overrideAttributes } = props;
4040
const [isEnabled, variables, clientReady, didTimeout] = useFeature(
4141
feature,

src/Provider.spec.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ describe('OptimizelyProvider', () => {
3030
};
3131

3232
beforeEach(() => {
33-
mockReactClient = ({
33+
mockReactClient = {
3434
user: {
3535
id: 'test-id',
3636
attributes: {},
3737
},
3838
setUser: jest.fn().mockResolvedValue(undefined),
39-
} as unknown) as ReactSDKClient;
39+
} as unknown as ReactSDKClient;
4040
});
4141

4242
it('should render successfully with user provided', () => {

src/client.spec.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ describe('ReactSDKClient', () => {
150150

151151
it('fulfills the returned promise with success: true when a user is set', async () => {
152152
jest.spyOn(mockInnerClient, 'onReady').mockResolvedValue({ success: true });
153-
const instance = createInstance(config);
153+
instance = createInstance(config);
154154
jest.spyOn(instance, 'fetchQualifiedSegments').mockResolvedValue(true);
155155

156156
await instance.setUser({
@@ -164,7 +164,7 @@ describe('ReactSDKClient', () => {
164164

165165
it('fulfills the returned promise with success: false when fetchqualifiedsegment is false', async () => {
166166
jest.spyOn(mockInnerClient, 'onReady').mockResolvedValue({ success: true });
167-
const instance = createInstance(config);
167+
instance = createInstance(config);
168168
jest.spyOn(instance, 'fetchQualifiedSegments').mockResolvedValue(false);
169169

170170
await instance.setUser({
@@ -179,8 +179,8 @@ describe('ReactSDKClient', () => {
179179
beforeEach(() => {
180180
// Mocks clientAndUserReadyPromise value instead of _client = null because test initialization of
181181
// instance causes clientAndUserReadyPromise to return { success: true }
182-
// @ts-ignore
183-
instance.clientAndUserReadyPromise = new Promise(resolve => {
182+
//@ts-ignore
183+
instance.clientAndUserReadyPromise = new Promise((resolve) => {
184184
resolve({
185185
success: false,
186186
reason: NotReadyReason.NO_CLIENT,
@@ -200,7 +200,7 @@ describe('ReactSDKClient', () => {
200200
it('waits for the inner client onReady to fulfill with success = false before fulfilling the returned promise', async () => {
201201
const mockInnerClientOnReady = jest.spyOn(mockInnerClient, 'onReady');
202202
let resolveInnerClientOnReady: (result: OnReadyResult) => void = () => {};
203-
const mockReadyPromise: Promise<OnReadyResult> = new Promise(res => {
203+
const mockReadyPromise: Promise<OnReadyResult> = new Promise((res) => {
204204
resolveInnerClientOnReady = res;
205205
});
206206
mockInnerClientOnReady.mockReturnValueOnce(mockReadyPromise);
@@ -220,11 +220,11 @@ describe('ReactSDKClient', () => {
220220
it('waits for the inner client onReady to fulfill with success = true before fulfilling the returned promise', async () => {
221221
const mockInnerClientOnReady = jest.spyOn(mockInnerClient, 'onReady');
222222
let resolveInnerClientOnReady: (result: OnReadyResult) => void;
223-
const mockReadyPromise: Promise<OnReadyResult> = new Promise(res => {
223+
const mockReadyPromise: Promise<OnReadyResult> = new Promise((res) => {
224224
resolveInnerClientOnReady = res;
225225
});
226226
mockInnerClientOnReady.mockReturnValueOnce(mockReadyPromise);
227-
const instance = createInstance(config);
227+
instance = createInstance(config);
228228
jest.spyOn(instance, 'fetchQualifiedSegments').mockImplementation(async () => true);
229229
await instance.setUser({
230230
id: 'user999',
@@ -1652,7 +1652,7 @@ describe('ReactSDKClient', () => {
16521652

16531653
it('should throw error when action param is falsy', async () => {
16541654
const badValues = ['', ' '];
1655-
badValues.forEach(item => {
1655+
badValues.forEach((item) => {
16561656
instance.sendOdpEvent(item);
16571657
});
16581658

src/client.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
235235
};
236236

237237
this.userPromiseResolver = () => {};
238-
const userReadyPromise = new Promise<OnReadyResult>(resolve => {
238+
const userReadyPromise = new Promise<OnReadyResult>((resolve) => {
239239
this.userPromiseResolver = resolve;
240240
});
241241

@@ -263,7 +263,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
263263
} else {
264264
logger.warn('Unable to resolve datafile and user information because Optimizely client failed to initialize.');
265265

266-
this.clientAndUserReadyPromise = new Promise(resolve => {
266+
this.clientAndUserReadyPromise = new Promise((resolve) => {
267267
resolve({
268268
success: false,
269269
reason: NotReadyReason.NO_CLIENT,
@@ -302,7 +302,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
302302
if (config && config.timeout !== undefined) {
303303
timeout = config.timeout;
304304
}
305-
const timeoutPromise = new Promise<OnReadyResult>(resolve => {
305+
const timeoutPromise = new Promise<OnReadyResult>((resolve) => {
306306
timeoutId = setTimeout(() => {
307307
resolve({
308308
success: false,
@@ -313,7 +313,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
313313
}, timeout) as any;
314314
});
315315

316-
return Promise.race([this.clientAndUserReadyPromise, timeoutPromise]).then(async res => {
316+
return Promise.race([this.clientAndUserReadyPromise, timeoutPromise]).then(async (res) => {
317317
clearTimeout(timeoutId);
318318
return res;
319319
});
@@ -406,7 +406,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
406406
this.isUserPromiseResolved = true;
407407
}
408408

409-
this.onUserUpdateHandlers.forEach(handler => handler(this.user));
409+
this.onUserUpdateHandlers.forEach((handler) => handler(this.user));
410410
}
411411

412412
public onUserUpdate(handler: OnUserUpdateHandler): DisposeFn {
@@ -718,7 +718,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
718718
const isSuccess = this.userContext.removeAllForcedDecisions();
719719

720720
if (isSuccess) {
721-
this.forcedDecisionFlagKeys.forEach(flagKey => notifier.notify(flagKey));
721+
this.forcedDecisionFlagKeys.forEach((flagKey) => notifier.notify(flagKey));
722722
this.forcedDecisionFlagKeys.clear();
723723
}
724724

@@ -812,7 +812,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
812812
return {};
813813
}
814814

815-
Object.keys(feature.variablesMap).forEach(key => {
815+
Object.keys(feature.variablesMap).forEach((key) => {
816816
const variable = feature.variablesMap[key];
817817
variableObj[variable.key] = this._client!.getFeatureVariable(featureKey, variable.key, userId, userAttributes);
818818
});
@@ -1150,7 +1150,7 @@ class OptimizelyReactSDKClient implements ReactSDKClient {
11501150
}
11511151

11521152
const result = this._client.setForcedVariation(experiment, finalUserId, finalVariationKey);
1153-
this.onForcedVariationsUpdateHandlers.forEach(handler => handler());
1153+
this.onForcedVariationsUpdateHandlers.forEach((handler) => handler());
11541154
return result;
11551155
}
11561156

0 commit comments

Comments
 (0)