Skip to content

Commit 62c9498

Browse files
committed
implements getFeature pattern
1 parent 2789bd2 commit 62c9498

File tree

2 files changed

+94
-22
lines changed

2 files changed

+94
-22
lines changed

packages/adapter-flagsmith/src/index.test.ts

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2-
import { createFlagsmithAdapter } from '.';
2+
import { flagsmithAdapter } from '.';
33
import flagsmith, { IFlagsmithFeature, IState } from 'flagsmith';
44

55
// Mock the flagsmith module
@@ -14,26 +14,24 @@ vi.mock('flagsmith', () => ({
1414
describe('Flagsmith Adapter', () => {
1515
beforeEach(() => {
1616
vi.resetAllMocks();
17+
process.env.FLAGSMITH_ENVIRONMENT_ID = 'test-key';
1718
});
1819

1920
afterEach(() => {
2021
vi.mocked(flagsmith.init).mockClear();
22+
delete process.env.FLAGSMITH_ENVIRONMENT_ID;
2123
vi.clearAllMocks();
2224
});
2325

2426
it('should initialize the adapter', async () => {
25-
const adapter = createFlagsmithAdapter({
26-
environmentID: 'test-key',
27-
});
27+
const adapter = flagsmithAdapter.getFeature();
2828

2929
expect(adapter).toBeDefined();
3030
expect(adapter.decide).toBeDefined();
3131
});
3232

3333
it('should initialize Flagsmith client when deciding flag value', async () => {
34-
const adapter = createFlagsmithAdapter<IFlagsmithFeature, any>({
35-
environmentID: 'test-key',
36-
});
34+
const adapter = flagsmithAdapter.getFeature();
3735

3836
// Mock getState to return a specific flag value
3937
const mockFlag: IFlagsmithFeature = {
@@ -57,16 +55,14 @@ describe('Flagsmith Adapter', () => {
5755
});
5856

5957
expect(flagsmith.init).toHaveBeenCalledWith({
60-
environmentID: 'test-key',
6158
fetch: expect.any(Function),
59+
environmentID: process.env.FLAGSMITH_ENVIRONMENT_ID,
6260
});
6361
expect(value).toEqual(mockFlag);
6462
});
6563

6664
it('should return default value when flag is not found', async () => {
67-
const adapter = createFlagsmithAdapter<IFlagsmithFeature, any>({
68-
environmentID: 'test-key',
69-
});
65+
const adapter = flagsmithAdapter.getFeature();
7066

7167
// Mock getState to return empty flags
7268
vi.mocked(flagsmith.getState).mockReturnValue({
@@ -91,9 +87,7 @@ describe('Flagsmith Adapter', () => {
9187
});
9288

9389
it('should reuse initialized Flagsmith client', async () => {
94-
const adapter = createFlagsmithAdapter<IFlagsmithFeature, any>({
95-
environmentID: 'test-key',
96-
});
90+
const adapter = flagsmithAdapter.getFeature();
9791

9892
// Set Flagsmith as already initialized
9993
vi.mocked(flagsmith).initialised = true;
@@ -115,8 +109,7 @@ describe('Flagsmith Adapter', () => {
115109
});
116110

117111
it('should handle additional Flagsmith configuration options', async () => {
118-
const adapter = createFlagsmithAdapter<IFlagsmithFeature, any>({
119-
environmentID: 'test-key',
112+
const adapter = flagsmithAdapter.getFeature({
120113
api: 'https://custom-api.com',
121114
enableLogs: true,
122115
});
@@ -131,10 +124,63 @@ describe('Flagsmith Adapter', () => {
131124
});
132125

133126
expect(flagsmith.init).toHaveBeenCalledWith({
134-
environmentID: 'test-key',
135127
api: 'https://custom-api.com',
136128
enableLogs: true,
129+
environmentID: process.env.FLAGSMITH_ENVIRONMENT_ID,
130+
fetch: expect.any(Function),
131+
});
132+
});
133+
134+
it('should handle manually set environmentID', async () => {
135+
const adapter = flagsmithAdapter.getFeature({
136+
environmentID: 'custom-env-id',
137+
});
138+
139+
vi.mocked(flagsmith).initialised = false;
140+
141+
await adapter.decide({
142+
key: 'test-flag',
143+
entities: undefined,
144+
headers: {} as any,
145+
cookies: {} as any,
146+
});
147+
148+
expect(flagsmith.init).toHaveBeenCalledWith({
149+
environmentID: 'custom-env-id',
150+
fetch: expect.any(Function),
151+
});
152+
});
153+
154+
it('should retrieve the feature flag value using the decide method', async () => {
155+
const mockFlag: IFlagsmithFeature = {
156+
enabled: true,
157+
value: 'mocked-value',
158+
};
159+
160+
vi.mocked(flagsmith.getState).mockReturnValue({
161+
flags: {
162+
'my-feature': mockFlag,
163+
},
164+
api: 'https://api.flagsmith.com/api/v1/',
165+
} as IState<string>);
166+
167+
// Mock Flagsmith as not initialized
168+
vi.mocked(flagsmith).initialised = false;
169+
170+
const adapter = flagsmithAdapter.getFeature();
171+
172+
const myFeatureFlag = await adapter.decide({
173+
key: 'my-feature',
174+
defaultValue: { enabled: false, value: 'default-value' },
175+
entities: undefined,
176+
headers: {} as any,
177+
cookies: {} as any,
178+
});
179+
180+
expect(flagsmith.init).toHaveBeenCalledWith({
181+
environmentID: process.env.FLAGSMITH_ENVIRONMENT_ID,
137182
fetch: expect.any(Function),
138183
});
184+
expect(myFeatureFlag).toEqual(mockFlag);
139185
});
140186
});
Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import type { Adapter } from 'flags';
22
import flagsmith, { IFlagsmithFeature, IInitConfig } from 'flagsmith';
33

4+
type AdapterParams = {
5+
key?: string;
6+
} & IInitConfig;
7+
48
export function createFlagsmithAdapter<
59
ValueType extends IFlagsmithFeature,
610
EntitiesType,
7-
>(config: IInitConfig): Adapter<ValueType, EntitiesType> {
11+
>({
12+
key: customKey,
13+
...configParams
14+
}: AdapterParams): Adapter<ValueType, EntitiesType> {
815
async function initialize(config: IInitConfig) {
916
if (flagsmith?.initialised) return;
10-
await flagsmith.init({ fetch: global.fetch, ...config });
17+
await flagsmith.init({ fetch: global.fetch, ...configParams });
1118
}
1219

1320
return {
@@ -18,11 +25,30 @@ export function createFlagsmithAdapter<
1825
cookies,
1926
defaultValue,
2027
}): Promise<ValueType> {
21-
await initialize(config);
28+
await initialize(configParams);
2229
const state = flagsmith.getState();
23-
const flag = state?.flags?.[key] ?? defaultValue;
24-
30+
const keyName = customKey || key;
31+
const flag = state?.flags?.[keyName] ?? defaultValue;
2532
return flag as ValueType;
2633
},
2734
};
2835
}
36+
37+
// Lazy default adapter
38+
export const flagsmithAdapter = {
39+
getFeature: <ValueType extends IFlagsmithFeature>(params?: AdapterParams) => {
40+
const environmentID = process.env.FLAGSMITH_ENVIRONMENT_ID;
41+
if (!environmentID && params?.environmentID) {
42+
throw new Error(
43+
'@flags-sdk/flagsmith: FLAGSMITH_ENVIRONMENT_ID is not set',
44+
);
45+
}
46+
47+
const adapter = createFlagsmithAdapter<ValueType, unknown>({
48+
environmentID,
49+
...params,
50+
});
51+
52+
return adapter;
53+
},
54+
};

0 commit comments

Comments
 (0)