Skip to content

Commit f2c2964

Browse files
authored
Merge pull request #248 from Flagsmith/fix/race-condition-on-init-response
fix: race condition within flagsmith.init responses
2 parents a030d57 + bdf0b5b commit f2c2964

File tree

6 files changed

+60
-5
lines changed

6 files changed

+60
-5
lines changed

flagsmith-core.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ const Flagsmith = class {
8686
isFetching: true
8787
})
8888
}
89+
const previousIdentity = `${this.identity}`;
8990
const handleResponse = (response: IFlagsmithResponse | null) => {
90-
if(!response) {
91+
if(!response || previousIdentity !== `${this.identity}`) {
9192
return // getJSON returned null due to request/response mismatch
9293
}
9394
let { flags: features, traits }: IFlagsmithResponse = response

lib/flagsmith-es/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "flagsmith-es",
3-
"version": "4.1.1",
3+
"version": "4.1.2",
44
"description": "Feature flagging to support continuous development. This is an esm equivalent of the standard flagsmith npm module.",
55
"main": "./index.js",
66
"type": "module",

lib/flagsmith/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "flagsmith",
3-
"version": "4.1.1",
3+
"version": "4.1.2",
44
"description": "Feature flagging to support continuous development",
55
"main": "./index.js",
66
"repository": {

lib/react-native-flagsmith/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-flagsmith",
3-
"version": "4.1.1",
3+
"version": "4.1.2",
44
"description": "Feature flagging to support continuous development",
55
"main": "./index.js",
66
"repository": {

test/react.test.tsx

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import React, { FC } from 'react';
22
import { render, screen, waitFor } from '@testing-library/react';
33
import { FlagsmithProvider, useFlags, useFlagsmithLoading } from '../lib/flagsmith/react';
4-
import { defaultState, environmentID, getFlagsmith, identityState, testIdentity } from './test-constants';
4+
import {
5+
defaultState, delay,
6+
environmentID,
7+
getFlagsmith,
8+
getMockFetchWithValue,
9+
identityState,
10+
testIdentity,
11+
} from './test-constants';
512
import removeIds from './test-utils/remove-ids';
613
const FlagsmithPage: FC<any> = () => {
714
const flags = useFlags(Object.keys(defaultState.flags))
@@ -117,4 +124,41 @@ describe('FlagsmithProvider', () => {
117124
expect(JSON.parse(screen.getByTestId("flags").innerHTML)).toEqual(removeIds(defaultState.flags));
118125
});
119126
});
127+
it('ignores init response if identify gets called and resolves first', async () => {
128+
129+
const onChange = jest.fn();
130+
const {flagsmith,initConfig, mockFetch} = getFlagsmith({onChange})
131+
getMockFetchWithValue(mockFetch, [{
132+
enabled: false,
133+
feature_state_value: null,
134+
feature: {
135+
id: 1,
136+
name: "hero"
137+
}
138+
}],300) // resolves after flagsmith.identify, it should be ignored
139+
140+
render(
141+
<FlagsmithProvider flagsmith={flagsmith} options={initConfig}>
142+
<FlagsmithPage/>
143+
</FlagsmithProvider>
144+
);
145+
expect(mockFetch).toHaveBeenCalledTimes(1);
146+
getMockFetchWithValue(mockFetch, {
147+
flags: [{
148+
enabled: true,
149+
feature_state_value: null,
150+
feature: {
151+
id: 1,
152+
name: "hero"
153+
}
154+
}]
155+
},0)
156+
await flagsmith.identify(testIdentity)
157+
expect(mockFetch).toHaveBeenCalledTimes(2);
158+
await waitFor(() => {
159+
expect(JSON.parse(screen.getByTestId("flags").innerHTML).hero.enabled).toBe(true)
160+
});
161+
await delay(500)
162+
expect(JSON.parse(screen.getByTestId("flags").innerHTML).hero.enabled).toBe(true)
163+
});
120164
});

test/test-constants.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { IInitConfig, IState } from '../lib/flagsmith/types';
22
import MockAsyncStorage from './mocks/async-storage-mock';
33
import { createFlagsmithInstance } from '../lib/flagsmith';
44
import fetch from 'isomorphic-unfetch';
5+
import type { ModuleMocker } from 'jest-mock';
6+
import Mock = jest.Mock;
57
export const environmentID = 'QjgYur4LQTwe5HpvbvhpzK'; // Flagsmith Demo Projects
68

79
export const defaultState = {
@@ -80,3 +82,11 @@ export function getFlagsmith(config: Partial<IInitConfig> = {}) {
8082
};
8183
return { flagsmith, initConfig, mockFetch, AsyncStorage };
8284
}
85+
export const delay = (ms:number) => new Promise((resolve) => setTimeout(resolve, ms));
86+
export function getMockFetchWithValue(mockFn:Mock, resolvedValue:object, ms=0) {
87+
mockFn.mockReturnValueOnce(delay(ms).then(()=>Promise.resolve({
88+
status:200,
89+
text: () => Promise.resolve(JSON.stringify(resolvedValue)), // Mock json() to return the mock response
90+
json: () => Promise.resolve(resolvedValue), // Mock json() to return the mock response
91+
})))
92+
}

0 commit comments

Comments
 (0)