Skip to content

Commit 85146b3

Browse files
author
Cache Hamm
committed
add factResult property to ruleResult
1 parent 534e391 commit 85146b3

4 files changed

Lines changed: 70 additions & 48 deletions

File tree

src/condition.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ export default class Condition {
9090
let rightHandSideValue = await this._getValue(almanac)
9191
let leftHandSideValue = await almanac.factValue(this.fact, this.params, this.path)
9292

93-
let evaluationResult = op.evaluate(leftHandSideValue, rightHandSideValue)
94-
debug(`condition::evaluate <${leftHandSideValue} ${this.operator} ${rightHandSideValue}?> (${evaluationResult})`)
95-
return evaluationResult
93+
let result = op.evaluate(leftHandSideValue, rightHandSideValue)
94+
debug(`condition::evaluate <${leftHandSideValue} ${this.operator} ${rightHandSideValue}?> (${result})`)
95+
return { result, leftHandSideValue, rightHandSideValue, operator: this.operator }
9696
}
9797

9898
/**

src/rule.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ class Rule extends EventEmitter {
153153
passes = comparisonValue === true
154154
} else {
155155
try {
156-
passes = await condition.evaluate(almanac, this.engine.operators, comparisonValue)
156+
let evaluationResult = await condition.evaluate(almanac, this.engine.operators, comparisonValue)
157+
passes = evaluationResult.result
158+
condition.factResult = evaluationResult.leftHandSideValue
157159
} catch (err) {
158160
// any condition raising an undefined fact error is considered falsey when allowUndefinedFacts is enabled
159161
if (this.engine.allowUndefinedFacts && err.code === 'UNDEFINED_FACT') passes = false

test/condition.test.js

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -89,110 +89,110 @@ describe('Condition', () => {
8989

9090
it('evaluates "equal"', async () => {
9191
setup({ operator: 'equal' }, 50)
92-
expect(await condition.evaluate(almanac, operators, 50)).to.equal(true)
92+
expect((await condition.evaluate(almanac, operators, 50)).result).to.equal(true)
9393
setup({ operator: 'equal' }, 5)
94-
expect(await condition.evaluate(almanac, operators, 5)).to.equal(false)
94+
expect((await condition.evaluate(almanac, operators, 5)).result).to.equal(false)
9595
})
9696

9797
it('evaluates "notEqual"', async () => {
9898
setup({ operator: 'notEqual' }, 50)
99-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
99+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
100100
setup({ operator: 'notEqual' }, 5)
101-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
101+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
102102
})
103103

104104
it('evaluates "in"', async () => {
105105
setup({ operator: 'in', value: [5, 10, 15, 20] }, 15)
106-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
106+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
107107
setup({ operator: 'in', value: [5, 10, 15, 20] }, 99)
108-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
108+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
109109
})
110110

111111
it('evaluates "contains"', async () => {
112112
setup({ operator: 'contains', value: 10 }, [5, 10, 15])
113-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
113+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
114114
setup({ operator: 'contains', value: 10 }, [1, 2, 3])
115-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
115+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
116116
})
117117

118118
it('evaluates "doesNotContain"', async () => {
119119
setup({ operator: 'doesNotContain', value: 10 }, [5, 10, 15])
120-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
120+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
121121
setup({ operator: 'doesNotContain', value: 10 }, [1, 2, 3])
122-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
122+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
123123
})
124124

125125
it('evaluates "notIn"', async () => {
126126
setup({ operator: 'notIn', value: [5, 10, 15, 20] }, 15)
127-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
127+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
128128
setup({ operator: 'notIn', value: [5, 10, 15, 20] }, 99)
129-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
129+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
130130
})
131131

132132
it('evaluates "lessThan"', async () => {
133133
setup({ operator: 'lessThan' }, 49)
134-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
134+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
135135
setup({ operator: 'lessThan' }, 50)
136-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
136+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
137137
setup({ operator: 'lessThan' }, 51)
138-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
138+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
139139
})
140140

141141
it('evaluates "lessThanInclusive"', async () => {
142142
setup({ operator: 'lessThanInclusive' }, 49)
143-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
143+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
144144
setup({ operator: 'lessThanInclusive' }, 50)
145-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
145+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
146146
setup({ operator: 'lessThanInclusive' }, 51)
147-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
147+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
148148
})
149149

150150
it('evaluates "greaterThan"', async () => {
151151
setup({ operator: 'greaterThan' }, 51)
152-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
152+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
153153
setup({ operator: 'greaterThan' }, 49)
154-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
154+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
155155
setup({ operator: 'greaterThan' }, 50)
156-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
156+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
157157
})
158158

159159
it('evaluates "greaterThanInclusive"', async () => {
160160
setup({ operator: 'greaterThanInclusive' }, 51)
161-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
161+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
162162
setup({ operator: 'greaterThanInclusive' }, 50)
163-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
163+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
164164
setup({ operator: 'greaterThanInclusive' }, 49)
165-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
165+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
166166
})
167167

168168
describe('invalid comparisonValues', () => {
169169
it('returns false when using contains or doesNotContain with a non-array', async () => {
170170
setup({ operator: 'contains' }, null)
171-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
171+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
172172
setup({ operator: 'doesNotContain' }, null)
173-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
173+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
174174
})
175175

176176
it('returns false when using comparison operators with null', async () => {
177177
setup({ operator: 'lessThan' }, null)
178-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
178+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
179179
setup({ operator: 'lessThanInclusive' }, null)
180-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
180+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
181181
setup({ operator: 'greaterThan' }, null)
182-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
182+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
183183
setup({ operator: 'greaterThanInclusive' }, null)
184-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
184+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
185185
})
186186

187187
it('returns false when using comparison operators with non-numbers', async () => {
188188
setup({operator: 'lessThan'}, 'non-number')
189-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
189+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
190190
setup({operator: 'lessThan'}, null)
191-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
191+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
192192
setup({operator: 'lessThan'}, [])
193-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
193+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
194194
setup({operator: 'lessThan'}, {})
195-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
195+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
196196
})
197197
})
198198
})
@@ -203,10 +203,10 @@ describe('Condition', () => {
203203
let ageFact = new Fact('age', [{ id: 50 }, { id: 60 }])
204204
let facts = new Map([[ageFact.id, ageFact]])
205205
let almanac = new Almanac(facts)
206-
expect(await condition.evaluate(almanac, operators)).to.equal(true)
206+
expect((await condition.evaluate(almanac, operators)).result).to.equal(true)
207207

208208
condition.value = 100 // negative case
209-
expect(await condition.evaluate(almanac, operators)).to.equal(false)
209+
expect((await condition.evaluate(almanac, operators)).result).to.equal(false)
210210
})
211211

212212
it('ignores "path" when non-objects are returned by the fact', async () => {
@@ -215,10 +215,10 @@ describe('Condition', () => {
215215
let almanac = new Almanac(facts)
216216

217217
let condition = new Condition({operator: 'equal', path: '[0].id', fact: 'age', value: 50})
218-
expect(await condition.evaluate(almanac, operators, 50)).to.equal(true)
218+
expect((await condition.evaluate(almanac, operators, 50)).result).to.equal(true)
219219

220220
condition.value = 100 // negative case
221-
expect(await condition.evaluate(almanac, operators, 50)).to.equal(false)
221+
expect((await condition.evaluate(almanac, operators, 50)).result).to.equal(false)
222222
})
223223
})
224224

test/engine-event.test.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import engineFactory from '../src/index'
44
import Almanac from '../src/almanac'
55
import sinon from 'sinon'
66

7-
describe.only('Engine: event', () => {
7+
describe('Engine: event', () => {
88
let engine
99

1010
let event = {
@@ -67,11 +67,11 @@ describe.only('Engine: event', () => {
6767
let ruleOptions = { conditions, event, priority: 100 }
6868
let determineDrinkingAgeRule = factories.rule(ruleOptions)
6969
engine.addRule(determineDrinkingAgeRule)
70+
// rule will succeed because of 'any'
7071
engine.addFact('age', 10) // age fails
7172
engine.addFact('qualified', false) // qualified fails.
7273
engine.addFact('zipCode', 80403) // zipCode succeeds
7374
engine.addFact('gender', 'male') // gender succeeds
74-
// rule will succeed because of 'any'
7575
}
7676

7777
context('engine events: simple', () => {
@@ -85,7 +85,9 @@ describe.only('Engine: event', () => {
8585
expect(almanac).to.be.an.instanceof(Almanac)
8686
expect(ruleResult.result).to.be.true()
8787
expect(ruleResult.conditions.any[0].result).to.be.true()
88+
expect(ruleResult.conditions.any[0].factResult).to.equal(21)
8889
expect(ruleResult.conditions.any[1].result).to.be.false()
90+
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
8991
successSpy()
9092
})
9193
engine.on('failure', failureSpy)
@@ -95,18 +97,21 @@ describe.only('Engine: event', () => {
9597
})
9698

9799
it('"failure" passes the event, almanac, and results', async () => {
100+
let AGE = 10
98101
let failureSpy = sinon.spy()
99102
let successSpy = sinon.spy()
100103
engine.on('failure', function (e, almanac, ruleResult) {
101104
expect(e).to.eql(event)
102105
expect(almanac).to.be.an.instanceof(Almanac)
103106
expect(ruleResult.result).to.be.false()
104107
expect(ruleResult.conditions.any[0].result).to.be.false()
108+
expect(ruleResult.conditions.any[0].factResult).to.equal(AGE)
105109
expect(ruleResult.conditions.any[1].result).to.be.false()
110+
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
106111
failureSpy()
107112
})
108113
engine.on('success', successSpy)
109-
engine.addFact('age', 10) // age fails
114+
engine.addFact('age', AGE) // age fails
110115
await engine.run()
111116
expect(failureSpy.callCount).to.equal(1)
112117
expect(successSpy.callCount).to.equal(0)
@@ -160,10 +165,14 @@ describe.only('Engine: event', () => {
160165
expect(almanac).to.be.an.instanceof(Almanac)
161166
expect(ruleResult.result).to.be.true()
162167
expect(ruleResult.conditions.any[0].result).to.be.false()
168+
expect(ruleResult.conditions.any[0].factResult).to.equal(10)
163169
expect(ruleResult.conditions.any[1].result).to.be.false()
170+
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
164171
expect(ruleResult.conditions.any[2].result).to.be.true()
165172
expect(ruleResult.conditions.any[2].all[0].result).to.be.true()
173+
expect(ruleResult.conditions.any[2].all[0].factResult).to.equal(80403)
166174
expect(ruleResult.conditions.any[2].all[1].result).to.be.true()
175+
expect(ruleResult.conditions.any[2].all[1].factResult).to.equal('male')
167176
successSpy()
168177
})
169178
engine.on('failure', failureSpy)
@@ -173,22 +182,28 @@ describe.only('Engine: event', () => {
173182
})
174183

175184
it('"failure" passes the event, almanac, and results', async () => {
185+
let ZIP_CODE = 99992
186+
let GENDER = 'female'
176187
let failureSpy = sinon.spy()
177188
let successSpy = sinon.spy()
178189
engine.on('failure', function (e, almanac, ruleResult) {
179190
expect(e).to.eql(event)
180191
expect(almanac).to.be.an.instanceof(Almanac)
181192
expect(ruleResult.result).to.be.false()
182193
expect(ruleResult.conditions.any[0].result).to.be.false()
194+
expect(ruleResult.conditions.any[0].factResult).to.equal(10)
183195
expect(ruleResult.conditions.any[1].result).to.be.false()
196+
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
184197
expect(ruleResult.conditions.any[2].result).to.be.false()
185198
expect(ruleResult.conditions.any[2].all[0].result).to.be.false()
199+
expect(ruleResult.conditions.any[2].all[0].factResult).to.equal(ZIP_CODE)
186200
expect(ruleResult.conditions.any[2].all[1].result).to.be.false()
201+
expect(ruleResult.conditions.any[2].all[1].factResult).to.equal(GENDER)
187202
failureSpy()
188203
})
189204
engine.on('success', successSpy)
190-
engine.addFact('zipCode', 99992) // zipCode fails
191-
engine.addFact('gender', 'female') // gender fails
205+
engine.addFact('zipCode', ZIP_CODE) // zipCode fails
206+
engine.addFact('gender', GENDER) // gender fails
192207
await engine.run()
193208
expect(failureSpy.callCount).to.equal(1)
194209
expect(successSpy.callCount).to.equal(0)
@@ -207,7 +222,9 @@ describe.only('Engine: event', () => {
207222
expect(failureSpy.callCount).to.equal(0)
208223
expect(ruleResult.result).to.be.true()
209224
expect(ruleResult.conditions.any[0].result).to.be.true()
225+
expect(ruleResult.conditions.any[0].factResult).to.equal(21)
210226
expect(ruleResult.conditions.any[1].result).to.be.false()
227+
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
211228
successSpy()
212229
})
213230
rule.on('failure', failureSpy)
@@ -217,6 +234,7 @@ describe.only('Engine: event', () => {
217234
})
218235

219236
it('on-failure, it passes the event type and params', async () => {
237+
let AGE = 10
220238
let successSpy = sinon.spy()
221239
let failureSpy = sinon.spy()
222240
let rule = engine.rules[0]
@@ -226,12 +244,14 @@ describe.only('Engine: event', () => {
226244
expect(successSpy.callCount).to.equal(0)
227245
expect(ruleResult.result).to.be.false()
228246
expect(ruleResult.conditions.any[0].result).to.be.false()
247+
expect(ruleResult.conditions.any[0].factResult).to.equal(AGE)
229248
expect(ruleResult.conditions.any[1].result).to.be.false()
249+
expect(ruleResult.conditions.any[1].factResult).to.equal(false)
230250
failureSpy()
231251
})
232252
rule.on('success', successSpy)
233253
// both conditions will fail
234-
engine.addFact('age', 10)
254+
engine.addFact('age', AGE)
235255
await engine.run()
236256
expect(failureSpy.callCount).to.equal(1)
237257
expect(successSpy.callCount).to.equal(0)

0 commit comments

Comments
 (0)