@newskit-render/feature-flags 0.0.0-1fc471ad
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -0
- package/dist/cjs/__tests__/utils.tests.d.ts +1 -0
- package/dist/cjs/__tests__/utils.tests.js +535 -0
- package/dist/cjs/__tests__/utils.tests.js.map +1 -0
- package/dist/cjs/feature-flags-context.d.ts +9 -0
- package/dist/cjs/feature-flags-context.js +44 -0
- package/dist/cjs/feature-flags-context.js.map +1 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/types.d.ts +40 -0
- package/dist/cjs/types.js +51 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/utils.d.ts +3 -0
- package/dist/cjs/utils.js +229 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/__tests__/utils.tests.d.ts +1 -0
- package/dist/esm/__tests__/utils.tests.js +538 -0
- package/dist/esm/__tests__/utils.tests.js.map +1 -0
- package/dist/esm/feature-flags-context.d.ts +9 -0
- package/dist/esm/feature-flags-context.js +16 -0
- package/dist/esm/feature-flags-context.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types.d.ts +40 -0
- package/dist/esm/types.js +48 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils.d.ts +3 -0
- package/dist/esm/utils.js +224 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @newskit-render/feature-flags
|
|
2
|
+
|
|
3
|
+
A package for adding feature flags to projects generated by newskit-render.
|
|
4
|
+
|
|
5
|
+
## How to use:
|
|
6
|
+
|
|
7
|
+
`yarn add @newskit-render/feature-flags` or <br />
|
|
8
|
+
`npm install --save @newskit-render/feature-flags` <br /><br />
|
|
9
|
+
|
|
10
|
+
There are two ways that feature flags can be utilized.
|
|
11
|
+
|
|
12
|
+
### getFeatureFlags() in getServerSideProps
|
|
13
|
+
|
|
14
|
+
The most performant way to use feature flags is to call `getFeatureFlags()` in `getServersideProps` and then use them throughout the page. This way the implementation will only be available for the current page and and wouldn't effect the rest of the site.
|
|
15
|
+
To do so you will need to initialize the package by calling `createFeatureFlagsInstance` with the sdkKey from optimizely.
|
|
16
|
+
Best practice is to store your sdk key in environment variables, the examples below utilize that method.
|
|
17
|
+
For local use, you cadd the Optimizely SDK key from your project in your `.env.local` file like so
|
|
18
|
+
`OPTIMIZELY_SDK_KEY="123"`.
|
|
19
|
+
In case you don't have project or access to the Optimizely platform please contact the Experimentation team.
|
|
20
|
+
Optionally the config can be switched to suit your need. More on this can be found [here](#createFeatureFlagsInstance).<br /> <br />
|
|
21
|
+
An example implementation would be as follows:
|
|
22
|
+
|
|
23
|
+
`pages/index.ts`
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
import {getFeatureFlags, createFeatureFlagsInstance} from '@newskit-render/feature-flags';
|
|
27
|
+
|
|
28
|
+
export async function getServerSideProps(context) {
|
|
29
|
+
// code
|
|
30
|
+
createFeatureFlagsInstance({ optimizelyConfig: { sdkKey: process.env.OPTIMIZELY_SDK_KEY } })
|
|
31
|
+
// code
|
|
32
|
+
|
|
33
|
+
const [resultFromOtherQueries, featureFlagsResult] = await Promise.allSettled([
|
|
34
|
+
// other queries,
|
|
35
|
+
getFeatureFlags()
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
const featureFlags = featureFlagsResult.value;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
props: {
|
|
42
|
+
// other data
|
|
43
|
+
featureFlags
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The package also provides a helper function that conbines getFeatureFlags, createFeatureFlagsInstance in one.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
import {initAndGetFeatureFlag} from '@newskit-render/feature-flags';
|
|
53
|
+
|
|
54
|
+
export async function getServerSideProps(context) {
|
|
55
|
+
const [resultFromOtherQueries, featureFlags] = await Promise.allSettled([
|
|
56
|
+
// other queries,
|
|
57
|
+
initAndGetFeatureFlag(process.env.OPTIMIZELY_SDK_KEY)
|
|
58
|
+
])
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
props: {
|
|
62
|
+
// other data
|
|
63
|
+
featureFlags
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`samplePage/index.tsx`
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
import React from 'react'
|
|
73
|
+
import { FeatureFlag } from '@newskit-render/feature-flags'
|
|
74
|
+
|
|
75
|
+
const SectionPage: React.FC<{
|
|
76
|
+
page: Page
|
|
77
|
+
// pageprops...
|
|
78
|
+
featureFlags?: FeatureFlag[]
|
|
79
|
+
}> = ({ page, pageprops..., featureFlags }) => {
|
|
80
|
+
|
|
81
|
+
return(
|
|
82
|
+
<Layout>
|
|
83
|
+
{featureFlags && featureFlags['test_flag'] && <p>FEATURE FLAG IS HEREEE</p>}
|
|
84
|
+
<Cell>
|
|
85
|
+
// ...content
|
|
86
|
+
</Cell>
|
|
87
|
+
</Layout>
|
|
88
|
+
)}
|
|
89
|
+
|
|
90
|
+
export default SamplePage
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### hooks in getInitialProps
|
|
95
|
+
|
|
96
|
+
Alternatively, feature flags can be applied on the whole app. To do so, you'll need to instantiate the package in `getInitialProps` of the main app, then call `getFeatureFlags` and pass the result to the whole app.
|
|
97
|
+
By calling the `useFeatureFlagsContext` hook, the list of featureFlags can be accessed from any point of the site.
|
|
98
|
+
<br /> <br />
|
|
99
|
+
Below we explore a solution, where we use it in the header of the app.
|
|
100
|
+
|
|
101
|
+
`pages/_app.tsx`
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
import { getFeatureFlags, FeatureFlagsContextProvider, FeatureFlag, createFeatureFlagsInstance } from '@newskit-render/feature-flags';
|
|
105
|
+
|
|
106
|
+
function MyApp({ featureFlags }: {featureFlags: FeatureFlag[]}) {
|
|
107
|
+
return (
|
|
108
|
+
<FeatureFlagsContextProvider context={ featureFlags } >
|
|
109
|
+
<App />
|
|
110
|
+
</FeatureFlagsContextProvider>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
MyApp.getInitialProps = async () => {
|
|
114
|
+
createFeatureFlagsInstance({ optimizelyConfig: { sdkKey: process.env.OPTIMIZELY_SDK_KEY } })
|
|
115
|
+
const featureFlags = await getFeatureFlags();
|
|
116
|
+
return { featureFlags }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default MyApp
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`header/index.tsx`
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
import { useFeatureFlagsContext } from '@newskit-render/feature-flags';
|
|
126
|
+
|
|
127
|
+
const Header: React.FC<{ user: UserData }> = ({ user }) => {
|
|
128
|
+
const featureFlags = useFeatureFlagsContext();
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<>
|
|
132
|
+
<StyledHeader>
|
|
133
|
+
<MainGrid>
|
|
134
|
+
<Cell xs={12}>
|
|
135
|
+
// ...nav buttons
|
|
136
|
+
{featureFlags && featureFlags['test_flag'] && <p>FEATURE FLAGG</p>}
|
|
137
|
+
// ...nav buttons
|
|
138
|
+
</Stack>
|
|
139
|
+
</Stack>
|
|
140
|
+
</Cell>
|
|
141
|
+
</MainGrid>
|
|
142
|
+
</StyledHeader>
|
|
143
|
+
</>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export default Header
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### createFeatureFlagsInstance
|
|
151
|
+
|
|
152
|
+
`createFeatureFlagsInstance` takes config object as parameter. The config object consists of [`optimizelyConfig`](https://docs.developers.optimizely.com/full-stack/v4.0/docs/initialize-sdk-javascript-node#section-parameters), `userId`, `defaultFeatureFlags`, `logLevel`. The only requirement for the feature flags to be instantiated is passing optimizely sdk key to `optimizelyConfig`. Further, the whole config can be changed to suit your needs.
|
|
153
|
+
`userId` serves as optimizely user identity.
|
|
154
|
+
`defaultFeatureFlags` are used in the event that optimizely doesn't load up and initial values are required.
|
|
155
|
+
`logLevel` serves to configure the optimizely logger if you wish to use it. It accepts `critical`, `error`, `warning`, `debug` or `info`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
var utils_1 = require("../utils");
|
|
15
|
+
// import { SDKConfig } from '../types'
|
|
16
|
+
var originalEnv = process.env;
|
|
17
|
+
jest.mock('@optimizely/optimizely-sdk', function () { return (__assign(__assign({}, jest.requireActual('@optimizely/optimizely-sdk')), { createInstance: function () { return (__assign(__assign({}, jest.requireActual('@optimizely/optimizely-sdk').createInstance), { createUserContext: function () { return ({
|
|
18
|
+
decide: jest
|
|
19
|
+
.fn()
|
|
20
|
+
.mockImplementation(function (key, options) {
|
|
21
|
+
return flagsMock[key];
|
|
22
|
+
}),
|
|
23
|
+
decideForKeys: jest
|
|
24
|
+
.fn()
|
|
25
|
+
.mockImplementation(function (keys, options) {
|
|
26
|
+
var filtered = {};
|
|
27
|
+
keys.forEach(function (k) { return (filtered[k] = flagsMock[k]); });
|
|
28
|
+
return filtered;
|
|
29
|
+
}),
|
|
30
|
+
decideAll: jest
|
|
31
|
+
.fn()
|
|
32
|
+
.mockImplementation(function (options) {
|
|
33
|
+
return flagsMock;
|
|
34
|
+
}),
|
|
35
|
+
}); }, onReady: jest.fn().mockResolvedValue({ success: true }), close: jest.fn().mockResolvedValue({ success: true }) })); }, setLogLevel: jest.fn(), setLogger: jest.fn() })); });
|
|
36
|
+
var flagsMock = {
|
|
37
|
+
qualtrics_flag: {
|
|
38
|
+
variationKey: 'on',
|
|
39
|
+
enabled: true,
|
|
40
|
+
variables: {},
|
|
41
|
+
ruleKey: 'default-rollout-216689-29200910123',
|
|
42
|
+
flagKey: 'qualtrics_flag',
|
|
43
|
+
userContext: {
|
|
44
|
+
_qualifiedSegments: null,
|
|
45
|
+
// optimizely: [e],
|
|
46
|
+
userId: 'user123',
|
|
47
|
+
attributes: {},
|
|
48
|
+
forcedDecisionsMap: {},
|
|
49
|
+
},
|
|
50
|
+
reasons: [],
|
|
51
|
+
},
|
|
52
|
+
testing_flag: {
|
|
53
|
+
variationKey: 'max_10',
|
|
54
|
+
enabled: true,
|
|
55
|
+
variables: { max_family_members: 10 },
|
|
56
|
+
ruleKey: 'default-rollout-223709-29200910123',
|
|
57
|
+
flagKey: 'testing_flag',
|
|
58
|
+
userContext: {
|
|
59
|
+
_qualifiedSegments: null,
|
|
60
|
+
// optimizely: [e],
|
|
61
|
+
userId: 'user123',
|
|
62
|
+
attributes: {},
|
|
63
|
+
forcedDecisionsMap: {},
|
|
64
|
+
},
|
|
65
|
+
reasons: [],
|
|
66
|
+
},
|
|
67
|
+
another_test_flag_1: {
|
|
68
|
+
variationKey: 'off',
|
|
69
|
+
enabled: false,
|
|
70
|
+
variables: {},
|
|
71
|
+
ruleKey: 'default-rollout-225089-29200910123',
|
|
72
|
+
flagKey: 'another_test_flag_1',
|
|
73
|
+
userContext: {
|
|
74
|
+
_qualifiedSegments: null,
|
|
75
|
+
// optimizely: [e],
|
|
76
|
+
userId: 'user123',
|
|
77
|
+
attributes: {},
|
|
78
|
+
forcedDecisionsMap: {},
|
|
79
|
+
},
|
|
80
|
+
reasons: [],
|
|
81
|
+
},
|
|
82
|
+
testing_flag_with_variations_and_variables: {
|
|
83
|
+
variationKey: 'primary_with_new_weclome_message_and_max_accounts',
|
|
84
|
+
enabled: true,
|
|
85
|
+
variables: {
|
|
86
|
+
family_primary_welcome_message: 'This is the new message',
|
|
87
|
+
family_primary_enable_secondary_accounts: true,
|
|
88
|
+
family_primary_max_secondary_accounts: 10,
|
|
89
|
+
family_primary_metadata_json: {
|
|
90
|
+
metadata1: 'a',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
ruleKey: 'default-rollout-225097-29200910123',
|
|
94
|
+
flagKey: 'testing_flag_with_variations_and_variables',
|
|
95
|
+
userContext: {
|
|
96
|
+
_qualifiedSegments: null,
|
|
97
|
+
// optimizely: [e],
|
|
98
|
+
userId: 'user123',
|
|
99
|
+
attributes: {},
|
|
100
|
+
forcedDecisionsMap: {},
|
|
101
|
+
},
|
|
102
|
+
reasons: [],
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
// TO DO: Improve test coverage
|
|
106
|
+
beforeEach(function () {
|
|
107
|
+
jest.resetModules();
|
|
108
|
+
process.env = __assign(__assign({}, originalEnv), { OPTIMIZELY_SDK_KEY: 'optimizely-sdk-key' });
|
|
109
|
+
});
|
|
110
|
+
afterEach(function () {
|
|
111
|
+
(0, utils_1._resetInstance)();
|
|
112
|
+
});
|
|
113
|
+
describe('initAndGetFeatureFlag', function () {
|
|
114
|
+
it('should return all feature flags', function () {
|
|
115
|
+
expect(true).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
// describe('getFlagsAll', () => {
|
|
119
|
+
// it('should return all flags with default options', async () => {
|
|
120
|
+
// const flagsAll = await getFlagsAll()
|
|
121
|
+
// expect(flagsAll).toEqual({
|
|
122
|
+
// qualtrics_flag: { variationKey: 'on', enabled: true, variables: {} },
|
|
123
|
+
// testing_flag: {
|
|
124
|
+
// variationKey: 'max_10',
|
|
125
|
+
// enabled: true,
|
|
126
|
+
// variables: { max_family_members: 10 },
|
|
127
|
+
// },
|
|
128
|
+
// another_test_flag_1: {
|
|
129
|
+
// variationKey: 'off',
|
|
130
|
+
// enabled: false,
|
|
131
|
+
// variables: {},
|
|
132
|
+
// },
|
|
133
|
+
// testing_flag_with_variations_and_variables: {
|
|
134
|
+
// variationKey: 'primary_with_new_weclome_message_and_max_accounts',
|
|
135
|
+
// enabled: true,
|
|
136
|
+
// variables: {
|
|
137
|
+
// family_primary_welcome_message: 'This is the new message',
|
|
138
|
+
// family_primary_enable_secondary_accounts: true,
|
|
139
|
+
// family_primary_max_secondary_accounts: 10,
|
|
140
|
+
// family_primary_metadata_json: {
|
|
141
|
+
// metadata1: 'a',
|
|
142
|
+
// },
|
|
143
|
+
// },
|
|
144
|
+
// },
|
|
145
|
+
// })
|
|
146
|
+
// })
|
|
147
|
+
// it('should return all flags with custom options', async () => {
|
|
148
|
+
// process.env = {
|
|
149
|
+
// ...originalEnv,
|
|
150
|
+
// OPTIMIZELY_SDK_KEY: undefined,
|
|
151
|
+
// }
|
|
152
|
+
// const options: SDKConfig = {
|
|
153
|
+
// sdkConfig: {
|
|
154
|
+
// sdkKey: 'custom-optimizely-sdk',
|
|
155
|
+
// },
|
|
156
|
+
// userData: {
|
|
157
|
+
// userId: 'user456',
|
|
158
|
+
// attributes: { logged_in: true, cpn: 'AAA123', subs_type: 'digi-print' },
|
|
159
|
+
// },
|
|
160
|
+
// includeFlagVariables: true,
|
|
161
|
+
// }
|
|
162
|
+
// const flagsAll = await getFlagsAll(options)
|
|
163
|
+
// expect(flagsAll).toEqual({
|
|
164
|
+
// qualtrics_flag: { variationKey: 'on', enabled: true, variables: {} },
|
|
165
|
+
// testing_flag: {
|
|
166
|
+
// variationKey: 'max_10',
|
|
167
|
+
// enabled: true,
|
|
168
|
+
// variables: { max_family_members: 10 },
|
|
169
|
+
// },
|
|
170
|
+
// another_test_flag_1: {
|
|
171
|
+
// variationKey: 'off',
|
|
172
|
+
// enabled: false,
|
|
173
|
+
// variables: {},
|
|
174
|
+
// },
|
|
175
|
+
// testing_flag_with_variations_and_variables: {
|
|
176
|
+
// variationKey: 'primary_with_new_weclome_message_and_max_accounts',
|
|
177
|
+
// enabled: true,
|
|
178
|
+
// variables: {
|
|
179
|
+
// family_primary_welcome_message: 'This is the new message',
|
|
180
|
+
// family_primary_enable_secondary_accounts: true,
|
|
181
|
+
// family_primary_max_secondary_accounts: 10,
|
|
182
|
+
// family_primary_metadata_json: {
|
|
183
|
+
// metadata1: 'a',
|
|
184
|
+
// },
|
|
185
|
+
// },
|
|
186
|
+
// },
|
|
187
|
+
// })
|
|
188
|
+
// })
|
|
189
|
+
// it('should return empty object if no flags are fetched', async () => {
|
|
190
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
191
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk'),
|
|
192
|
+
// createInstance: () => ({
|
|
193
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
194
|
+
// createUserContext: () => ({
|
|
195
|
+
// decideAll: jest
|
|
196
|
+
// .fn()
|
|
197
|
+
// .mockImplementation((options?: OptimizelyDecideOption[]) => {
|
|
198
|
+
// return undefined
|
|
199
|
+
// }),
|
|
200
|
+
// }),
|
|
201
|
+
// onReady: jest.fn().mockResolvedValue({ success: true }),
|
|
202
|
+
// close: jest.fn().mockResolvedValue({ success: true }),
|
|
203
|
+
// }),
|
|
204
|
+
// }))
|
|
205
|
+
// const { getFlagsAll } = require('../utils')
|
|
206
|
+
// const flagsAll = await getFlagsAll()
|
|
207
|
+
// expect(flagsAll).toEqual({})
|
|
208
|
+
// })
|
|
209
|
+
// it('should return empty object when called without sdk key', async () => {
|
|
210
|
+
// process.env = {
|
|
211
|
+
// ...originalEnv,
|
|
212
|
+
// OPTIMIZELY_SDK_KEY: undefined,
|
|
213
|
+
// }
|
|
214
|
+
// const flagsAll = await getFlagsAll()
|
|
215
|
+
// expect(flagsAll).toEqual({})
|
|
216
|
+
// })
|
|
217
|
+
// it('should return empty object when sdk not initialized', async () => {
|
|
218
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
219
|
+
// createInstance: jest.fn().mockReturnValue(null),
|
|
220
|
+
// }))
|
|
221
|
+
// const { getFlagsAll } = require('../utils')
|
|
222
|
+
// const flagsAll = await getFlagsAll()
|
|
223
|
+
// expect(flagsAll).toEqual({})
|
|
224
|
+
// })
|
|
225
|
+
// it('should return empty object when user context not initialized', async () => {
|
|
226
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
227
|
+
// createInstance: () => ({
|
|
228
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
229
|
+
// createUserContext: jest.fn().mockReturnValue(null),
|
|
230
|
+
// onReady: jest.fn().mockResolvedValue({ success: true }),
|
|
231
|
+
// }),
|
|
232
|
+
// }))
|
|
233
|
+
// const { getFlagsAll } = require('../utils')
|
|
234
|
+
// const flagsAll = await getFlagsAll()
|
|
235
|
+
// expect(flagsAll).toEqual({})
|
|
236
|
+
// })
|
|
237
|
+
// it('should instantiate logger with log level', async () => {
|
|
238
|
+
// const options: SDKConfig = {
|
|
239
|
+
// logLevel: 'critical',
|
|
240
|
+
// }
|
|
241
|
+
// await getFlagsAll(options)
|
|
242
|
+
// expect(setLogLevel).toBeCalledWith('critical')
|
|
243
|
+
// expect(setLogger).toHaveBeenCalled()
|
|
244
|
+
// })
|
|
245
|
+
// it('should return defaultFeatureFlags when they have been passed and optimizely client is not ready', async () => {
|
|
246
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
247
|
+
// createInstance: () => ({
|
|
248
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
249
|
+
// createUserContext: () => ({
|
|
250
|
+
// decideAll: jest
|
|
251
|
+
// .fn()
|
|
252
|
+
// .mockImplementation((options?: OptimizelyDecideOption[]) => {
|
|
253
|
+
// return flagsMock as {
|
|
254
|
+
// [key: string]: Omit<OptimizelyDecision, 'userContext'>
|
|
255
|
+
// }
|
|
256
|
+
// }),
|
|
257
|
+
// }),
|
|
258
|
+
// onReady: jest
|
|
259
|
+
// .fn()
|
|
260
|
+
// .mockResolvedValue({ success: false, reason: 'Promise rejected' }),
|
|
261
|
+
// }),
|
|
262
|
+
// }))
|
|
263
|
+
// const { getFlagsAll } = require('../utils')
|
|
264
|
+
// const options: SDKConfig = {
|
|
265
|
+
// defaultFeatureFlags: {
|
|
266
|
+
// default_flag: {
|
|
267
|
+
// variationKey: 'off',
|
|
268
|
+
// enabled: true,
|
|
269
|
+
// variables: {},
|
|
270
|
+
// },
|
|
271
|
+
// },
|
|
272
|
+
// }
|
|
273
|
+
// const flagsAll = await getFlagsAll(options)
|
|
274
|
+
// expect(flagsAll).toEqual(options.defaultFeatureFlags)
|
|
275
|
+
// })
|
|
276
|
+
// it('should return empty object when no default flag have been passed and optimizely client is not ready', async () => {
|
|
277
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
278
|
+
// createInstance: () => ({
|
|
279
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
280
|
+
// createUserContext: () => ({
|
|
281
|
+
// decideAll: jest
|
|
282
|
+
// .fn()
|
|
283
|
+
// .mockImplementation((options?: OptimizelyDecideOption[]) => {
|
|
284
|
+
// return flagsMock as {
|
|
285
|
+
// [key: string]: Omit<OptimizelyDecision, 'userContext'>
|
|
286
|
+
// }
|
|
287
|
+
// }),
|
|
288
|
+
// }),
|
|
289
|
+
// onReady: jest
|
|
290
|
+
// .fn()
|
|
291
|
+
// .mockResolvedValue({ success: false, reason: 'Promise rejected' }),
|
|
292
|
+
// }),
|
|
293
|
+
// }))
|
|
294
|
+
// const { getFlagsAll } = require('../utils')
|
|
295
|
+
// const flagsAll = await getFlagsAll()
|
|
296
|
+
// expect(flagsAll).toEqual({})
|
|
297
|
+
// })
|
|
298
|
+
// })
|
|
299
|
+
// describe('closeFlagsInstance', () => {
|
|
300
|
+
// it('should close sdk instance successfully', async () => {
|
|
301
|
+
// const spy = jest.spyOn(console, 'log')
|
|
302
|
+
// await getFlagsAll()
|
|
303
|
+
// await closeFlagsInstance()
|
|
304
|
+
// expect(spy).toHaveBeenCalledWith('optimizely instance closed successfully')
|
|
305
|
+
// })
|
|
306
|
+
// it('should not close sdk instance sucessfully', async () => {
|
|
307
|
+
// const spy = jest.spyOn(console, 'log')
|
|
308
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
309
|
+
// createInstance: () => ({
|
|
310
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
311
|
+
// createUserContext: () => ({
|
|
312
|
+
// decide: jest
|
|
313
|
+
// .fn()
|
|
314
|
+
// .mockImplementation(
|
|
315
|
+
// (key: string, options?: OptimizelyDecideOption[]) => {
|
|
316
|
+
// return getFlagsAll as Omit<OptimizelyDecision, 'userContext'>
|
|
317
|
+
// }
|
|
318
|
+
// ),
|
|
319
|
+
// }),
|
|
320
|
+
// onReady: jest.fn().mockResolvedValue({ success: true }),
|
|
321
|
+
// close: jest
|
|
322
|
+
// .fn()
|
|
323
|
+
// .mockResolvedValue({ success: false, reason: 'Closing rejected' }),
|
|
324
|
+
// }),
|
|
325
|
+
// }))
|
|
326
|
+
// const { getFlagsAll, closeFlagsInstance } = require('../utils')
|
|
327
|
+
// await getFlagsAll()
|
|
328
|
+
// await closeFlagsInstance()
|
|
329
|
+
// expect(spy).toHaveBeenCalledWith(
|
|
330
|
+
// 'closing Optimizely instance failed, reason: Closing rejected'
|
|
331
|
+
// )
|
|
332
|
+
// })
|
|
333
|
+
// })
|
|
334
|
+
// describe('getFlag', () => {
|
|
335
|
+
// it('should return a flag with default options', async () => {
|
|
336
|
+
// const flag = await getFlag('testing_flag_with_variations_and_variables')
|
|
337
|
+
// expect(flag).toEqual({
|
|
338
|
+
// testing_flag_with_variations_and_variables: {
|
|
339
|
+
// variationKey: 'primary_with_new_weclome_message_and_max_accounts',
|
|
340
|
+
// enabled: true,
|
|
341
|
+
// variables: {
|
|
342
|
+
// family_primary_welcome_message: 'This is the new message',
|
|
343
|
+
// family_primary_enable_secondary_accounts: true,
|
|
344
|
+
// family_primary_max_secondary_accounts: 10,
|
|
345
|
+
// family_primary_metadata_json: {
|
|
346
|
+
// metadata1: 'a',
|
|
347
|
+
// },
|
|
348
|
+
// },
|
|
349
|
+
// },
|
|
350
|
+
// })
|
|
351
|
+
// })
|
|
352
|
+
// it('should return empty object if no flags are fetched', async () => {
|
|
353
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
354
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk'),
|
|
355
|
+
// createInstance: () => ({
|
|
356
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
357
|
+
// createUserContext: () => ({
|
|
358
|
+
// decide: jest
|
|
359
|
+
// .fn()
|
|
360
|
+
// .mockImplementation((options?: OptimizelyDecideOption[]) => {
|
|
361
|
+
// return undefined
|
|
362
|
+
// }),
|
|
363
|
+
// }),
|
|
364
|
+
// onReady: jest.fn().mockResolvedValue({ success: true }),
|
|
365
|
+
// close: jest.fn().mockResolvedValue({ success: true }),
|
|
366
|
+
// }),
|
|
367
|
+
// }))
|
|
368
|
+
// const { getFlag } = require('../utils')
|
|
369
|
+
// const flagsAll = await getFlag('testing_flag_with_variations_and_variables')
|
|
370
|
+
// expect(flagsAll).toEqual({})
|
|
371
|
+
// })
|
|
372
|
+
// it('should return defaultFeatureFlags when they have been passed and optimizely client is not ready', async () => {
|
|
373
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
374
|
+
// createInstance: () => ({
|
|
375
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
376
|
+
// createUserContext: () => ({
|
|
377
|
+
// decide: jest
|
|
378
|
+
// .fn()
|
|
379
|
+
// .mockImplementation(
|
|
380
|
+
// (key: string, options?: OptimizelyDecideOption[]) => {
|
|
381
|
+
// return flagsMock[key] as Omit<OptimizelyDecision, 'userContext'>
|
|
382
|
+
// }
|
|
383
|
+
// ),
|
|
384
|
+
// }),
|
|
385
|
+
// onReady: jest
|
|
386
|
+
// .fn()
|
|
387
|
+
// .mockResolvedValue({ success: false, reason: 'Promise rejected' }),
|
|
388
|
+
// }),
|
|
389
|
+
// }))
|
|
390
|
+
// const { getFlag } = require('../utils')
|
|
391
|
+
// const options: SDKConfig = {
|
|
392
|
+
// defaultFeatureFlags: {
|
|
393
|
+
// default_flag: {
|
|
394
|
+
// variationKey: 'off',
|
|
395
|
+
// enabled: true,
|
|
396
|
+
// variables: {},
|
|
397
|
+
// },
|
|
398
|
+
// },
|
|
399
|
+
// }
|
|
400
|
+
// const flag = await getFlag(
|
|
401
|
+
// 'testing_flag_with_variations_and_variables',
|
|
402
|
+
// options
|
|
403
|
+
// )
|
|
404
|
+
// expect(flag).toEqual(options.defaultFeatureFlags)
|
|
405
|
+
// })
|
|
406
|
+
// it('should return empty object when no default flag have been passed and optimizely client is not ready', async () => {
|
|
407
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
408
|
+
// createInstance: () => ({
|
|
409
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
410
|
+
// createUserContext: () => ({
|
|
411
|
+
// decide: jest
|
|
412
|
+
// .fn()
|
|
413
|
+
// .mockImplementation(
|
|
414
|
+
// (key: string, options?: OptimizelyDecideOption[]) => {
|
|
415
|
+
// return flagsMock[key] as Omit<OptimizelyDecision, 'userContext'>
|
|
416
|
+
// }
|
|
417
|
+
// ),
|
|
418
|
+
// }),
|
|
419
|
+
// onReady: jest
|
|
420
|
+
// .fn()
|
|
421
|
+
// .mockResolvedValue({ success: false, reason: 'Promise rejected' }),
|
|
422
|
+
// }),
|
|
423
|
+
// }))
|
|
424
|
+
// const { getFlag } = require('../utils')
|
|
425
|
+
// const flag = await getFlag('testing_flag_with_variations_and_variables')
|
|
426
|
+
// expect(flag).toEqual({})
|
|
427
|
+
// })
|
|
428
|
+
// })
|
|
429
|
+
// describe('getFlagsByKeys', () => {
|
|
430
|
+
// it('should return flags by keys with default options', async () => {
|
|
431
|
+
// const flagsByKeys = await getFlagsByKeys([
|
|
432
|
+
// 'another_test_flag_1',
|
|
433
|
+
// 'qualtrics_flag',
|
|
434
|
+
// ])
|
|
435
|
+
// expect(flagsByKeys).toEqual({
|
|
436
|
+
// qualtrics_flag: { variationKey: 'on', enabled: true, variables: {} },
|
|
437
|
+
// another_test_flag_1: {
|
|
438
|
+
// variationKey: 'off',
|
|
439
|
+
// enabled: false,
|
|
440
|
+
// variables: {},
|
|
441
|
+
// },
|
|
442
|
+
// })
|
|
443
|
+
// })
|
|
444
|
+
// it('should return empty object if no flags are fetched', async () => {
|
|
445
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
446
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk'),
|
|
447
|
+
// createInstance: () => ({
|
|
448
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
449
|
+
// createUserContext: () => ({
|
|
450
|
+
// decideForKeys: jest
|
|
451
|
+
// .fn()
|
|
452
|
+
// .mockImplementation((options?: OptimizelyDecideOption[]) => {
|
|
453
|
+
// return undefined
|
|
454
|
+
// }),
|
|
455
|
+
// }),
|
|
456
|
+
// onReady: jest.fn().mockResolvedValue({ success: true }),
|
|
457
|
+
// close: jest.fn().mockResolvedValue({ success: true }),
|
|
458
|
+
// }),
|
|
459
|
+
// }))
|
|
460
|
+
// const { getFlagsByKeys } = require('../utils')
|
|
461
|
+
// const flagsAll = await getFlagsByKeys([
|
|
462
|
+
// 'another_test_flag_1',
|
|
463
|
+
// 'qualtrics_flag',
|
|
464
|
+
// ])
|
|
465
|
+
// expect(flagsAll).toEqual({})
|
|
466
|
+
// })
|
|
467
|
+
// it('should return defaultFeatureFlags when they have been passed and optimizely client is not ready', async () => {
|
|
468
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
469
|
+
// createInstance: () => ({
|
|
470
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
471
|
+
// createUserContext: () => ({
|
|
472
|
+
// decideForKeys: jest
|
|
473
|
+
// .fn()
|
|
474
|
+
// .mockImplementation(
|
|
475
|
+
// (keys: string[], options?: OptimizelyDecideOption[]) => {
|
|
476
|
+
// const filtered: {
|
|
477
|
+
// [key: string]: Omit<OptimizelyDecision, 'userContext'>
|
|
478
|
+
// } = {}
|
|
479
|
+
// keys.forEach((k) => (filtered[k] = flagsMock[k]))
|
|
480
|
+
// return filtered
|
|
481
|
+
// }
|
|
482
|
+
// ),
|
|
483
|
+
// }),
|
|
484
|
+
// onReady: jest
|
|
485
|
+
// .fn()
|
|
486
|
+
// .mockResolvedValue({ success: false, reason: 'Promise rejected' }),
|
|
487
|
+
// }),
|
|
488
|
+
// }))
|
|
489
|
+
// const { getFlagsByKeys } = require('../utils')
|
|
490
|
+
// const options: SDKConfig = {
|
|
491
|
+
// defaultFeatureFlags: {
|
|
492
|
+
// default_flag: {
|
|
493
|
+
// variationKey: 'off',
|
|
494
|
+
// enabled: true,
|
|
495
|
+
// variables: {},
|
|
496
|
+
// },
|
|
497
|
+
// },
|
|
498
|
+
// }
|
|
499
|
+
// const flagsByKeys = await getFlagsByKeys(
|
|
500
|
+
// ['another_test_flag_1', 'qualtrics_flag'],
|
|
501
|
+
// options
|
|
502
|
+
// )
|
|
503
|
+
// expect(flagsByKeys).toEqual(options.defaultFeatureFlags)
|
|
504
|
+
// })
|
|
505
|
+
// it('should return empty object when no default flag have been passed and optimizely client is not ready', async () => {
|
|
506
|
+
// jest.doMock('@optimizely/optimizely-sdk', () => ({
|
|
507
|
+
// createInstance: () => ({
|
|
508
|
+
// ...jest.requireActual('@optimizely/optimizely-sdk').createInstance,
|
|
509
|
+
// createUserContext: () => ({
|
|
510
|
+
// decideForKeys: jest
|
|
511
|
+
// .fn()
|
|
512
|
+
// .mockImplementation(
|
|
513
|
+
// (keys: string[], options?: OptimizelyDecideOption[]) => {
|
|
514
|
+
// const filtered: {
|
|
515
|
+
// [key: string]: Omit<OptimizelyDecision, 'userContext'>
|
|
516
|
+
// } = {}
|
|
517
|
+
// keys.forEach((k) => (filtered[k] = flagsMock[k]))
|
|
518
|
+
// return filtered
|
|
519
|
+
// }
|
|
520
|
+
// ),
|
|
521
|
+
// }),
|
|
522
|
+
// onReady: jest
|
|
523
|
+
// .fn()
|
|
524
|
+
// .mockResolvedValue({ success: false, reason: 'Promise rejected' }),
|
|
525
|
+
// }),
|
|
526
|
+
// }))
|
|
527
|
+
// const { getFlagsByKeys } = require('../utils')
|
|
528
|
+
// const flagsByKeys = await getFlagsByKeys([
|
|
529
|
+
// 'another_test_flag_1',
|
|
530
|
+
// 'qualtrics_flag',
|
|
531
|
+
// ])
|
|
532
|
+
// expect(flagsByKeys).toEqual({})
|
|
533
|
+
// })
|
|
534
|
+
// })
|
|
535
|
+
//# sourceMappingURL=utils.tests.js.map
|