UNPKG

13.3 kBJavaScriptView Raw
1var RuleEngine = require('../index');
2var expect = require("chai").expect;
3describe("Rules", function() {
4 describe(".init()", function() {
5 it("should empty the existing rule array", function() {
6 var rules = [{
7 "condition": function(R) {
8 R.when(1);
9 },
10 "consequence": function(R) {
11 R.stop();
12 }
13 }];
14 var R = new RuleEngine(rules);
15 R.init();
16 expect(R.rules).to.eql([]);
17 });
18 });
19 describe(".register()", function() {
20 it("Rule should be turned on if the field - ON is absent in the rule", function() {
21 var rules = [{
22 "condition": function(R) {
23 R.when(1);
24 },
25 "consequence": function(R) {
26 R.stop();
27 }
28 }];
29 var R = new RuleEngine(rules);
30 expect(R.rules[0].on).to.eql(true);
31 });
32 it("Rule can be passed to register as both arrays and individual objects", function() {
33 var rule = {
34 "condition": function(R) {
35 R.when(1);
36 },
37 "consequence": function(R) {
38 R.stop();
39 }
40 };
41 var R1 = new RuleEngine(rule);
42 var R2 = new RuleEngine([rule]);
43 expect(R1.rules).to.eql(R2.rules);
44 });
45 it("Rules can be appended multiple times via register after creating rule engine instance", function() {
46 var rules = [{
47 "condition": function(R) {
48 R.when(1);
49 },
50 "consequence": function(R) {
51 R.stop();
52 }
53 }, {
54 "condition": function(R) {
55 R.when(0);
56 },
57 "consequence": function(R) {
58 R.stop();
59 }
60 }];
61 var R1 = new RuleEngine(rules);
62 var R2 = new RuleEngine(rules[0]);
63 R2.register(rules[1]);
64 expect(R1.rules).to.eql(R2.rules);
65 });
66 });
67 describe(".sync()", function() {
68 it("should only push active rules into active rules array", function() {
69 var rules = [{
70 "condition": function(R) {
71 R.when(1);
72 },
73 "consequence": function(R) {
74 R.stop();
75 },
76 "id": "one",
77 "on": true
78 }, {
79 "condition": function(R) {
80 R.when(0);
81 },
82 "consequence": function(R) {
83 R.stop();
84 },
85 "id": "one",
86 "on": false
87 }];
88 var R = new RuleEngine();
89 R.register(rules);
90 expect(R.activeRules).not.to.eql(R.rules);
91 });
92 it("should sort the rules accroding to priority, if priority is present", function() {
93 var rules = [{
94 "priority": 8,
95 "index": 1,
96 "condition": function(R) {
97 R.when(1);
98 },
99 "consequence": function(R) {
100 R.stop();
101 },
102 }, {
103 "priority": 6,
104 "index": 2,
105 "condition": function(R) {
106 R.when(1);
107 },
108 "consequence": function(R) {
109 R.stop();
110 },
111 }, {
112 "priority": 9,
113 "index": 0,
114 "condition": function(R) {
115 R.when(1);
116 },
117 "consequence": function(R) {
118 R.stop();
119 },
120 }];
121 var R = new RuleEngine();
122 R.register(rules);
123 expect(R.activeRules[2].index).to.eql(2);
124 });
125 });
126 describe(".exec()", function() {
127 it("should run consequnce when condition matches", function() {
128 var rule = {
129 "condition": function(R) {
130 R.when(this && (this.transactionTotal < 500));
131 },
132 "consequence": function(R) {
133 this.result = false;
134 R.stop();
135 }
136 };
137 var R = new RuleEngine(rule);
138 R.execute({
139 "transactionTotal": 200
140 }, function(result) {
141 expect(result.result).to.eql(false);
142 });
143 });
144 it("should chain rules and find result with next()", function() {
145 var rule = [{
146 "condition": function(R) {
147 R.when(this && (this.card == "VISA"));
148 },
149 "consequence": function(R) {
150 R.stop();
151 this.result = "Custom Result";
152 },
153 "priority": 4
154 }, {
155 "condition": function(R) {
156 R.when(this && (this.transactionTotal < 1000));
157 },
158 "consequence": function(R) {
159 R.next();
160 },
161 "priority": 8
162 }];
163 var R = new RuleEngine(rule);
164 R.execute({
165 "transactionTotal": 200,
166 "card": "VISA"
167 }, function(result) {
168 expect(result.result).to.eql("Custom Result");
169 });
170 });
171 it("should provide access to rule definition properties via rule()", function() {
172 var rule = {
173 "name": "sample rule name",
174 "id": "xyzzy",
175 "condition": function(R) {
176 R.when(this && (this.input === true));
177 },
178 "consequence": function(R) {
179 this.result = true;
180 this.ruleName = R.rule().name;
181 this.ruleID = R.rule().id;
182 R.stop();
183 }
184 };
185 var R = new RuleEngine(rule);
186 R.execute({
187 "input": true
188 }, function(result) {
189 expect(result.ruleName).to.eql(rule.name);
190 expect(result.ruleID).to.eql(rule.id);
191 });
192 });
193 it("should include the matched rule path", function() {
194 var rules = [
195 {
196 "name": "rule A",
197 "condition": function(R) {
198 R.when(this && (this.x === true));
199 },
200 "consequence": function(R) {
201 R.next();
202 }
203 },
204 {
205 "name": "rule B",
206 "condition": function(R) {
207 R.when(this && (this.y === true));
208 },
209 "consequence": function(R) {
210 R.next();
211 }
212 },
213 {
214 "id": "rule C",
215 "condition": function(R) {
216 R.when(this && (this.x === true && this.y === false));
217 },
218 "consequence": function(R) {
219 R.next();
220 }
221 },
222 {
223 "id": "rule D",
224 "condition": function(R) {
225 R.when(this && (this.x === false && this.y === false));
226 },
227 "consequence": function(R) {
228 R.next();
229 }
230 },
231 {
232 "condition": function(R) {
233 R.when(this && (this.x === true && this.y === false));
234 },
235 "consequence": function(R) {
236 R.next();
237 }
238 }
239 ];
240 var lastMatch = 'index_' + ((rules.length)-1).toString();
241 var R = new RuleEngine(rules);
242 R.execute({
243 "x": true,
244 "y": false
245 }, function(result) {
246 expect(result.matchPath).to.eql([rules[0].name, rules[2].id, lastMatch]);
247 });
248 });
249
250 it("should support fact as optional second parameter for es6 compatibility", function() {
251 var rule = {
252 "condition": function(R, fact) {
253 R.when(fact && (fact.transactionTotal < 500));
254 },
255 "consequence": function(R, fact) {
256 fact.result = false;
257 R.stop();
258 }
259 };
260 var R = new RuleEngine(rule);
261 R.execute({
262 "transactionTotal": 200
263 }, function(result) {
264 expect(result.result).to.eql(false);
265 });
266 });
267
268 });
269 describe(".findRules()", function() {
270 var rules = [{
271 "condition": function(R) {
272 R.when(1);
273 },
274 "consequence": function(R) {
275 R.stop();
276 },
277 "id": "one"
278 }, {
279 "condition": function(R) {
280 R.when(0);
281 },
282 "consequence": function(R) {
283 R.stop();
284 },
285 "id": "two"
286 }];
287 var R = new RuleEngine(rules);
288 it("find selector function for rules should exact number of matches", function() {
289 expect(R.findRules({
290 "id": "one"
291 }).length).to.eql(1);
292 });
293 it("find selector function for rules should give the correct match as result", function() {
294 expect(R.findRules({
295 "id": "one"
296 })[0].id).to.eql("one");
297 });
298 it("find without condition works fine", function() {
299 expect(R.findRules().length).to.eql(2);
300 });
301 });
302 describe(".turn()", function() {
303 var rules = [{
304 "condition": function(R) {
305 R.when(1);
306 },
307 "consequence": function(R) {
308 R.stop();
309 },
310 "id": "one"
311 }, {
312 "condition": function(R) {
313 R.when(0);
314 },
315 "consequence": function(R) {
316 R.stop();
317 },
318 "id": "two",
319 "on": false
320 }];
321 var R = new RuleEngine(rules);
322 it("checking whether turn off rules work as expected", function() {
323 R.turn("OFF", {
324 "id": "one"
325 });
326 expect(R.findRules({
327 "id": "one"
328 })[0].on).to.eql(false);
329 });
330 it("checking whether turn on rules work as expected", function() {
331 R.turn("ON", {
332 "id": "two"
333 });
334 expect(R.findRules({
335 "id": "two"
336 })[0].on).to.eql(true);
337 });
338 });
339 describe(".prioritize()", function() {
340 var rules = [{
341 "condition": function(R) {
342 R.when(1);
343 },
344 "consequence": function(R) {
345 R.stop();
346 },
347 "id": "two",
348 "priority": 1
349 }, {
350 "condition": function(R) {
351 R.when(0);
352 },
353 "consequence": function(R) {
354 R.stop();
355 },
356 "id": "zero",
357 "priority": 8
358 }, {
359 "condition": function(R) {
360 R.when(0);
361 },
362 "consequence": function(R) {
363 R.stop();
364 },
365 "id": "one",
366 "priority": 4
367 }];
368 var R = new RuleEngine(rules);
369 it("checking whether prioritize work", function() {
370 R.prioritize(10, {
371 "id": "one"
372 });
373 expect(R.findRules({
374 "id": "one"
375 })[0].priority).to.eql(10);
376 });
377 it("checking whether rules reorder after prioritize", function() {
378 R.prioritize(10, {
379 "id": "one"
380 });
381 expect(R.activeRules[0].id).to.eql("one");
382 });
383 });
384 describe("ignoreFactChanges", function() {
385 var rules = [{
386 "name": "rule1",
387 "condition": function(R) {
388 R.when(this.value1 > 5);
389 },
390 "consequence": function(R) {
391 this.result = false;
392 this.errors = this.errors || [];
393 this.errors.push('must be less than 5');
394 R.next();
395 }
396 }];
397
398 var fact = {
399 "value1": 6
400 };
401
402 it("doesn't rerun when a fact changes if ignoreFactChanges is true", function(done) {
403 var R = new RuleEngine(rules, { ignoreFactChanges: true });
404
405 R.execute(fact, function(result) {
406 expect(result.errors).to.have.length(1);
407 done();
408 });
409 });
410 });
411});