Skip to content

Commit 4870f55

Browse files
committed
[FSSDK-11095] rewrite condition_tree_evaluator tests in Typescript
1 parent 493b181 commit 4870f55

File tree

1 file changed

+230
-0
lines changed

1 file changed

+230
-0
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/****************************************************************************
2+
* Copyright 2018, 2020-2021, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
import { describe, it, vi, expect } from 'vitest';
17+
18+
import * as conditionTreeEvaluator from '.';
19+
20+
const conditionA = {
21+
name: 'browser_type',
22+
value: 'safari',
23+
type: 'custom_attribute',
24+
};
25+
const conditionB = {
26+
name: 'device_model',
27+
value: 'iphone6',
28+
type: 'custom_attribute',
29+
};
30+
const conditionC = {
31+
name: 'location',
32+
match: 'exact',
33+
type: 'custom_attribute',
34+
value: 'CA',
35+
};
36+
37+
describe.only('lib/core/condition_tree_evaluator', function() {
38+
describe('APIs', function() {
39+
describe('evaluate', function() {
40+
it('should return true for a leaf condition when the leaf condition evaluator returns true', function() {
41+
expect(
42+
conditionTreeEvaluator.evaluate(conditionA, function() {
43+
return true;
44+
})
45+
).toBe(true);
46+
});
47+
48+
it('should return false for a leaf condition when the leaf condition evaluator returns false', function() {
49+
expect(
50+
conditionTreeEvaluator.evaluate(conditionA, function() {
51+
return false;
52+
})
53+
).toBe(false)
54+
});
55+
56+
describe('and evaluation', function() {
57+
it('should return true when ALL conditions evaluate to true', function() {
58+
expect(
59+
conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], function() {
60+
return true;
61+
})
62+
).toBe(true);
63+
});
64+
65+
it('should return false if one condition evaluates to false', function() {
66+
const leafEvaluator = vi.fn();
67+
leafEvaluator.mockImplementationOnce(() => true)
68+
.mockImplementationOnce(() => false);
69+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBe(false);
70+
});
71+
72+
describe('null handling', function() {
73+
it('should return null when all operands evaluate to null', function() {
74+
expect(
75+
conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], function() {
76+
return null;
77+
})
78+
).toBeNull();
79+
});
80+
81+
it('should return null when operands evaluate to trues and nulls', function() {
82+
const leafEvaluator = vi.fn();
83+
leafEvaluator.mockImplementationOnce(() => true)
84+
.mockImplementationOnce(() => null);
85+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBeNull();
86+
});
87+
88+
it('should return false when operands evaluate to falses and nulls', function() {
89+
const leafEvaluator = vi.fn();
90+
leafEvaluator.mockImplementationOnce(() => false)
91+
.mockImplementationOnce(() => null);
92+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBe(false);
93+
94+
leafEvaluator.mockReset();
95+
leafEvaluator.mockImplementationOnce(() => null)
96+
.mockImplementationOnce(() => false);
97+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBe(false);
98+
});
99+
100+
it('should return false when operands evaluate to trues, falses, and nulls', function() {
101+
const leafEvaluator = vi.fn();
102+
leafEvaluator.mockImplementationOnce(() => true)
103+
.mockImplementationOnce(() => false)
104+
.mockImplementationOnce(() => null);
105+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB, conditionC], leafEvaluator)).toBe(false);
106+
});
107+
});
108+
});
109+
110+
describe('or evaluation', function() {
111+
it('should return true if any condition evaluates to true', function() {
112+
const leafEvaluator = vi.fn();
113+
leafEvaluator.mockImplementationOnce(() => false)
114+
.mockImplementationOnce(() => true);
115+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBe(true);
116+
});
117+
118+
it('should return false if all conditions evaluate to false', function() {
119+
expect(
120+
conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], function() {
121+
return false;
122+
})
123+
).toBe(false);
124+
});
125+
126+
describe('null handling', function() {
127+
it('should return null when all operands evaluate to null', function() {
128+
expect(
129+
conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], function() {
130+
return null;
131+
})
132+
).toBeNull();
133+
});
134+
135+
it('should return true when operands evaluate to trues and nulls', function() {
136+
const leafEvaluator = vi.fn();
137+
leafEvaluator.mockImplementationOnce(() => true)
138+
.mockImplementationOnce(() => null);
139+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBe(true);
140+
});
141+
142+
it('should return null when operands evaluate to falses and nulls', function() {
143+
const leafEvaluator = vi.fn();
144+
leafEvaluator.mockImplementationOnce(() => null)
145+
.mockImplementationOnce(() => false);
146+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBeNull();
147+
148+
leafEvaluator.mockReset();
149+
leafEvaluator.mockImplementationOnce(() => false)
150+
.mockImplementationOnce(() => null);
151+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBeNull();
152+
});
153+
154+
it('should return true when operands evaluate to trues, falses, and nulls', function() {
155+
const leafEvaluator = vi.fn();
156+
leafEvaluator.mockImplementationOnce(() => true)
157+
.mockImplementationOnce(() => null)
158+
.mockImplementationOnce(() => false);
159+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB, conditionC], leafEvaluator)).toBe(true);
160+
});
161+
});
162+
});
163+
164+
describe('not evaluation', function() {
165+
it('should return true if the condition evaluates to false', function() {
166+
expect(
167+
conditionTreeEvaluator.evaluate(['not', conditionA], function() {
168+
return false;
169+
})
170+
).toBe(true);
171+
});
172+
173+
it('should return false if the condition evaluates to true', function() {
174+
expect(
175+
conditionTreeEvaluator.evaluate(['not', conditionB], function() {
176+
return true;
177+
})
178+
).toBe(false);
179+
});
180+
181+
it('should return the result of negating the first condition, and ignore any additional conditions', function() {
182+
let result = conditionTreeEvaluator.evaluate(['not', '1', '2', '1'], function(id) {
183+
return String(id) === '1';
184+
});
185+
expect(result).toBe(false);
186+
result = conditionTreeEvaluator.evaluate(['not', '1', '2', '1'], function(id) {
187+
return String(id) === '2';
188+
});
189+
expect(result).toBe(true);
190+
result = conditionTreeEvaluator.evaluate(['not', '1', '2', '3'], function(id) {
191+
return String(id) === '1' ? null : String(id) === '3';
192+
});
193+
expect(result).toBeNull();
194+
});
195+
196+
describe('null handling', function() {
197+
it('should return null when operand evaluates to null', function() {
198+
expect(
199+
conditionTreeEvaluator.evaluate(['not', conditionA], function() {
200+
return null;
201+
})
202+
).toBeNull();
203+
});
204+
205+
it('should return null when there are no operands', function() {
206+
expect(
207+
conditionTreeEvaluator.evaluate(['not'], function() {
208+
return null;
209+
})
210+
).toBeNull();
211+
});
212+
});
213+
});
214+
215+
describe('implicit operator', function() {
216+
it('should behave like an "or" operator when the first item in the array is not a recognized operator', function() {
217+
const leafEvaluator = vi.fn();
218+
leafEvaluator.mockImplementationOnce(() => true)
219+
.mockImplementationOnce(() => false);
220+
expect(conditionTreeEvaluator.evaluate([conditionA, conditionB], leafEvaluator)).toBe(true);
221+
expect(
222+
conditionTreeEvaluator.evaluate([conditionA, conditionB], function() {
223+
return false;
224+
})
225+
).toBe(false);
226+
});
227+
});
228+
});
229+
});
230+
});

0 commit comments

Comments
 (0)