@featurevisor/core 0.53.0 → 0.53.2

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.
Files changed (43) hide show
  1. package/.eslintcache +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/coverage/clover.xml +2 -2
  4. package/coverage/lcov-report/index.html +1 -1
  5. package/coverage/lcov-report/lib/builder/allocator.js.html +1 -1
  6. package/coverage/lcov-report/lib/builder/index.html +1 -1
  7. package/coverage/lcov-report/lib/builder/traffic.js.html +1 -1
  8. package/coverage/lcov-report/src/builder/allocator.ts.html +1 -1
  9. package/coverage/lcov-report/src/builder/index.html +1 -1
  10. package/coverage/lcov-report/src/builder/traffic.ts.html +1 -1
  11. package/lib/tester/checkIfArraysAreEqual.d.ts +1 -0
  12. package/lib/tester/checkIfArraysAreEqual.js +19 -0
  13. package/lib/tester/checkIfArraysAreEqual.js.map +1 -0
  14. package/lib/tester/checkIfObjectsAreEqual.d.ts +1 -0
  15. package/lib/tester/checkIfObjectsAreEqual.js +22 -0
  16. package/lib/tester/checkIfObjectsAreEqual.js.map +1 -0
  17. package/lib/tester/cliFormat.d.ts +3 -0
  18. package/lib/tester/cliFormat.js +7 -0
  19. package/lib/tester/cliFormat.js.map +1 -0
  20. package/lib/tester/index.d.ts +1 -0
  21. package/lib/tester/index.js +18 -0
  22. package/lib/tester/index.js.map +1 -0
  23. package/lib/tester/testFeature.d.ts +4 -0
  24. package/lib/tester/testFeature.js +75 -0
  25. package/lib/tester/testFeature.js.map +1 -0
  26. package/lib/tester/testProject.d.ts +2 -0
  27. package/lib/tester/testProject.js +61 -0
  28. package/lib/tester/testProject.js.map +1 -0
  29. package/lib/tester/testSegment.d.ts +3 -0
  30. package/lib/tester/testSegment.js +31 -0
  31. package/lib/tester/testSegment.js.map +1 -0
  32. package/package.json +2 -2
  33. package/src/tester/checkIfArraysAreEqual.ts +16 -0
  34. package/src/tester/checkIfObjectsAreEqual.ts +21 -0
  35. package/src/tester/cliFormat.ts +4 -0
  36. package/src/tester/index.ts +1 -0
  37. package/src/tester/testFeature.ts +116 -0
  38. package/src/tester/testProject.ts +73 -0
  39. package/src/tester/testSegment.ts +43 -0
  40. package/lib/tester.d.ts +0 -4
  41. package/lib/tester.js +0 -159
  42. package/lib/tester.js.map +0 -1
  43. package/src/tester.ts +0 -213
@@ -0,0 +1 @@
1
+ export * from "./testProject";
@@ -0,0 +1,116 @@
1
+ import * as fs from "fs";
2
+
3
+ import { TestFeature, ExistingState } from "@featurevisor/types";
4
+ import { createInstance, MAX_BUCKETED_NUMBER } from "@featurevisor/sdk";
5
+
6
+ import { Datasource } from "../datasource";
7
+ import { ProjectConfig } from "../config";
8
+ import { buildDatafile, getExistingStateFilePath } from "../builder";
9
+ import { SCHEMA_VERSION } from "../config";
10
+
11
+ import { checkIfArraysAreEqual } from "./checkIfArraysAreEqual";
12
+ import { checkIfObjectsAreEqual } from "./checkIfObjectsAreEqual";
13
+ import { CLI_FORMAT_BOLD, CLI_FORMAT_RED } from "./cliFormat";
14
+
15
+ export function testFeature(
16
+ datasource: Datasource,
17
+ projectConfig: ProjectConfig,
18
+ test: TestFeature,
19
+ ): boolean {
20
+ let hasError = false;
21
+ const featureKey = test.feature;
22
+
23
+ console.log(CLI_FORMAT_BOLD, ` Feature "${featureKey}":`);
24
+
25
+ test.assertions.forEach(function (assertion, aIndex) {
26
+ const description = assertion.description || `at ${assertion.at}%`;
27
+
28
+ console.log(` Assertion #${aIndex + 1}: (${assertion.environment}) ${description}`);
29
+
30
+ const featuresToInclude = Array.from(datasource.getRequiredFeaturesChain(test.feature));
31
+
32
+ const datafileContent = buildDatafile(
33
+ projectConfig,
34
+ datasource,
35
+ {
36
+ schemaVersion: SCHEMA_VERSION,
37
+ revision: "testing",
38
+ environment: assertion.environment,
39
+ features: featuresToInclude,
40
+ },
41
+ JSON.parse(
42
+ fs.readFileSync(getExistingStateFilePath(projectConfig, assertion.environment), "utf8"),
43
+ ) as ExistingState,
44
+ );
45
+
46
+ const sdk = createInstance({
47
+ datafile: datafileContent,
48
+ configureBucketValue: () => {
49
+ return assertion.at * (MAX_BUCKETED_NUMBER / 100);
50
+ },
51
+ // logger: createLogger({
52
+ // levels: ["debug", "info", "warn", "error"],
53
+ // }),
54
+ });
55
+
56
+ // isEnabled
57
+ if ("expectedToBeEnabled" in assertion) {
58
+ const isEnabled = sdk.isEnabled(featureKey, assertion.context);
59
+
60
+ if (isEnabled !== assertion.expectedToBeEnabled) {
61
+ hasError = true;
62
+
63
+ console.error(
64
+ CLI_FORMAT_RED,
65
+ ` isEnabled failed: expected "${assertion.expectedToBeEnabled}", got "${isEnabled}"`,
66
+ );
67
+ }
68
+ }
69
+
70
+ // variation
71
+ if ("expectedVariation" in assertion) {
72
+ const variation = sdk.getVariation(featureKey, assertion.context);
73
+
74
+ if (variation !== assertion.expectedVariation) {
75
+ hasError = true;
76
+
77
+ console.error(
78
+ CLI_FORMAT_RED,
79
+ ` Variation failed: expected "${assertion.expectedVariation}", got "${variation}"`,
80
+ );
81
+ }
82
+ }
83
+
84
+ // variables
85
+ if (typeof assertion.expectedVariables === "object") {
86
+ Object.keys(assertion.expectedVariables).forEach(function (variableKey) {
87
+ const expectedValue =
88
+ assertion.expectedVariables && assertion.expectedVariables[variableKey];
89
+ const actualValue = sdk.getVariable(featureKey, variableKey, assertion.context);
90
+
91
+ let passed;
92
+
93
+ if (typeof expectedValue === "object") {
94
+ passed = checkIfObjectsAreEqual(expectedValue, actualValue);
95
+ } else if (Array.isArray(expectedValue)) {
96
+ passed = checkIfArraysAreEqual(expectedValue, actualValue);
97
+ } else {
98
+ passed = expectedValue === actualValue;
99
+ }
100
+
101
+ if (!passed) {
102
+ hasError = true;
103
+
104
+ console.error(
105
+ CLI_FORMAT_RED,
106
+ ` Variable "${variableKey}" failed: expected ${JSON.stringify(
107
+ expectedValue,
108
+ )}, got "${JSON.stringify(actualValue)}"`,
109
+ );
110
+ }
111
+ });
112
+ }
113
+ });
114
+
115
+ return hasError;
116
+ }
@@ -0,0 +1,73 @@
1
+ import * as fs from "fs";
2
+
3
+ import { TestSegment, TestFeature } from "@featurevisor/types";
4
+
5
+ import { ProjectConfig } from "../config";
6
+ import { Datasource } from "../datasource";
7
+
8
+ import { testSegment } from "./testSegment";
9
+ import { testFeature } from "./testFeature";
10
+ import { CLI_FORMAT_BOLD, CLI_FORMAT_GREEN, CLI_FORMAT_RED } from "./cliFormat";
11
+
12
+ export function testProject(rootDirectoryPath: string, projectConfig: ProjectConfig): boolean {
13
+ let hasError = false;
14
+ const datasource = new Datasource(projectConfig);
15
+
16
+ if (!fs.existsSync(projectConfig.testsDirectoryPath)) {
17
+ console.error(`Tests directory does not exist: ${projectConfig.testsDirectoryPath}`);
18
+ hasError = true;
19
+
20
+ return hasError;
21
+ }
22
+
23
+ const testFiles = datasource.listTests();
24
+
25
+ if (testFiles.length === 0) {
26
+ console.error(`No tests found in: ${projectConfig.testsDirectoryPath}`);
27
+ hasError = true;
28
+
29
+ return hasError;
30
+ }
31
+
32
+ for (const testFile of testFiles) {
33
+ const testFilePath = datasource.getEntityPath("test", testFile);
34
+
35
+ console.log("");
36
+ console.log(CLI_FORMAT_BOLD, `Testing: ${testFilePath.replace(rootDirectoryPath, "")}`);
37
+
38
+ const t = datasource.readTest(testFile);
39
+
40
+ if ((t as TestSegment).segment) {
41
+ // segment testing
42
+ const test = t as TestSegment;
43
+
44
+ const segmentHasError = testSegment(datasource, test);
45
+
46
+ if (segmentHasError) {
47
+ hasError = true;
48
+ }
49
+ } else if ((t as TestFeature).feature) {
50
+ // feature testing
51
+ const test = t as TestFeature;
52
+
53
+ const featureHasError = testFeature(datasource, projectConfig, test);
54
+
55
+ if (featureHasError) {
56
+ hasError = true;
57
+ }
58
+ } else {
59
+ console.error(` => Invalid test: ${JSON.stringify(test)}`);
60
+ hasError = true;
61
+ }
62
+ }
63
+
64
+ console.log("");
65
+ if (hasError) {
66
+ console.log(CLI_FORMAT_RED, `Some tests failed`);
67
+ } else {
68
+ console.log(CLI_FORMAT_GREEN, `All tests passed`);
69
+ }
70
+ console.log("");
71
+
72
+ return hasError;
73
+ }
@@ -0,0 +1,43 @@
1
+ import { TestSegment, Condition } from "@featurevisor/types";
2
+ import { allConditionsAreMatched } from "@featurevisor/sdk";
3
+
4
+ import { Datasource } from "../datasource";
5
+
6
+ import { CLI_FORMAT_BOLD, CLI_FORMAT_RED } from "./cliFormat";
7
+
8
+ export function testSegment(datasource: Datasource, test: TestSegment): boolean {
9
+ let hasError = false;
10
+
11
+ const segmentKey = test.segment;
12
+
13
+ console.log(CLI_FORMAT_BOLD, ` Segment "${segmentKey}":`);
14
+
15
+ const segmentExists = datasource.entityExists("segment", segmentKey);
16
+
17
+ if (!segmentExists) {
18
+ console.error(CLI_FORMAT_RED, ` Segment does not exist: ${segmentKey}`);
19
+ hasError = true;
20
+
21
+ return hasError;
22
+ }
23
+
24
+ const parsedSegment = datasource.readSegment(segmentKey);
25
+ const conditions = parsedSegment.conditions as Condition | Condition[];
26
+
27
+ test.assertions.forEach(function (assertion, aIndex) {
28
+ const description = assertion.description || `#${aIndex + 1}`;
29
+
30
+ console.log(` Assertion #${aIndex + 1}: ${description}`);
31
+
32
+ const expected = assertion.expectedToMatch;
33
+ const actual = allConditionsAreMatched(conditions, assertion.context);
34
+
35
+ if (actual !== expected) {
36
+ hasError = true;
37
+
38
+ console.error(CLI_FORMAT_RED, ` Segment failed: expected "${expected}", got "${actual}"`);
39
+ }
40
+ });
41
+
42
+ return hasError;
43
+ }
package/lib/tester.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { ProjectConfig } from "./config";
2
- export declare function checkIfArraysAreEqual(a: any, b: any): boolean;
3
- export declare function checkIfObjectsAreEqual(a: any, b: any): boolean;
4
- export declare function testProject(rootDirectoryPath: string, projectConfig: ProjectConfig): boolean;
package/lib/tester.js DELETED
@@ -1,159 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.testProject = exports.checkIfObjectsAreEqual = exports.checkIfArraysAreEqual = void 0;
4
- var fs = require("fs");
5
- var sdk_1 = require("@featurevisor/sdk");
6
- var config_1 = require("./config");
7
- var builder_1 = require("./builder");
8
- var datasource_1 = require("./datasource");
9
- // @TODO: make it better
10
- function checkIfArraysAreEqual(a, b) {
11
- if (!Array.isArray(a) || !Array.isArray(b)) {
12
- return false;
13
- }
14
- if (a.length !== b.length)
15
- return false;
16
- for (var i = 0; i < a.length; ++i) {
17
- if (a[i] !== b[i]) {
18
- return false;
19
- }
20
- }
21
- return true;
22
- }
23
- exports.checkIfArraysAreEqual = checkIfArraysAreEqual;
24
- function checkIfObjectsAreEqual(a, b) {
25
- if (typeof a !== "object" || typeof b !== "object") {
26
- return false;
27
- }
28
- if (a === null || b === null) {
29
- return false;
30
- }
31
- if (Object.keys(a).length !== Object.keys(b).length) {
32
- return false;
33
- }
34
- for (var key in a) {
35
- if (a[key] !== b[key]) {
36
- return false;
37
- }
38
- }
39
- return true;
40
- }
41
- exports.checkIfObjectsAreEqual = checkIfObjectsAreEqual;
42
- function testProject(rootDirectoryPath, projectConfig) {
43
- var hasError = false;
44
- var datasource = new datasource_1.Datasource(projectConfig);
45
- if (!fs.existsSync(projectConfig.testsDirectoryPath)) {
46
- console.error("Tests directory does not exist: ".concat(projectConfig.testsDirectoryPath));
47
- hasError = true;
48
- return hasError;
49
- }
50
- var testFiles = datasource.listTests();
51
- if (testFiles.length === 0) {
52
- console.error("No tests found in: ".concat(projectConfig.testsDirectoryPath));
53
- hasError = true;
54
- return hasError;
55
- }
56
- var _loop_1 = function (testFile) {
57
- var testFilePath = datasource.getEntityPath("test", testFile);
58
- console.log(" => Testing: ".concat(testFilePath.replace(rootDirectoryPath, "")));
59
- var test_1 = datasource.readTest(testFile);
60
- if (test_1.segment) {
61
- // segment testing
62
- var testSegment = test_1;
63
- var segmentKey = testSegment.segment;
64
- console.log(" => Segment \"".concat(segmentKey, "\":"));
65
- var segmentExists = datasource.entityExists("segment", segmentKey);
66
- if (!segmentExists) {
67
- console.error(" => Segment does not exist: ".concat(segmentKey));
68
- hasError = true;
69
- return "continue";
70
- }
71
- var parsedSegment = datasource.readSegment(segmentKey);
72
- var conditions_1 = parsedSegment.conditions;
73
- testSegment.assertions.forEach(function (assertion, aIndex) {
74
- var description = assertion.description || "#".concat(aIndex + 1);
75
- console.log(" => Assertion #".concat(aIndex + 1, ": ").concat(description));
76
- var expected = assertion.expectedToMatch;
77
- var actual = (0, sdk_1.allConditionsAreMatched)(conditions_1, assertion.context);
78
- if (actual !== expected) {
79
- hasError = true;
80
- console.error(" Segment failed: expected \"".concat(expected, "\", got \"").concat(actual, "\""));
81
- }
82
- });
83
- }
84
- else if (test_1.feature) {
85
- // feature testing
86
- var testFeature_1 = test_1;
87
- var featureKey_1 = testFeature_1.feature;
88
- console.log(" => Feature \"".concat(featureKey_1, "\":"));
89
- testFeature_1.assertions.forEach(function (assertion, aIndex) {
90
- var description = assertion.description || "at ".concat(assertion.at, "%");
91
- console.log(" => Assertion #".concat(aIndex + 1, ": (").concat(assertion.environment, ") ").concat(description));
92
- var featuresToInclude = Array.from(datasource.getRequiredFeaturesChain(testFeature_1.feature));
93
- var datafileContent = (0, builder_1.buildDatafile)(projectConfig, datasource, {
94
- schemaVersion: config_1.SCHEMA_VERSION,
95
- revision: "testing",
96
- environment: assertion.environment,
97
- features: featuresToInclude,
98
- }, JSON.parse(fs.readFileSync((0, builder_1.getExistingStateFilePath)(projectConfig, assertion.environment), "utf8")));
99
- var sdk = (0, sdk_1.createInstance)({
100
- datafile: datafileContent,
101
- configureBucketValue: function () {
102
- return assertion.at * (sdk_1.MAX_BUCKETED_NUMBER / 100);
103
- },
104
- // logger: createLogger({
105
- // levels: ["debug", "info", "warn", "error"],
106
- // }),
107
- });
108
- // isEnabled
109
- if ("expectedToBeEnabled" in assertion) {
110
- var isEnabled = sdk.isEnabled(featureKey_1, assertion.context);
111
- if (isEnabled !== assertion.expectedToBeEnabled) {
112
- hasError = true;
113
- console.error(" isEnabled failed: expected \"".concat(assertion.expectedToBeEnabled, "\", got \"").concat(isEnabled, "\""));
114
- }
115
- }
116
- // variation
117
- if ("expectedVariation" in assertion) {
118
- var variation = sdk.getVariation(featureKey_1, assertion.context);
119
- if (variation !== assertion.expectedVariation) {
120
- hasError = true;
121
- console.error(" Variation failed: expected \"".concat(assertion.expectedVariation, "\", got \"").concat(variation, "\""));
122
- }
123
- }
124
- // variables
125
- if (typeof assertion.expectedVariables === "object") {
126
- Object.keys(assertion.expectedVariables).forEach(function (variableKey) {
127
- var expectedValue = assertion.expectedVariables && assertion.expectedVariables[variableKey];
128
- var actualValue = sdk.getVariable(featureKey_1, variableKey, assertion.context);
129
- var passed;
130
- if (typeof expectedValue === "object") {
131
- passed = checkIfObjectsAreEqual(expectedValue, actualValue);
132
- }
133
- else if (Array.isArray(expectedValue)) {
134
- passed = checkIfArraysAreEqual(expectedValue, actualValue);
135
- }
136
- else {
137
- passed = expectedValue === actualValue;
138
- }
139
- if (!passed) {
140
- hasError = true;
141
- console.error(" Variable \"".concat(variableKey, "\" failed: expected ").concat(JSON.stringify(expectedValue), ", got \"").concat(JSON.stringify(actualValue), "\""));
142
- }
143
- });
144
- }
145
- });
146
- }
147
- else {
148
- console.error(" => Invalid test: ".concat(JSON.stringify(test_1)));
149
- hasError = true;
150
- }
151
- };
152
- for (var _i = 0, testFiles_1 = testFiles; _i < testFiles_1.length; _i++) {
153
- var testFile = testFiles_1[_i];
154
- _loop_1(testFile);
155
- }
156
- return hasError;
157
- }
158
- exports.testProject = testProject;
159
- //# sourceMappingURL=tester.js.map
package/lib/tester.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"tester.js","sourceRoot":"","sources":["../src/tester.ts"],"names":[],"mappings":"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"}
package/src/tester.ts DELETED
@@ -1,213 +0,0 @@
1
- import * as fs from "fs";
2
-
3
- import { Condition, ExistingState, TestSegment, TestFeature } from "@featurevisor/types";
4
- import { createInstance, allConditionsAreMatched, MAX_BUCKETED_NUMBER } from "@featurevisor/sdk";
5
-
6
- import { ProjectConfig, SCHEMA_VERSION } from "./config";
7
- import { getExistingStateFilePath, buildDatafile } from "./builder";
8
- import { Datasource } from "./datasource";
9
-
10
- // @TODO: make it better
11
- export function checkIfArraysAreEqual(a, b) {
12
- if (!Array.isArray(a) || !Array.isArray(b)) {
13
- return false;
14
- }
15
-
16
- if (a.length !== b.length) return false;
17
-
18
- for (let i = 0; i < a.length; ++i) {
19
- if (a[i] !== b[i]) {
20
- return false;
21
- }
22
- }
23
-
24
- return true;
25
- }
26
-
27
- export function checkIfObjectsAreEqual(a, b) {
28
- if (typeof a !== "object" || typeof b !== "object") {
29
- return false;
30
- }
31
-
32
- if (a === null || b === null) {
33
- return false;
34
- }
35
-
36
- if (Object.keys(a).length !== Object.keys(b).length) {
37
- return false;
38
- }
39
-
40
- for (const key in a) {
41
- if (a[key] !== b[key]) {
42
- return false;
43
- }
44
- }
45
-
46
- return true;
47
- }
48
-
49
- export function testProject(rootDirectoryPath: string, projectConfig: ProjectConfig): boolean {
50
- let hasError = false;
51
- const datasource = new Datasource(projectConfig);
52
-
53
- if (!fs.existsSync(projectConfig.testsDirectoryPath)) {
54
- console.error(`Tests directory does not exist: ${projectConfig.testsDirectoryPath}`);
55
- hasError = true;
56
-
57
- return hasError;
58
- }
59
-
60
- const testFiles = datasource.listTests();
61
-
62
- if (testFiles.length === 0) {
63
- console.error(`No tests found in: ${projectConfig.testsDirectoryPath}`);
64
- hasError = true;
65
-
66
- return hasError;
67
- }
68
-
69
- for (const testFile of testFiles) {
70
- const testFilePath = datasource.getEntityPath("test", testFile);
71
-
72
- console.log(` => Testing: ${testFilePath.replace(rootDirectoryPath, "")}`);
73
-
74
- const test = datasource.readTest(testFile);
75
-
76
- if ((test as TestSegment).segment) {
77
- // segment testing
78
- const testSegment = test as TestSegment;
79
- const segmentKey = testSegment.segment;
80
-
81
- console.log(` => Segment "${segmentKey}":`);
82
-
83
- const segmentExists = datasource.entityExists("segment", segmentKey);
84
-
85
- if (!segmentExists) {
86
- console.error(` => Segment does not exist: ${segmentKey}`);
87
- hasError = true;
88
-
89
- continue;
90
- }
91
-
92
- const parsedSegment = datasource.readSegment(segmentKey);
93
- const conditions = parsedSegment.conditions as Condition | Condition[];
94
-
95
- testSegment.assertions.forEach(function (assertion, aIndex) {
96
- const description = assertion.description || `#${aIndex + 1}`;
97
-
98
- console.log(` => Assertion #${aIndex + 1}: ${description}`);
99
-
100
- const expected = assertion.expectedToMatch;
101
- const actual = allConditionsAreMatched(conditions, assertion.context);
102
-
103
- if (actual !== expected) {
104
- hasError = true;
105
-
106
- console.error(` Segment failed: expected "${expected}", got "${actual}"`);
107
- }
108
- });
109
- } else if ((test as TestFeature).feature) {
110
- // feature testing
111
- const testFeature = test as TestFeature;
112
- const featureKey = testFeature.feature;
113
-
114
- console.log(` => Feature "${featureKey}":`);
115
-
116
- testFeature.assertions.forEach(function (assertion, aIndex) {
117
- const description = assertion.description || `at ${assertion.at}%`;
118
-
119
- console.log(
120
- ` => Assertion #${aIndex + 1}: (${assertion.environment}) ${description}`,
121
- );
122
-
123
- const featuresToInclude = Array.from(
124
- datasource.getRequiredFeaturesChain(testFeature.feature),
125
- );
126
-
127
- const datafileContent = buildDatafile(
128
- projectConfig,
129
- datasource,
130
- {
131
- schemaVersion: SCHEMA_VERSION,
132
- revision: "testing",
133
- environment: assertion.environment,
134
- features: featuresToInclude,
135
- },
136
- JSON.parse(
137
- fs.readFileSync(getExistingStateFilePath(projectConfig, assertion.environment), "utf8"),
138
- ) as ExistingState,
139
- );
140
-
141
- const sdk = createInstance({
142
- datafile: datafileContent,
143
- configureBucketValue: () => {
144
- return assertion.at * (MAX_BUCKETED_NUMBER / 100);
145
- },
146
- // logger: createLogger({
147
- // levels: ["debug", "info", "warn", "error"],
148
- // }),
149
- });
150
-
151
- // isEnabled
152
- if ("expectedToBeEnabled" in assertion) {
153
- const isEnabled = sdk.isEnabled(featureKey, assertion.context);
154
-
155
- if (isEnabled !== assertion.expectedToBeEnabled) {
156
- hasError = true;
157
-
158
- console.error(
159
- ` isEnabled failed: expected "${assertion.expectedToBeEnabled}", got "${isEnabled}"`,
160
- );
161
- }
162
- }
163
-
164
- // variation
165
- if ("expectedVariation" in assertion) {
166
- const variation = sdk.getVariation(featureKey, assertion.context);
167
-
168
- if (variation !== assertion.expectedVariation) {
169
- hasError = true;
170
-
171
- console.error(
172
- ` Variation failed: expected "${assertion.expectedVariation}", got "${variation}"`,
173
- );
174
- }
175
- }
176
-
177
- // variables
178
- if (typeof assertion.expectedVariables === "object") {
179
- Object.keys(assertion.expectedVariables).forEach(function (variableKey) {
180
- const expectedValue =
181
- assertion.expectedVariables && assertion.expectedVariables[variableKey];
182
- const actualValue = sdk.getVariable(featureKey, variableKey, assertion.context);
183
-
184
- let passed;
185
-
186
- if (typeof expectedValue === "object") {
187
- passed = checkIfObjectsAreEqual(expectedValue, actualValue);
188
- } else if (Array.isArray(expectedValue)) {
189
- passed = checkIfArraysAreEqual(expectedValue, actualValue);
190
- } else {
191
- passed = expectedValue === actualValue;
192
- }
193
-
194
- if (!passed) {
195
- hasError = true;
196
-
197
- console.error(
198
- ` Variable "${variableKey}" failed: expected ${JSON.stringify(
199
- expectedValue,
200
- )}, got "${JSON.stringify(actualValue)}"`,
201
- );
202
- }
203
- });
204
- }
205
- });
206
- } else {
207
- console.error(` => Invalid test: ${JSON.stringify(test)}`);
208
- hasError = true;
209
- }
210
- }
211
-
212
- return hasError;
213
- }