@featurevisor/sdk 0.47.4 → 0.47.6

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/dist/index.js.gz CHANGED
Binary file
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featurevisor/sdk",
3
- "version": "0.47.4",
3
+ "version": "0.47.6",
4
4
  "description": "Featurevisor SDK for Node.js and the browser",
5
5
  "main": "dist/index.js",
6
6
  "module": "lib/index.js",
@@ -49,5 +49,5 @@
49
49
  "compare-versions": "^6.0.0-rc.1",
50
50
  "murmurhash": "^2.0.1"
51
51
  },
52
- "gitHead": "a0a4cfe96b9223e7bfca022425c851c451b52b89"
52
+ "gitHead": "e7b6c3a8596d1df292b9c6857baf767e0839a245"
53
53
  }
@@ -393,6 +393,9 @@ describe("sdk: instance", function () {
393
393
  test: {
394
394
  enabled: true,
395
395
  variation: "control",
396
+ variables: {
397
+ color: "red",
398
+ },
396
399
  },
397
400
  },
398
401
  datafileUrl: "http://localhost:3000/datafile.json",
@@ -436,6 +439,11 @@ describe("sdk: instance", function () {
436
439
  userId: "123",
437
440
  }),
438
441
  ).toEqual("control");
442
+ expect(
443
+ sdk.getVariable("test", "color", {
444
+ userId: "123",
445
+ }),
446
+ ).toEqual("red");
439
447
 
440
448
  setTimeout(function () {
441
449
  // still control after fetching datafile
@@ -463,6 +471,9 @@ describe("sdk: instance", function () {
463
471
  test: {
464
472
  enabled: true,
465
473
  variation: "control",
474
+ variables: {
475
+ color: "red",
476
+ },
466
477
  },
467
478
  },
468
479
  datafileUrl: "http://localhost:3000/datafile.json",
@@ -506,6 +517,11 @@ describe("sdk: instance", function () {
506
517
  userId: "123",
507
518
  }),
508
519
  ).toEqual("control");
520
+ expect(
521
+ sdk.getVariable("test", "color", {
522
+ userId: "123",
523
+ }),
524
+ ).toEqual("red");
509
525
 
510
526
  setTimeout(function () {
511
527
  // treatment after fetching datafile
@@ -765,6 +781,105 @@ describe("sdk: instance", function () {
765
781
  expect(deprecatedCount).toEqual(1);
766
782
  });
767
783
 
784
+ it("should check if enabled for mutually exclusive features", function () {
785
+ let bucketValue = 10000;
786
+
787
+ const sdk = createInstance({
788
+ configureBucketValue: function () {
789
+ return bucketValue;
790
+ },
791
+
792
+ datafile: {
793
+ schemaVersion: "1",
794
+ revision: "1.0",
795
+ features: [
796
+ {
797
+ key: "mutex",
798
+ bucketBy: "userId",
799
+ ranges: [[0, 50000]],
800
+ traffic: [{ key: "1", segments: "*", percentage: 50000, allocation: [] }],
801
+ },
802
+ ],
803
+ attributes: [],
804
+ segments: [],
805
+ },
806
+ });
807
+
808
+ expect(sdk.isEnabled("test")).toEqual(false);
809
+ expect(sdk.isEnabled("test", { userId: "123" })).toEqual(false);
810
+
811
+ bucketValue = 40000;
812
+ expect(sdk.isEnabled("mutex", { userId: "123" })).toEqual(true);
813
+
814
+ bucketValue = 60000;
815
+ expect(sdk.isEnabled("mutex", { userId: "123" })).toEqual(false);
816
+ });
817
+
818
+ it("should get variation", function () {
819
+ const sdk = createInstance({
820
+ datafile: {
821
+ schemaVersion: "1",
822
+ revision: "1.0",
823
+ features: [
824
+ {
825
+ key: "test",
826
+ bucketBy: "userId",
827
+ variations: [{ value: "control" }, { value: "treatment" }],
828
+ force: [
829
+ {
830
+ conditions: [{ attribute: "userId", operator: "equals", value: "user-gb" }],
831
+ enabled: false,
832
+ },
833
+ {
834
+ segments: ["netherlands"],
835
+ enabled: false,
836
+ },
837
+ ],
838
+ traffic: [
839
+ {
840
+ key: "1",
841
+ segments: "*",
842
+ percentage: 100000,
843
+ allocation: [
844
+ { variation: "control", range: [0, 0] },
845
+ { variation: "treatment", range: [0, 100000] },
846
+ ],
847
+ },
848
+ ],
849
+ },
850
+ ],
851
+ attributes: [],
852
+ segments: [
853
+ {
854
+ key: "netherlands",
855
+ conditions: JSON.stringify([
856
+ {
857
+ attribute: "country",
858
+ operator: "equals",
859
+ value: "nl",
860
+ },
861
+ ]),
862
+ },
863
+ ],
864
+ },
865
+ });
866
+
867
+ const context = {
868
+ userId: "123",
869
+ };
870
+
871
+ expect(sdk.getVariation("test", context)).toEqual("treatment");
872
+ expect(sdk.getVariation("test", { userId: "user-ch" })).toEqual("treatment");
873
+
874
+ // non existing
875
+ expect(sdk.getVariation("nonExistingFeature", context)).toEqual(undefined);
876
+
877
+ // disabled
878
+ expect(sdk.getVariation("test", { userId: "user-gb" })).toEqual(undefined);
879
+ expect(sdk.getVariation("test", { userId: "user-gb" })).toEqual(undefined);
880
+ expect(sdk.getVariation("test", { userId: "123", country: "nl" })).toEqual(undefined);
881
+ });
882
+
768
883
  it("should get variable", function () {
769
884
  const sdk = createInstance({
770
885
  datafile: {
@@ -790,6 +905,11 @@ describe("sdk: instance", function () {
790
905
  type: "integer",
791
906
  defaultValue: 0,
792
907
  },
908
+ {
909
+ key: "price",
910
+ type: "double",
911
+ defaultValue: 9.99,
912
+ },
793
913
  {
794
914
  key: "paymentMethods",
795
915
  type: "array",
@@ -820,25 +940,101 @@ describe("sdk: instance", function () {
820
940
  {
821
941
  key: "showSidebar",
822
942
  value: true,
943
+ overrides: [
944
+ {
945
+ segments: ["netherlands"],
946
+ value: false,
947
+ },
948
+ {
949
+ conditions: [
950
+ {
951
+ attribute: "country",
952
+ operator: "equals",
953
+ value: "de",
954
+ },
955
+ ],
956
+ value: false,
957
+ },
958
+ ],
823
959
  },
824
960
  ],
825
961
  },
826
962
  ],
963
+ force: [
964
+ {
965
+ conditions: [{ attribute: "userId", operator: "equals", value: "user-ch" }],
966
+ enabled: true,
967
+ variation: "control",
968
+ variables: {
969
+ color: "red and white",
970
+ },
971
+ },
972
+ {
973
+ conditions: [{ attribute: "userId", operator: "equals", value: "user-gb" }],
974
+ enabled: false,
975
+ },
976
+ ],
827
977
  traffic: [
978
+ // belgium
979
+ {
980
+ key: "2",
981
+ segments: ["belgium"],
982
+ percentage: 100000,
983
+ allocation: [
984
+ { variation: "control", range: [0, 0] },
985
+ {
986
+ variation: "treatment",
987
+ range: [0, 100000],
988
+ },
989
+ ],
990
+ variation: "control",
991
+ variables: {
992
+ color: "black",
993
+ },
994
+ },
995
+
996
+ // everyone
828
997
  {
829
998
  key: "1",
830
999
  segments: "*",
831
1000
  percentage: 100000,
832
1001
  allocation: [
833
1002
  { variation: "control", range: [0, 0] },
834
- { variation: "treatment", range: [0, 100000] },
1003
+ {
1004
+ variation: "treatment",
1005
+ range: [0, 100000],
1006
+ },
835
1007
  ],
836
1008
  },
837
1009
  ],
838
1010
  },
839
1011
  ],
840
- attributes: [],
841
- segments: [],
1012
+ attributes: [
1013
+ { key: "userId", type: "string", capture: true },
1014
+ { key: "country", type: "string" },
1015
+ ],
1016
+ segments: [
1017
+ {
1018
+ key: "netherlands",
1019
+ conditions: JSON.stringify([
1020
+ {
1021
+ attribute: "country",
1022
+ operator: "equals",
1023
+ value: "nl",
1024
+ },
1025
+ ]),
1026
+ },
1027
+ {
1028
+ key: "belgium",
1029
+ conditions: JSON.stringify([
1030
+ {
1031
+ attribute: "country",
1032
+ operator: "equals",
1033
+ value: "be",
1034
+ },
1035
+ ]),
1036
+ },
1037
+ ],
842
1038
  },
843
1039
  });
844
1040
 
@@ -847,16 +1043,40 @@ describe("sdk: instance", function () {
847
1043
  };
848
1044
 
849
1045
  expect(sdk.getVariation("test", context)).toEqual("treatment");
1046
+ expect(
1047
+ sdk.getVariation("test", {
1048
+ ...context,
1049
+ country: "be",
1050
+ }),
1051
+ ).toEqual("control");
1052
+ expect(sdk.getVariation("test", { userId: "user-ch" })).toEqual("control");
850
1053
 
851
1054
  expect(sdk.getVariable("test", "color", context)).toEqual("red");
852
1055
  expect(sdk.getVariableString("test", "color", context)).toEqual("red");
1056
+ expect(sdk.getVariable("test", "color", { ...context, country: "be" })).toEqual("black");
1057
+ expect(sdk.getVariable("test", "color", { userId: "user-ch" })).toEqual("red and white");
853
1058
 
854
1059
  expect(sdk.getVariable("test", "showSidebar", context)).toEqual(true);
855
1060
  expect(sdk.getVariableBoolean("test", "showSidebar", context)).toEqual(true);
1061
+ expect(
1062
+ sdk.getVariableBoolean("test", "showSidebar", {
1063
+ ...context,
1064
+ country: "nl",
1065
+ }),
1066
+ ).toEqual(false);
1067
+ expect(
1068
+ sdk.getVariableBoolean("test", "showSidebar", {
1069
+ ...context,
1070
+ country: "de",
1071
+ }),
1072
+ ).toEqual(false);
856
1073
 
857
1074
  expect(sdk.getVariable("test", "count", context)).toEqual(0);
858
1075
  expect(sdk.getVariableInteger("test", "count", context)).toEqual(0);
859
1076
 
1077
+ expect(sdk.getVariable("test", "price", context)).toEqual(9.99);
1078
+ expect(sdk.getVariableDouble("test", "price", context)).toEqual(9.99);
1079
+
860
1080
  expect(sdk.getVariable("test", "paymentMethods", context)).toEqual(["paypal", "creditcard"]);
861
1081
  expect(sdk.getVariableArray("test", "paymentMethods", context)).toEqual([
862
1082
  "paypal",
@@ -880,5 +1100,12 @@ describe("sdk: instance", function () {
880
1100
  nested: "value",
881
1101
  },
882
1102
  });
1103
+
1104
+ // non existing
1105
+ expect(sdk.getVariable("test", "nonExisting", context)).toEqual(undefined);
1106
+ expect(sdk.getVariable("nonExistingFeature", "nonExisting", context)).toEqual(undefined);
1107
+
1108
+ // disabled
1109
+ expect(sdk.getVariable("test", "color", { userId: "user-gb" })).toEqual(undefined);
883
1110
  });
884
1111
  });
@@ -0,0 +1,154 @@
1
+ /* eslint-disable no-global-assign */
2
+
3
+ import { createLogger } from "./logger";
4
+
5
+ describe("logger", () => {
6
+ it("should log", () => {
7
+ const logger = createLogger({
8
+ levels: ["debug", "info", "warn", "error"],
9
+ handler: jest.fn(),
10
+ });
11
+
12
+ logger.debug("debug");
13
+ logger.info("info");
14
+ logger.warn("warn");
15
+ logger.error("error");
16
+
17
+ expect(logger).toBeDefined();
18
+ expect(logger.debug).toBeDefined();
19
+ expect(logger.info).toBeDefined();
20
+ expect(logger.warn).toBeDefined();
21
+ expect(logger.error).toBeDefined();
22
+ expect(logger.setLevels).toBeDefined();
23
+ expect(logger.log).toBeDefined();
24
+ expect(logger.log).toBeInstanceOf(Function);
25
+ expect(logger.debug).toBeInstanceOf(Function);
26
+ expect(logger.info).toBeInstanceOf(Function);
27
+ expect(logger.warn).toBeInstanceOf(Function);
28
+ expect(logger.error).toBeInstanceOf(Function);
29
+ expect(logger.setLevels).toBeInstanceOf(Function);
30
+ });
31
+
32
+ it("should log with custom levels", () => {
33
+ const logger = createLogger({
34
+ levels: ["debug", "info"],
35
+ handler: jest.fn(),
36
+ });
37
+
38
+ logger.debug("debug");
39
+ logger.info("info");
40
+ logger.warn("warn");
41
+ logger.error("error");
42
+
43
+ expect(logger).toBeDefined();
44
+ expect(logger.debug).toBeDefined();
45
+ expect(logger.info).toBeDefined();
46
+ expect(logger.warn).toBeDefined();
47
+ expect(logger.error).toBeDefined();
48
+ expect(logger.setLevels).toBeDefined();
49
+ expect(logger.log).toBeDefined();
50
+ expect(logger.log).toBeInstanceOf(Function);
51
+ expect(logger.debug).toBeInstanceOf(Function);
52
+ expect(logger.info).toBeInstanceOf(Function);
53
+ expect(logger.warn).toBeInstanceOf(Function);
54
+ expect(logger.error).toBeInstanceOf(Function);
55
+ expect(logger.setLevels).toBeInstanceOf(Function);
56
+ });
57
+
58
+ it("should log with default handler", () => {
59
+ const logs: any[] = [];
60
+
61
+ const realConsole = console;
62
+ const customConsole = {
63
+ log: (...args) => logs.push(args),
64
+ info: (...args) => logs.push(args),
65
+ warn: (...args) => logs.push(args),
66
+ error: (...args) => logs.push(args),
67
+ };
68
+
69
+ console = customConsole as unknown as Console; // eslint-ignore-line
70
+
71
+ const logger = createLogger({});
72
+
73
+ logger.setLevels(["debug", "info", "warn", "error"]);
74
+
75
+ logger.debug("debug");
76
+ logger.info("info");
77
+ logger.warn("warn");
78
+ logger.error("error");
79
+
80
+ expect(logger).toBeDefined();
81
+ expect(logger.debug).toBeDefined();
82
+ expect(logger.info).toBeDefined();
83
+ expect(logger.warn).toBeDefined();
84
+ expect(logger.error).toBeDefined();
85
+ expect(logger.setLevels).toBeDefined();
86
+ expect(logger.log).toBeDefined();
87
+ expect(logger.log).toBeInstanceOf(Function);
88
+ expect(logger.debug).toBeInstanceOf(Function);
89
+ expect(logger.info).toBeInstanceOf(Function);
90
+ expect(logger.warn).toBeInstanceOf(Function);
91
+ expect(logger.error).toBeInstanceOf(Function);
92
+ expect(logger.setLevels).toBeInstanceOf(Function);
93
+
94
+ expect(logs.length).toBe(4);
95
+
96
+ console = realConsole; // eslint-ignore-line
97
+ });
98
+
99
+ it("should log with custom handler", () => {
100
+ const handler = jest.fn();
101
+ const logger = createLogger({
102
+ levels: ["debug", "info", "warn", "error"],
103
+ handler,
104
+ });
105
+
106
+ logger.debug("debug");
107
+ logger.info("info");
108
+ logger.warn("warn");
109
+ logger.error("error");
110
+
111
+ expect(logger).toBeDefined();
112
+ expect(logger.debug).toBeDefined();
113
+ expect(logger.info).toBeDefined();
114
+ expect(logger.warn).toBeDefined();
115
+ expect(logger.error).toBeDefined();
116
+ expect(logger.setLevels).toBeDefined();
117
+ expect(logger.log).toBeDefined();
118
+ expect(logger.log).toBeInstanceOf(Function);
119
+ expect(logger.debug).toBeInstanceOf(Function);
120
+ expect(logger.info).toBeInstanceOf(Function);
121
+ expect(logger.warn).toBeInstanceOf(Function);
122
+ expect(logger.error).toBeInstanceOf(Function);
123
+ expect(logger.setLevels).toBeInstanceOf(Function);
124
+ expect(handler).toHaveBeenCalledTimes(4);
125
+ });
126
+
127
+ it("should log with custom levels and handler", () => {
128
+ const handler = jest.fn();
129
+ const logger = createLogger({
130
+ levels: ["debug", "info"],
131
+ handler,
132
+ });
133
+
134
+ logger.debug("debug");
135
+ logger.info("info");
136
+ logger.warn("warn");
137
+ logger.error("error");
138
+
139
+ expect(logger).toBeDefined();
140
+ expect(logger.debug).toBeDefined();
141
+ expect(logger.info).toBeDefined();
142
+ expect(logger.warn).toBeDefined();
143
+ expect(logger.error).toBeDefined();
144
+ expect(logger.setLevels).toBeDefined();
145
+ expect(logger.log).toBeDefined();
146
+ expect(logger.log).toBeInstanceOf(Function);
147
+ expect(logger.debug).toBeInstanceOf(Function);
148
+ expect(logger.info).toBeInstanceOf(Function);
149
+ expect(logger.warn).toBeInstanceOf(Function);
150
+ expect(logger.error).toBeInstanceOf(Function);
151
+ expect(logger.setLevels).toBeInstanceOf(Function);
152
+ expect(handler).toHaveBeenCalledTimes(2);
153
+ });
154
+ });