diff --git a/source/reducers.js b/source/reducers.js index abb6fd44f..6d09926c6 100644 --- a/source/reducers.js +++ b/source/reducers.js @@ -23,10 +23,7 @@ let assume = (evaluator, assumptions) => state => name => { return userInput != null ? userInput : assumptions[name] } -export let reduceSteps = (state, action) => { - - let flatRules = rules - +export let reduceSteps = (tracker, flatRules, answerSource) => (state, action) => { if (![START_CONVERSATION, STEP_ACTION].includes(action.type)) return state @@ -38,7 +35,7 @@ export let reduceSteps = (state, action) => { hardAssumptions = R.pathOr({},['simulateur','hypothèses'],sim), // Soft assumptions are revealed after the simulation ends, and can be changed softAssumptions = R.pathOr({},['simulateur','par défaut'],sim), - intermediateSituation = assume(fromConversation, hardAssumptions), + intermediateSituation = assume(answerSource, hardAssumptions), completeSituation = assume(intermediateSituation,softAssumptions) let situationGate = completeSituation(state), @@ -52,14 +49,16 @@ export let reduceSteps = (state, action) => { } if (action.type == START_CONVERSATION) { + let unfoldedSteps = buildNextSteps(situationGate, flatRules, newState.analysedSituation) + return { ...newState, foldedSteps: [], - unfoldedSteps: buildNextSteps(situationGate, flatRules, newState.analysedSituation) + unfoldedSteps } } if (action.type == STEP_ACTION && action.name == 'fold') { - ReactPiwik.push(['trackEvent', 'answer', action.step+": "+situationGate(action.step)]); + tracker.push(['trackEvent', 'answer', action.step+": "+situationGate(action.step)]); let foldedSteps = [...state.foldedSteps, R.head(state.unfoldedSteps)], unfoldedSteps = buildNextSteps(situationGate, flatRules, newState.analysedSituation), @@ -73,7 +72,7 @@ export let reduceSteps = (state, action) => { reanalyse = analyseTopDown(flatRules,rootVariable)(newSituation), extraSteps = buildNextSteps(newSituation, flatRules, reanalyse) - ReactPiwik.push(['trackEvent', 'done', 'extra questions: '+extraSteps.length]); + tracker.push(['trackEvent', 'done', 'extra questions: '+extraSteps.length]); return { ...newState, @@ -84,7 +83,7 @@ export let reduceSteps = (state, action) => { } if (done) { - ReactPiwik.push(['trackEvent', 'done', 'no more questions']); + tracker.push(['trackEvent', 'done', 'no more questions']); } return { @@ -94,10 +93,10 @@ export let reduceSteps = (state, action) => { } } if (action.type == STEP_ACTION && action.name == 'unfold') { - ReactPiwik.push(['trackEvent', 'unfold', action.step]); + tracker.push(['trackEvent', 'unfold', action.step]); let stepFinder = R.propEq('name', action.step), - foldedSteps = R.reject(stepFinder)(state.foldedSteps), + foldedSteps = R.reject(stepFinder)(state.foldedSteps).concat(state.unfoldedSteps), extraSteps = R.reject(stepFinder)(state.extraSteps) return { @@ -148,5 +147,5 @@ export default reduceReducers( }), // cross-cutting concerns because here `state` is the whole state tree - reduceSteps + reduceSteps(ReactPiwik, rules, fromConversation) ) diff --git a/test/reducers.test.js b/test/reducers.test.js new file mode 100644 index 000000000..747d1042b --- /dev/null +++ b/test/reducers.test.js @@ -0,0 +1,69 @@ +import R from 'ramda' + +import {expect} from 'chai' +import {rules as realRules, enrichRule} from '../source/engine/rules' +import {analyseSituation, analyseTopDown} from '../source/engine/traverse' +import {buildNextSteps, collectMissingVariables, getObjectives} from '../source/engine/generateQuestions' + +import {reduceSteps} from '../source/reducers' + +let stateSelector = state => name => null +let tracker = {push: array => null} + +describe('fold', function() { + + it('should start conversation with only unfolded questions', function() { + let rawRules = [ + // TODO - this won't work without the indirection, figure out why + {nom: "startHere", formule: {somme: ["a","b"]}, espace: "top"}, + {nom: "a", espace: "top", formule: "aa"}, + {nom: "b", espace: "top", formule: "bb"}, + {nom: "aa", question: "?", titre: "a", espace: "top"}, + {nom: "bb", question: "?", titre: "b", espace: "top"}], + rules = rawRules.map(enrichRule), + reducer = reduceSteps(tracker, rules, stateSelector), + action = {type:'START_CONVERSATION', rootVariable: 'startHere'}, + // situation = analyseTopDown(rules,"startHere")(stateSelector({})), + // objectives = getObjectives(stateSelector({}), situation.root, situation.parsedRules), + // missing = collectMissingVariables()(stateSelector({}),situation), + result = reducer({},action) + + expect(result).to.have.property('unfoldedSteps') + expect(result.unfoldedSteps).to.have.lengthOf(2) + expect(result.unfoldedSteps[0]).to.have.deep.property("name","top . aa") + expect(result.unfoldedSteps[1]).to.have.deep.property("name","top . bb") + }); + + it('should deal with double unfold', function() { + let fakeState = {} + let stateSelector = state => name => fakeState[name] + + let rawRules = [ + // TODO - this won't work without the indirection, figure out why + {nom: "startHere", formule: {somme: ["a","b"]}, espace: "top"}, + {nom: "a", espace: "top", formule: "aa"}, + {nom: "b", espace: "top", formule: "bb"}, + {nom: "aa", question: "?", titre: "a", espace: "top"}, + {nom: "bb", question: "?", titre: "b", espace: "top"}], + rules = rawRules.map(enrichRule), + reducer = reduceSteps(tracker, rules, stateSelector) + + var step1 = reducer({},{type:'START_CONVERSATION', rootVariable: 'startHere'}) + fakeState['top . aa'] = 1 + var step2 = reducer(step1,{type:'STEP_ACTION', name: 'fold', step: 'top . aa'}) + fakeState['top . bb'] = 1 + var step3 = reducer(step2,{type:'STEP_ACTION', name: 'fold', step: 'top . bb'}) + var step4 = reducer(step3,{type:'STEP_ACTION', name: 'unfold', step: 'top . aa'}) + var step5 = reducer(step4,{type:'STEP_ACTION', name: 'unfold', step: 'top . bb'}) + + let result = step5 + + expect(result).to.have.property('unfoldedSteps') + expect(result.unfoldedSteps).to.have.lengthOf(1) + expect(result.unfoldedSteps[0]).to.have.deep.property("name","top . bb") + expect(result).to.have.property('foldedSteps') + expect(result.foldedSteps).to.have.lengthOf(1) + expect(result.foldedSteps[0]).to.have.deep.property("name","top . aa") + }); + +});