Skip to content

Commit fd9c9ed

Browse files
[FSSDK-11095] rewrite condition_tree_evaluator tests in Typescript (#994)
* [FSSDK-11095] rewrite condition_tree_evaluator tests in Typescript * Remove only tag * Implement comments
1 parent 493b181 commit fd9c9ed

File tree

1 file changed

+218
-0
lines changed

1 file changed

+218
-0
lines changed
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
/**
2+
* Copyright 2025, Optimizely
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+
* https://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+
describe('evaluate', function() {
37+
it('should return true for a leaf condition when the leaf condition evaluator returns true', function() {
38+
expect(
39+
conditionTreeEvaluator.evaluate(conditionA, function() {
40+
return true;
41+
})
42+
).toBe(true);
43+
});
44+
45+
it('should return false for a leaf condition when the leaf condition evaluator returns false', function() {
46+
expect(
47+
conditionTreeEvaluator.evaluate(conditionA, function() {
48+
return false;
49+
})
50+
).toBe(false);
51+
});
52+
53+
describe('and evaluation', function() {
54+
it('should return true when ALL conditions evaluate to true', function() {
55+
expect(
56+
conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], function() {
57+
return true;
58+
})
59+
).toBe(true);
60+
});
61+
62+
it('should return false if one condition evaluates to false', function() {
63+
const leafEvaluator = vi.fn();
64+
leafEvaluator.mockImplementationOnce(() => true).mockImplementationOnce(() => false);
65+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBe(false);
66+
});
67+
68+
describe('null handling', function() {
69+
it('should return null when all operands evaluate to null', function() {
70+
expect(
71+
conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], function() {
72+
return null;
73+
})
74+
).toBeNull();
75+
});
76+
77+
it('should return null when operands evaluate to trues and nulls', function() {
78+
const leafEvaluator = vi.fn();
79+
leafEvaluator.mockImplementationOnce(() => true).mockImplementationOnce(() => null);
80+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBeNull();
81+
});
82+
83+
it('should return false when operands evaluate to falses and nulls', function() {
84+
const leafEvaluator = vi.fn();
85+
leafEvaluator.mockImplementationOnce(() => false).mockImplementationOnce(() => null);
86+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBe(false);
87+
88+
leafEvaluator.mockReset();
89+
leafEvaluator.mockImplementationOnce(() => null).mockImplementationOnce(() => false);
90+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB], leafEvaluator)).toBe(false);
91+
});
92+
93+
it('should return false when operands evaluate to trues, falses, and nulls', function() {
94+
const leafEvaluator = vi.fn();
95+
leafEvaluator
96+
.mockImplementationOnce(() => true)
97+
.mockImplementationOnce(() => false)
98+
.mockImplementationOnce(() => null);
99+
expect(conditionTreeEvaluator.evaluate(['and', conditionA, conditionB, conditionC], leafEvaluator)).toBe(false);
100+
});
101+
});
102+
});
103+
104+
describe('or evaluation', function() {
105+
it('should return true if any condition evaluates to true', function() {
106+
const leafEvaluator = vi.fn();
107+
leafEvaluator.mockImplementationOnce(() => false).mockImplementationOnce(() => true);
108+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBe(true);
109+
});
110+
111+
it('should return false if all conditions evaluate to false', function() {
112+
expect(
113+
conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], function() {
114+
return false;
115+
})
116+
).toBe(false);
117+
});
118+
119+
describe('null handling', function() {
120+
it('should return null when all operands evaluate to null', function() {
121+
expect(
122+
conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], function() {
123+
return null;
124+
})
125+
).toBeNull();
126+
});
127+
128+
it('should return true when operands evaluate to trues and nulls', function() {
129+
const leafEvaluator = vi.fn();
130+
leafEvaluator.mockImplementationOnce(() => true).mockImplementationOnce(() => null);
131+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBe(true);
132+
});
133+
134+
it('should return null when operands evaluate to falses and nulls', function() {
135+
const leafEvaluator = vi.fn();
136+
leafEvaluator.mockImplementationOnce(() => null).mockImplementationOnce(() => false);
137+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBeNull();
138+
139+
leafEvaluator.mockReset();
140+
leafEvaluator.mockImplementationOnce(() => false).mockImplementationOnce(() => null);
141+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB], leafEvaluator)).toBeNull();
142+
});
143+
144+
it('should return true when operands evaluate to trues, falses, and nulls', function() {
145+
const leafEvaluator = vi.fn();
146+
leafEvaluator
147+
.mockImplementationOnce(() => true)
148+
.mockImplementationOnce(() => null)
149+
.mockImplementationOnce(() => false);
150+
expect(conditionTreeEvaluator.evaluate(['or', conditionA, conditionB, conditionC], leafEvaluator)).toBe(true);
151+
});
152+
});
153+
});
154+
155+
describe('not evaluation', function() {
156+
it('should return true if the condition evaluates to false', function() {
157+
expect(
158+
conditionTreeEvaluator.evaluate(['not', conditionA], function() {
159+
return false;
160+
})
161+
).toBe(true);
162+
});
163+
164+
it('should return false if the condition evaluates to true', function() {
165+
expect(
166+
conditionTreeEvaluator.evaluate(['not', conditionB], function() {
167+
return true;
168+
})
169+
).toBe(false);
170+
});
171+
172+
it('should return the result of negating the first condition, and ignore any additional conditions', function() {
173+
let result = conditionTreeEvaluator.evaluate(['not', '1', '2', '1'], function(id: string) {
174+
return id === '1';
175+
});
176+
expect(result).toBe(false);
177+
result = conditionTreeEvaluator.evaluate(['not', '1', '2', '1'], function(id: string) {
178+
return id === '2';
179+
});
180+
expect(result).toBe(true);
181+
result = conditionTreeEvaluator.evaluate(['not', '1', '2', '3'], function(id: string) {
182+
return id === '1' ? null : id === '3';
183+
});
184+
expect(result).toBeNull();
185+
});
186+
187+
describe('null handling', function() {
188+
it('should return null when operand evaluates to null', function() {
189+
expect(
190+
conditionTreeEvaluator.evaluate(['not', conditionA], function() {
191+
return null;
192+
})
193+
).toBeNull();
194+
});
195+
196+
it('should return null when there are no operands', function() {
197+
expect(
198+
conditionTreeEvaluator.evaluate(['not'], function() {
199+
return null;
200+
})
201+
).toBeNull();
202+
});
203+
});
204+
});
205+
206+
describe('implicit operator', function() {
207+
it('should behave like an "or" operator when the first item in the array is not a recognized operator', function() {
208+
const leafEvaluator = vi.fn();
209+
leafEvaluator.mockImplementationOnce(() => true).mockImplementationOnce(() => false);
210+
expect(conditionTreeEvaluator.evaluate([conditionA, conditionB], leafEvaluator)).toBe(true);
211+
expect(
212+
conditionTreeEvaluator.evaluate([conditionA, conditionB], function() {
213+
return false;
214+
})
215+
).toBe(false);
216+
});
217+
});
218+
});

0 commit comments

Comments
 (0)