flagsmith-nodejs 1.1.3 → 2.0.0-beta.3
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/.github/workflows/pull_request.yaml +33 -0
- package/.gitmodules +3 -0
- package/.husky/pre-commit +6 -0
- package/.tool-versions +1 -0
- package/example/README.md +0 -6
- package/example/package-lock.json +1070 -2
- package/example/package.json +4 -3
- package/example/server/api/index.js +23 -18
- package/example/server/index.js +7 -6
- package/flagsmith-engine/environments/integrations/models.ts +4 -0
- package/flagsmith-engine/environments/models.ts +50 -0
- package/flagsmith-engine/environments/util.ts +29 -0
- package/flagsmith-engine/features/constants.ts +4 -0
- package/flagsmith-engine/features/models.ts +105 -0
- package/flagsmith-engine/features/util.ts +38 -0
- package/flagsmith-engine/identities/models.ts +60 -0
- package/flagsmith-engine/identities/traits/models.ts +9 -0
- package/flagsmith-engine/identities/util.ts +30 -0
- package/flagsmith-engine/index.ts +93 -0
- package/flagsmith-engine/organisations/models.ts +25 -0
- package/flagsmith-engine/organisations/util.ts +11 -0
- package/flagsmith-engine/projects/models.ts +22 -0
- package/flagsmith-engine/projects/util.ts +18 -0
- package/flagsmith-engine/segments/constants.ts +31 -0
- package/flagsmith-engine/segments/evaluators.ts +72 -0
- package/flagsmith-engine/segments/models.ts +103 -0
- package/flagsmith-engine/segments/util.ts +29 -0
- package/flagsmith-engine/utils/collections.ts +14 -0
- package/flagsmith-engine/utils/errors.ts +1 -0
- package/flagsmith-engine/utils/hashing/index.ts +52 -0
- package/flagsmith-engine/utils/index.ts +10 -0
- package/index.ts +6 -0
- package/jest.config.js +5 -0
- package/package.json +30 -12
- package/sdk/analytics.ts +60 -0
- package/sdk/errors.ts +2 -0
- package/sdk/index.ts +329 -0
- package/sdk/models.ts +145 -0
- package/sdk/polling_manager.ts +31 -0
- package/sdk/utils.ts +45 -0
- package/tests/engine/e2e/engine.test.ts +51 -0
- package/tests/engine/engine-tests/engine-test-data/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json +12393 -0
- package/tests/engine/engine-tests/engine-test-data/readme.md +30 -0
- package/tests/engine/unit/egine.test.ts +96 -0
- package/tests/engine/unit/environments/builder.test.ts +148 -0
- package/tests/engine/unit/environments/models.test.ts +49 -0
- package/tests/engine/unit/features/models.test.ts +72 -0
- package/tests/engine/unit/identities/identities_builders.test.ts +85 -0
- package/tests/engine/unit/identities/identities_models.test.ts +105 -0
- package/tests/engine/unit/organization/models.test.ts +12 -0
- package/tests/engine/unit/segments/segments_model.test.ts +101 -0
- package/tests/engine/unit/segments/util.ts +151 -0
- package/tests/engine/unit/utils.ts +114 -0
- package/tests/index.js +0 -0
- package/tests/sdk/analytics.test.ts +43 -0
- package/tests/sdk/data/environment.json +70 -0
- package/tests/sdk/data/flags.json +20 -0
- package/tests/sdk/data/identities.json +29 -0
- package/tests/sdk/flagsmith.test.ts +203 -0
- package/tests/sdk/polling.test.ts +34 -0
- package/tests/sdk/utils.ts +39 -0
- package/tsconfig.json +19 -0
- package/flagsmith-core.js +0 -243
- package/index.d.ts +0 -85
- package/index.js +0 -3
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_RULE,
|
|
3
|
+
ANY_RULE,
|
|
4
|
+
CONDITION_OPERATORS,
|
|
5
|
+
NONE_RULE
|
|
6
|
+
} from '../../../../flagsmith-engine/segments/constants';
|
|
7
|
+
import {
|
|
8
|
+
all,
|
|
9
|
+
any,
|
|
10
|
+
SegmentConditionModel,
|
|
11
|
+
SegmentRuleModel
|
|
12
|
+
} from '../../../../flagsmith-engine/segments/models';
|
|
13
|
+
|
|
14
|
+
const conditionMatchCases: [string, string | number | boolean, string, boolean][] = [
|
|
15
|
+
[CONDITION_OPERATORS.EQUAL, 'bar', 'bar', true],
|
|
16
|
+
[CONDITION_OPERATORS.EQUAL, 'bar', 'baz', false],
|
|
17
|
+
[CONDITION_OPERATORS.EQUAL, 1, '1', true],
|
|
18
|
+
[CONDITION_OPERATORS.EQUAL, 1, '2', false],
|
|
19
|
+
[CONDITION_OPERATORS.EQUAL, true, 'true', true],
|
|
20
|
+
[CONDITION_OPERATORS.EQUAL, false, 'false', true],
|
|
21
|
+
[CONDITION_OPERATORS.EQUAL, false, 'true', false],
|
|
22
|
+
[CONDITION_OPERATORS.EQUAL, true, 'false', false],
|
|
23
|
+
[CONDITION_OPERATORS.EQUAL, 1.23, '1.23', true],
|
|
24
|
+
[CONDITION_OPERATORS.EQUAL, 1.23, '4.56', false],
|
|
25
|
+
[CONDITION_OPERATORS.GREATER_THAN, 2, '1', true],
|
|
26
|
+
[CONDITION_OPERATORS.GREATER_THAN, 1, '1', false],
|
|
27
|
+
[CONDITION_OPERATORS.GREATER_THAN, 0, '1', false],
|
|
28
|
+
[CONDITION_OPERATORS.GREATER_THAN, 2.1, '2.0', true],
|
|
29
|
+
[CONDITION_OPERATORS.GREATER_THAN, 2.1, '2.1', false],
|
|
30
|
+
[CONDITION_OPERATORS.GREATER_THAN, 2.0, '2.1', false],
|
|
31
|
+
[CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2, '1', true],
|
|
32
|
+
[CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 1, '1', true],
|
|
33
|
+
[CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 0, '1', false],
|
|
34
|
+
[CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2.1, '2.0', true],
|
|
35
|
+
[CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2.1, '2.1', true],
|
|
36
|
+
[CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, 2.0, '2.1', false],
|
|
37
|
+
[CONDITION_OPERATORS.LESS_THAN, 1, '2', true],
|
|
38
|
+
[CONDITION_OPERATORS.LESS_THAN, 1, '1', false],
|
|
39
|
+
[CONDITION_OPERATORS.LESS_THAN, 1, '0', false],
|
|
40
|
+
[CONDITION_OPERATORS.LESS_THAN, 2.0, '2.1', true],
|
|
41
|
+
[CONDITION_OPERATORS.LESS_THAN, 2.1, '2.1', false],
|
|
42
|
+
[CONDITION_OPERATORS.LESS_THAN, 2.1, '2.0', false],
|
|
43
|
+
[CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 1, '2', true],
|
|
44
|
+
[CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 1, '1', true],
|
|
45
|
+
[CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 1, '0', false],
|
|
46
|
+
[CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 2.0, '2.1', true],
|
|
47
|
+
[CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 2.1, '2.1', true],
|
|
48
|
+
[CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, 2.1, '2.0', false],
|
|
49
|
+
[CONDITION_OPERATORS.NOT_EQUAL, 'bar', 'baz', true],
|
|
50
|
+
[CONDITION_OPERATORS.NOT_EQUAL, 'bar', 'bar', false],
|
|
51
|
+
[CONDITION_OPERATORS.NOT_EQUAL, 1, '2', true],
|
|
52
|
+
[CONDITION_OPERATORS.NOT_EQUAL, 1, '1', false],
|
|
53
|
+
[CONDITION_OPERATORS.NOT_EQUAL, true, 'false', true],
|
|
54
|
+
[CONDITION_OPERATORS.NOT_EQUAL, false, 'true', true],
|
|
55
|
+
[CONDITION_OPERATORS.NOT_EQUAL, false, 'false', false],
|
|
56
|
+
[CONDITION_OPERATORS.NOT_EQUAL, true, 'true', false],
|
|
57
|
+
[CONDITION_OPERATORS.CONTAINS, 'bar', 'b', true],
|
|
58
|
+
[CONDITION_OPERATORS.CONTAINS, 'bar', 'bar', true],
|
|
59
|
+
[CONDITION_OPERATORS.CONTAINS, 'bar', 'baz', false],
|
|
60
|
+
[CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'b', false],
|
|
61
|
+
[CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'bar', false],
|
|
62
|
+
[CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'baz', true],
|
|
63
|
+
[CONDITION_OPERATORS.REGEX, 'foo', '[a-z]+', true],
|
|
64
|
+
[CONDITION_OPERATORS.REGEX, 'FOO', '[a-z]+', false]
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
test('test_segment_condition_matches_trait_value', () => {
|
|
68
|
+
for (const testCase of conditionMatchCases) {
|
|
69
|
+
expect(
|
|
70
|
+
new SegmentConditionModel(testCase[0], testCase[2], 'foo').matchesTraitValue(
|
|
71
|
+
testCase[1]
|
|
72
|
+
)
|
|
73
|
+
).toBe(testCase[3]);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('test_segment_rule_none', () => {
|
|
78
|
+
const testCases: [boolean[], boolean][] = [
|
|
79
|
+
[[], true],
|
|
80
|
+
[[false], true],
|
|
81
|
+
[[false, false], true],
|
|
82
|
+
[[false, true], false],
|
|
83
|
+
[[true, true], false]
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
for (const testCase of testCases) {
|
|
87
|
+
expect(SegmentRuleModel.none(testCase[0])).toBe(testCase[1]);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('test_segment_rule_matching_function', () => {
|
|
92
|
+
const testCases: [string, CallableFunction][] = [
|
|
93
|
+
[ALL_RULE, all],
|
|
94
|
+
[ANY_RULE, any],
|
|
95
|
+
[NONE_RULE, SegmentRuleModel.none]
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
for (const testCase of testCases) {
|
|
99
|
+
expect(new SegmentRuleModel(testCase[0]).matchingFunction()).toBe(testCase[1]);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { ALL_RULE, ANY_RULE, EQUAL } from '../../../../flagsmith-engine/segments/constants';
|
|
2
|
+
import { SegmentModel } from '../../../../flagsmith-engine/segments/models';
|
|
3
|
+
import { buildSegmentModel } from '../../../../flagsmith-engine/segments/util';
|
|
4
|
+
|
|
5
|
+
export const traitKey1 = 'email';
|
|
6
|
+
export const traitValue1 = 'user@example.com';
|
|
7
|
+
|
|
8
|
+
export const traitKey2 = 'num_purchase';
|
|
9
|
+
export const traitValue2 = '12';
|
|
10
|
+
|
|
11
|
+
export const traitKey_3 = 'date_joined';
|
|
12
|
+
export const traitValue3 = '2021-01-01';
|
|
13
|
+
|
|
14
|
+
export const emptySegment = new SegmentModel(1, 'empty_segment');
|
|
15
|
+
|
|
16
|
+
export const segmentSingleCondition = buildSegmentModel({
|
|
17
|
+
id: 2,
|
|
18
|
+
name: 'segment_one_condition',
|
|
19
|
+
rules: [
|
|
20
|
+
{
|
|
21
|
+
type: ALL_RULE,
|
|
22
|
+
conditions: [
|
|
23
|
+
{
|
|
24
|
+
operator: EQUAL,
|
|
25
|
+
property_: traitKey1,
|
|
26
|
+
value: traitValue1
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const segmentMultipleConditionsAll = buildSegmentModel({
|
|
34
|
+
id: 3,
|
|
35
|
+
name: 'segment_multiple_conditions_all',
|
|
36
|
+
rules: [
|
|
37
|
+
{
|
|
38
|
+
type: ALL_RULE,
|
|
39
|
+
conditions: [
|
|
40
|
+
{
|
|
41
|
+
operator: EQUAL,
|
|
42
|
+
property_: traitKey1,
|
|
43
|
+
value: traitValue1
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
operator: EQUAL,
|
|
47
|
+
property_: traitKey2,
|
|
48
|
+
value: traitValue2
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const segmentMultipleConditionsAny = buildSegmentModel({
|
|
56
|
+
id: 4,
|
|
57
|
+
name: 'segment_multiple_conditions_any',
|
|
58
|
+
rules: [
|
|
59
|
+
{
|
|
60
|
+
type: ANY_RULE,
|
|
61
|
+
conditions: [
|
|
62
|
+
{
|
|
63
|
+
operator: EQUAL,
|
|
64
|
+
property_: traitKey1,
|
|
65
|
+
value: traitValue1
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
operator: EQUAL,
|
|
69
|
+
property_: traitKey2,
|
|
70
|
+
value: traitValue2
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
export const segmentNestedRules = buildSegmentModel({
|
|
78
|
+
id: 5,
|
|
79
|
+
name: 'segment_nested_rules_all',
|
|
80
|
+
rules: [
|
|
81
|
+
{
|
|
82
|
+
type: ALL_RULE,
|
|
83
|
+
rules: [
|
|
84
|
+
{
|
|
85
|
+
type: ALL_RULE,
|
|
86
|
+
conditions: [
|
|
87
|
+
{
|
|
88
|
+
operator: EQUAL,
|
|
89
|
+
property_: traitKey1,
|
|
90
|
+
value: traitValue1
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
operator: EQUAL,
|
|
94
|
+
property_: traitKey2,
|
|
95
|
+
value: traitValue2
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
type: ALL_RULE,
|
|
101
|
+
conditions: [
|
|
102
|
+
{
|
|
103
|
+
operator: EQUAL,
|
|
104
|
+
property_: traitKey_3,
|
|
105
|
+
value: traitValue3
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
export const segmentConditionsAndNestedRules = buildSegmentModel({
|
|
115
|
+
id: 6,
|
|
116
|
+
name: 'segment_multiple_conditions_all_and_nested_rules',
|
|
117
|
+
rules: [
|
|
118
|
+
{
|
|
119
|
+
type: ALL_RULE,
|
|
120
|
+
conditions: [
|
|
121
|
+
{
|
|
122
|
+
operator: EQUAL,
|
|
123
|
+
property_: traitKey1,
|
|
124
|
+
value: traitValue1
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
rules: [
|
|
128
|
+
{
|
|
129
|
+
type: ALL_RULE,
|
|
130
|
+
conditions: [
|
|
131
|
+
{
|
|
132
|
+
operator: EQUAL,
|
|
133
|
+
property_: traitKey2,
|
|
134
|
+
value: traitValue2
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
type: ALL_RULE,
|
|
140
|
+
conditions: [
|
|
141
|
+
{
|
|
142
|
+
operator: EQUAL,
|
|
143
|
+
property_: traitKey_3,
|
|
144
|
+
value: traitValue3
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { EnvironmentModel } from '../../../flagsmith-engine/environments/models';
|
|
2
|
+
import { CONSTANTS } from '../../../flagsmith-engine/features/constants';
|
|
3
|
+
import { FeatureModel, FeatureStateModel } from '../../../flagsmith-engine/features/models';
|
|
4
|
+
import { IdentityModel } from '../../../flagsmith-engine/identities/models';
|
|
5
|
+
import { TraitModel } from '../../../flagsmith-engine/identities/traits/models';
|
|
6
|
+
import { OrganisationModel } from '../../../flagsmith-engine/organisations/models';
|
|
7
|
+
import { ProjectModel } from '../../../flagsmith-engine/projects/models';
|
|
8
|
+
import { ALL_RULE, EQUAL } from '../../../flagsmith-engine/segments/constants';
|
|
9
|
+
import {
|
|
10
|
+
SegmentConditionModel,
|
|
11
|
+
SegmentModel,
|
|
12
|
+
SegmentRuleModel
|
|
13
|
+
} from '../../../flagsmith-engine/segments/models';
|
|
14
|
+
|
|
15
|
+
export const segmentConditionProperty = 'foo';
|
|
16
|
+
export const segmentConditionStringValue = 'bar';
|
|
17
|
+
|
|
18
|
+
export function segmentCondition() {
|
|
19
|
+
return new SegmentConditionModel(EQUAL, segmentConditionStringValue, segmentConditionProperty);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function traitMatchingSegment() {
|
|
23
|
+
return new TraitModel(segmentCondition().property_ as string, segmentCondition().value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function organisation() {
|
|
27
|
+
return new OrganisationModel(1, 'test Org', true, false, true);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function segmentRule() {
|
|
31
|
+
const rule = new SegmentRuleModel(ALL_RULE);
|
|
32
|
+
rule.conditions = [segmentCondition()];
|
|
33
|
+
return rule;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function segment() {
|
|
37
|
+
const segment = new SegmentModel(1, 'test name');
|
|
38
|
+
segment.rules = [segmentRule()];
|
|
39
|
+
return segment;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function project() {
|
|
43
|
+
const project = new ProjectModel(1, 'test project', false, organisation());
|
|
44
|
+
project.segments = [segment()];
|
|
45
|
+
return project;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function feature1() {
|
|
49
|
+
return new FeatureModel(1, 'feature_1', CONSTANTS.STANDARD);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function feature2() {
|
|
53
|
+
return new FeatureModel(2, 'feature_2', CONSTANTS.STANDARD);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function environment() {
|
|
57
|
+
const env = new EnvironmentModel(1, 'api-key', project());
|
|
58
|
+
|
|
59
|
+
env.featureStates = [
|
|
60
|
+
new FeatureStateModel(feature1(), true, 1),
|
|
61
|
+
new FeatureStateModel(feature2(), false, 2)
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
return env;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function identity() {
|
|
68
|
+
return new IdentityModel(Date.now().toString(), [], [], environment().apiKey, 'identity_1');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function identityInSegment() {
|
|
72
|
+
const identity = new IdentityModel(
|
|
73
|
+
Date.now().toString(),
|
|
74
|
+
[],
|
|
75
|
+
[],
|
|
76
|
+
environment().apiKey,
|
|
77
|
+
'identity_2'
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
identity.identityTraits = [traitMatchingSegment()];
|
|
81
|
+
|
|
82
|
+
return identity;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getEnvironmentFeatureStateForFeatureByName(
|
|
86
|
+
environment: EnvironmentModel,
|
|
87
|
+
feature_name: string
|
|
88
|
+
): FeatureStateModel | undefined {
|
|
89
|
+
const features = environment.featureStates.filter(fs => fs.feature.name === feature_name);
|
|
90
|
+
return features.length > 0 ? features[0] : undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getEnvironmentFeatureStateForFeature(
|
|
94
|
+
environment: EnvironmentModel,
|
|
95
|
+
feature: FeatureModel
|
|
96
|
+
): FeatureStateModel | undefined {
|
|
97
|
+
const f = environment.featureStates.find(f => f.feature === feature);
|
|
98
|
+
return f;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function segmentOverrideFs() {
|
|
102
|
+
const fs = new FeatureStateModel(feature1(), false, 4);
|
|
103
|
+
fs.setValue('segment_override');
|
|
104
|
+
return fs;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function environmentWithSegmentOverride(): EnvironmentModel {
|
|
108
|
+
const env = environment();
|
|
109
|
+
const segm = segment();
|
|
110
|
+
|
|
111
|
+
segm.featureStates.push(segmentOverrideFs());
|
|
112
|
+
env.project.segments.push(segm);
|
|
113
|
+
return env;
|
|
114
|
+
}
|
package/tests/index.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
jest.mock('node-fetch');
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
import { analyticsProcessor } from './utils';
|
|
4
|
+
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
jest.clearAllMocks();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test('test_analytics_processor_track_feature_updates_analytics_data', () => {
|
|
10
|
+
const aP = analyticsProcessor();
|
|
11
|
+
aP.trackFeature(1);
|
|
12
|
+
expect(aP.analyticsData[1]).toBe(1);
|
|
13
|
+
|
|
14
|
+
aP.trackFeature(1);
|
|
15
|
+
expect(aP.analyticsData[1]).toBe(2);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('test_analytics_processor_flush_clears_analytics_data', async () => {
|
|
19
|
+
const aP = analyticsProcessor();
|
|
20
|
+
aP.trackFeature(1);
|
|
21
|
+
await aP.flush();
|
|
22
|
+
expect(aP.analyticsData).toStrictEqual({});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('test_analytics_processor_flush_post_request_data_match_ananlytics_data', async () => {
|
|
26
|
+
const aP = analyticsProcessor();
|
|
27
|
+
aP.trackFeature(1);
|
|
28
|
+
aP.trackFeature(2);
|
|
29
|
+
await aP.flush();
|
|
30
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
31
|
+
expect(fetch).toHaveBeenCalledWith('http://testUrlanalytics/flags/', {
|
|
32
|
+
body: '{"1":1,"2":1}',
|
|
33
|
+
headers: { 'Content-Type': 'application/json', 'X-Environment-Key': 'test-key' },
|
|
34
|
+
method: 'POST',
|
|
35
|
+
timeout: 3
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('test_analytics_processor_flush_early_exit_if_analytics_data_is_empty', async () => {
|
|
40
|
+
const aP = analyticsProcessor();
|
|
41
|
+
await aP.flush();
|
|
42
|
+
expect(fetch).not.toHaveBeenCalled();
|
|
43
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"api_key": "B62qaMZNwfiqT76p38ggrQ",
|
|
3
|
+
"project": {
|
|
4
|
+
"name": "Test project",
|
|
5
|
+
"organisation": {
|
|
6
|
+
"feature_analytics": false,
|
|
7
|
+
"name": "Test Org",
|
|
8
|
+
"id": 1,
|
|
9
|
+
"persist_trait_data": true,
|
|
10
|
+
"stop_serving_flags": false
|
|
11
|
+
},
|
|
12
|
+
"id": 1,
|
|
13
|
+
"hide_disabled_flags": false,
|
|
14
|
+
"segments": [
|
|
15
|
+
{
|
|
16
|
+
"name": "regular_segment",
|
|
17
|
+
"feature_states": [
|
|
18
|
+
{
|
|
19
|
+
"feature_state_value": "segment_override",
|
|
20
|
+
"multivariate_feature_state_values": [],
|
|
21
|
+
"django_id": 81027,
|
|
22
|
+
"feature": {
|
|
23
|
+
"name": "some_feature",
|
|
24
|
+
"type": "STANDARD",
|
|
25
|
+
"id": 1
|
|
26
|
+
},
|
|
27
|
+
"enabled": false
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"id": 1,
|
|
31
|
+
"rules": [
|
|
32
|
+
{
|
|
33
|
+
"type": "ALL",
|
|
34
|
+
"conditions": [],
|
|
35
|
+
"rules": [
|
|
36
|
+
{
|
|
37
|
+
"type": "ANY",
|
|
38
|
+
"conditions": [
|
|
39
|
+
{
|
|
40
|
+
"value": "40",
|
|
41
|
+
"property_": "age",
|
|
42
|
+
"operator": "LESS_THAN"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"rules": []
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"segment_overrides": [],
|
|
54
|
+
"id": 1,
|
|
55
|
+
"feature_states": [
|
|
56
|
+
{
|
|
57
|
+
"multivariate_feature_state_values": [],
|
|
58
|
+
"feature_state_value": "some-value",
|
|
59
|
+
"id": 1,
|
|
60
|
+
"featurestate_uuid": "40eb539d-3713-4720-bbd4-829dbef10d51",
|
|
61
|
+
"feature": {
|
|
62
|
+
"name": "some_feature",
|
|
63
|
+
"type": "STANDARD",
|
|
64
|
+
"id": 1
|
|
65
|
+
},
|
|
66
|
+
"segment_id": null,
|
|
67
|
+
"enabled": true
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": 1,
|
|
4
|
+
"feature": {
|
|
5
|
+
"id": 1,
|
|
6
|
+
"name": "some_feature",
|
|
7
|
+
"created_date": "2019-08-27T14:53:45.698555Z",
|
|
8
|
+
"initial_value": null,
|
|
9
|
+
"description": null,
|
|
10
|
+
"default_enabled": false,
|
|
11
|
+
"type": "STANDARD",
|
|
12
|
+
"project": 1
|
|
13
|
+
},
|
|
14
|
+
"feature_state_value": "some-value",
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"environment": 1,
|
|
17
|
+
"identity": null,
|
|
18
|
+
"feature_segment": null
|
|
19
|
+
}
|
|
20
|
+
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"traits": [
|
|
3
|
+
{
|
|
4
|
+
"id": 1,
|
|
5
|
+
"trait_key": "some_trait",
|
|
6
|
+
"trait_value": "some_value"
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"flags": [
|
|
10
|
+
{
|
|
11
|
+
"id": 1,
|
|
12
|
+
"feature": {
|
|
13
|
+
"id": 1,
|
|
14
|
+
"name": "some_feature",
|
|
15
|
+
"created_date": "2019-08-27T14:53:45.698555Z",
|
|
16
|
+
"initial_value": null,
|
|
17
|
+
"description": null,
|
|
18
|
+
"default_enabled": false,
|
|
19
|
+
"type": "STANDARD",
|
|
20
|
+
"project": 1
|
|
21
|
+
},
|
|
22
|
+
"feature_state_value": "some-value",
|
|
23
|
+
"enabled": true,
|
|
24
|
+
"environment": 1,
|
|
25
|
+
"identity": null,
|
|
26
|
+
"feature_segment": null
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|