mirror of
https://github.com/betagouv/mon-entreprise
synced 2025-03-14 02:05:08 +00:00
Le mécanisme variation doit avoir un ordre de précédence (si une condition vraie suit une condition non résolue, alors on doit attendre la résolution de cette dernière) en l'absence d'un système de typage qui nous garantirait l'exhaustivité des variations.
387 lines
9.8 KiB
JavaScript
387 lines
9.8 KiB
JavaScript
import { expect } from 'chai'
|
|
import {
|
|
collectMissingVariables,
|
|
getNextSteps
|
|
} from '../source/engine/generateQuestions'
|
|
import { enrichRule, rules as realRules } from '../source/engine/rules'
|
|
import { analyse, parseAll } from '../source/engine/traverse'
|
|
|
|
let stateSelector = () => null
|
|
|
|
describe('collectMissingVariables', function() {
|
|
it('should identify missing variables', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: 2,
|
|
'non applicable si': 'sum . evt . ko',
|
|
espace: 'sum'
|
|
},
|
|
{
|
|
nom: 'evt',
|
|
espace: 'sum',
|
|
formule: { 'une possibilité': ['ko'] },
|
|
titre: 'Truc',
|
|
question: '?'
|
|
},
|
|
{ nom: 'ko', espace: 'sum . evt' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.include('sum . evt . ko')
|
|
})
|
|
|
|
it('should identify missing variables mentioned in expressions', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: 2,
|
|
'non applicable si': 'evt . nyet > evt . nope',
|
|
espace: 'sum'
|
|
},
|
|
{ nom: 'nope', espace: 'sum . evt' },
|
|
{ nom: 'nyet', espace: 'sum . evt' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.include('sum . evt . nyet')
|
|
expect(result).to.include('sum . evt . nope')
|
|
})
|
|
|
|
it('should ignore missing variables in the formula if not applicable', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: 'trois',
|
|
'non applicable si': '3 > 2',
|
|
espace: 'sum'
|
|
},
|
|
{ nom: 'trois', espace: 'sum' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.be.empty
|
|
})
|
|
|
|
it('should not report missing variables when "one of these" short-circuits', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: 'trois',
|
|
'non applicable si': {
|
|
'une de ces conditions': ['3 > 2', 'trois']
|
|
},
|
|
espace: 'sum'
|
|
},
|
|
{ nom: 'trois', espace: 'sum' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.be.empty
|
|
})
|
|
|
|
it('should report "une possibilité" as a missing variable even though it has a formula', function() {
|
|
let rawRules = [
|
|
{ nom: 'startHere', formule: 'trois', espace: 'top' },
|
|
{
|
|
nom: 'trois',
|
|
formule: { 'une possibilité': ['ko'] },
|
|
espace: 'top'
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.include('top . trois')
|
|
})
|
|
|
|
it('should not report missing variables when "une possibilité" is inapplicable', function() {
|
|
let rawRules = [
|
|
{ nom: 'startHere', formule: 'trois', espace: 'top' },
|
|
{
|
|
nom: 'trois',
|
|
formule: { 'une possibilité': ['ko'] },
|
|
'non applicable si': 1,
|
|
espace: 'top'
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.be.empty
|
|
null
|
|
})
|
|
|
|
it('should not report missing variables when "une possibilité" was answered', function() {
|
|
let mySelector = name => ({ 'top . trois': 'ko' }[name])
|
|
|
|
let rawRules = [
|
|
{ nom: 'startHere', formule: 'trois', espace: 'top' },
|
|
{
|
|
nom: 'trois',
|
|
formule: { 'une possibilité': ['ko'] },
|
|
espace: 'top'
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(mySelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.be.empty
|
|
})
|
|
|
|
it('should report missing variables in switch statements', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
'aiguillage numérique': {
|
|
'11 > dix': '1000%',
|
|
'3 > dix': '1100%',
|
|
'1 > dix': '1200%'
|
|
}
|
|
},
|
|
espace: 'top'
|
|
},
|
|
{ nom: 'dix', espace: 'top' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.include('top . dix')
|
|
})
|
|
|
|
it('should report missing variables in variations', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: { somme: ['variations'] },
|
|
espace: 'top'
|
|
},
|
|
{
|
|
nom: 'variations',
|
|
espace: 'top',
|
|
formule: {
|
|
barème: {
|
|
assiette: 2008,
|
|
variations: [
|
|
{
|
|
si: 'dix',
|
|
alors: {
|
|
'multiplicateur des tranches': 'deux',
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.1 },
|
|
{ de: 1, à: 2, taux: 'trois' },
|
|
{ 'au-dessus de': 2, taux: 10 }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
si: '3 > 4',
|
|
alors: {
|
|
'multiplicateur des tranches': 'quatre',
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.1 },
|
|
{ de: 1, à: 2, taux: 1.8 },
|
|
{ 'au-dessus de': 2, taux: 10 }
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
{ nom: 'dix', espace: 'top' },
|
|
{ nom: 'deux', espace: 'top' },
|
|
{ nom: 'trois', espace: 'top' },
|
|
{ nom: 'quatre', espace: 'top' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.include('top . dix')
|
|
expect(result).to.include('top . deux')
|
|
expect(result).not.to.include('top . quatre')
|
|
// TODO
|
|
// expect(result).to.include('top . trois')
|
|
})
|
|
|
|
it('should not report missing variables in switch for consequences of false conditions', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
'aiguillage numérique': {
|
|
'8 > 10': '1000%',
|
|
'1 > 2': 'dix'
|
|
}
|
|
},
|
|
espace: 'top'
|
|
},
|
|
{ nom: 'dix', espace: 'top' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.be.empty
|
|
})
|
|
|
|
it('should report missing variables in consequence when its condition is unresolved', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
'aiguillage numérique': {
|
|
'10 > 11': '1000%',
|
|
'3 > dix': {
|
|
douze: '560%',
|
|
'1 > 2': '75015%'
|
|
}
|
|
}
|
|
},
|
|
espace: 'top'
|
|
},
|
|
{ nom: 'douze', espace: 'top' },
|
|
{ nom: 'dix', espace: 'top' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.include('top . dix')
|
|
expect(result).to.include('top . douze')
|
|
})
|
|
|
|
it('should not report missing variables when a switch short-circuits', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
'aiguillage numérique': {
|
|
'11 > 10': '1000%',
|
|
'3 > dix': '1100%',
|
|
'1 > dix': '1200%'
|
|
}
|
|
},
|
|
espace: 'top'
|
|
},
|
|
{ nom: 'dix', espace: 'top' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'startHere')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.be.empty
|
|
})
|
|
})
|
|
|
|
describe('nextSteps', function() {
|
|
it('should generate questions', function() {
|
|
let rawRules = [
|
|
{ nom: 'sum', formule: { somme: [2, 'deux'] }, espace: 'top' },
|
|
{
|
|
nom: 'deux',
|
|
formule: 2,
|
|
'non applicable si': "top . sum . evt = 'ko'",
|
|
espace: 'top'
|
|
},
|
|
{
|
|
nom: 'evt',
|
|
espace: 'top . sum',
|
|
formule: { 'une possibilité': ['ko'] },
|
|
titre: 'Truc',
|
|
question: '?'
|
|
},
|
|
{ nom: 'ko', espace: 'top . sum . evt' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'sum')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.have.lengthOf(1)
|
|
expect(result[0]).to.equal('top . sum . evt')
|
|
})
|
|
|
|
it('should generate questions from the real rules, experimental version', function() {
|
|
let stateSelector = name =>
|
|
({
|
|
'contrat salarié . type de contrat': 'CDI',
|
|
'entreprise . effectif': '50'
|
|
}[name])
|
|
|
|
let rules = parseAll(realRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'salaire')(stateSelector),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result[0]).to.equal('contrat salarié . temps partiel')
|
|
})
|
|
|
|
it('should ask "motif CDD" if "CDD" applies', function() {
|
|
let stateSelector = name =>
|
|
({
|
|
'contrat salarié . type de contrat': 'CDD',
|
|
'contrat salarié . salaire . brut de base': '2300'
|
|
}[name])
|
|
|
|
let rules = parseAll(realRules.map(enrichRule)),
|
|
analysis = analyse(rules, 'contrat salarié . salaire . net')(
|
|
stateSelector
|
|
),
|
|
result = collectMissingVariables(analysis.targets)
|
|
|
|
expect(result).to.include('contrat salarié . CDD . motif')
|
|
})
|
|
})
|
|
|
|
describe('getNextSteps', function() {
|
|
it('should give priority to questions that advance most targets', function() {
|
|
let missingVariablesByTarget = {
|
|
chargé: {
|
|
effectif: 34.01,
|
|
cadre: 30
|
|
},
|
|
net: {
|
|
cadre: 10.1
|
|
},
|
|
aides: {
|
|
effectif: 32.0,
|
|
cadre: 10
|
|
}
|
|
}
|
|
|
|
let result = getNextSteps(missingVariablesByTarget)
|
|
|
|
expect(result[0]).to.equal('cadre')
|
|
})
|
|
|
|
it('should give priority to questions by total weight when advancing the same target count', function() {
|
|
let missingVariablesByTarget = {
|
|
chargé: {
|
|
effectif: 24.01,
|
|
cadre: 30
|
|
},
|
|
net: {
|
|
effectif: 24.01,
|
|
cadre: 10.1
|
|
},
|
|
aides: {}
|
|
}
|
|
|
|
let result = getNextSteps(missingVariablesByTarget)
|
|
|
|
expect(result[0]).to.equal('effectif')
|
|
})
|
|
})
|