mirror of
https://github.com/betagouv/mon-entreprise
synced 2025-02-09 00:35:00 +00:00
* Définition à partir du nom complet en notation pointée (plutôt que comme deux attributs indépendants "name" et "espace") * Structure de données de premier niveau "dictionnaire" plutôt que liste, s'aligne mieux avec notre contrainte d'unicité des noms * Possibilité de définir les règles à partir d'une liste dans les tests, dans ce cas il ne faut plus utiliser l'attribut "espace" mais renseigner directement la notation pointée dans le "nom".
449 lines
12 KiB
JavaScript
449 lines
12 KiB
JavaScript
import { expect } from 'chai'
|
|
import { analyse, parseAll } from '../source/engine/traverse'
|
|
import { enrichRule } from '../source/engine/rules'
|
|
|
|
let stateSelector = () => null
|
|
|
|
describe('analyse', function() {
|
|
it('should directly return simple numerical values', function() {
|
|
let rule = { nom: 'startHere', formule: 3269 }
|
|
let rules = parseAll([rule].map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 3269)
|
|
})
|
|
|
|
it('should compute expressions combining constants', function() {
|
|
let rule = { nom: 'startHere', formule: '32 + 69' }
|
|
let rules = parseAll([rule].map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 101)
|
|
})
|
|
})
|
|
|
|
describe('analyse on raw rules', function() {
|
|
it('should handle direct referencing of a variable', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{ nom: 'top . startHere', formule: 'dix' },
|
|
{ nom: 'top . dix', formule: 10 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 10)
|
|
})
|
|
|
|
it('should handle expressions referencing other rules', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{ nom: 'top . startHere', formule: '3259 + dix' },
|
|
{ nom: 'top . dix', formule: 10 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 3269)
|
|
})
|
|
|
|
it('should handle applicability conditions', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{ nom: 'top . startHere', formule: '3259 + dix' },
|
|
{ nom: 'top . dix', formule: 10, 'non applicable si': 'vrai' },
|
|
{ nom: 'top . vrai', formule: '2 > 1' }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 3259)
|
|
})
|
|
|
|
it('should handle comparisons', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{ nom: 'top . startHere', formule: '3259 > dix' },
|
|
{ nom: 'top . dix', formule: 10 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', true)
|
|
})
|
|
|
|
/* TODO: make this pass
|
|
it('should handle applicability conditions', function() {
|
|
let rawRules = [
|
|
{nom: "startHere", formule: "3259 + dix", espace: "top"},
|
|
{nom: "dix", formule: 10, espace: "top", "non applicable si" : "vrai"},
|
|
{nom: "vrai", formule: "1", espace: "top"}],
|
|
rules = rawRules.map(enrichRule)
|
|
expect(analyse(rules,"startHere")(stateSelector).targets[0]).to.have.property('nodeValue',3259)
|
|
});
|
|
*/
|
|
})
|
|
|
|
describe('analyse with mecanisms', function() {
|
|
it('should handle n-way "or"', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: { 'une de ces conditions': ['1 > 2', '1 > 0', '0 > 2'] }
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', true)
|
|
})
|
|
|
|
it('should handle n-way "and"', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: { 'toutes ces conditions': ['1 > 2', '1 > 0', '0 > 2'] }
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', false)
|
|
})
|
|
|
|
it('should handle switch statements', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{
|
|
nom: 'top . startHere',
|
|
formule: {
|
|
'aiguillage numérique': {
|
|
'1 > dix': '1000%',
|
|
'3 < dix': '1100%',
|
|
'3 > dix': '1200%'
|
|
}
|
|
}
|
|
},
|
|
{ nom: 'top . dix', formule: 10 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 11)
|
|
})
|
|
|
|
it('should handle percentages', function() {
|
|
let rawRules = [{ nom: 'top' }, { nom: 'top . startHere', formule: '35%' }],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 0.35)
|
|
})
|
|
|
|
it('should handle sums', function() {
|
|
let rawRules = [
|
|
{ nom: 'startHere', formule: { somme: [3200, 'dix', 9] } },
|
|
{ nom: 'dix', formule: 10 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 3219)
|
|
})
|
|
|
|
it('should handle multiplications', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
multiplication: {
|
|
assiette: 3259,
|
|
plafond: 3200,
|
|
facteur: 1,
|
|
taux: 1.5
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 4800)
|
|
})
|
|
|
|
it('should handle components in multiplication', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
multiplication: {
|
|
assiette: 3200,
|
|
composantes: [{ taux: 0.7 }, { taux: 0.8 }]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 4800)
|
|
})
|
|
|
|
it('should apply a ceiling to the sum of components', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
multiplication: {
|
|
assiette: 3259,
|
|
plafond: 3200,
|
|
composantes: [{ taux: 0.7 }, { taux: 0.8 }]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 4800)
|
|
})
|
|
|
|
it('should handle progressive scales', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
barème: {
|
|
assiette: 2008,
|
|
multiplicateur: 1000,
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.1 },
|
|
{ de: 1, à: 2, taux: 1.2 },
|
|
{ 'au-dessus de': 2, taux: 10 }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 100 + 1200 + 80)
|
|
})
|
|
|
|
it('should handle progressive scales with components', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
barème: {
|
|
assiette: 2008,
|
|
multiplicateur: 1000,
|
|
composantes: [
|
|
{
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.05 },
|
|
{ de: 1, à: 2, taux: 0.4 },
|
|
{ 'au-dessus de': 2, taux: 5 }
|
|
]
|
|
},
|
|
{
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.05 },
|
|
{ de: 1, à: 2, taux: 0.8 },
|
|
{ 'au-dessus de': 2, taux: 5 }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 100 + 1200 + 80)
|
|
})
|
|
|
|
it('should handle progressive scales with variations', function() {
|
|
let rawRules = [
|
|
{
|
|
nom: 'startHere',
|
|
formule: {
|
|
barème: {
|
|
assiette: 2008,
|
|
multiplicateur: 1000,
|
|
variations: [
|
|
{
|
|
si: '3 > 4',
|
|
alors: {
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.1 },
|
|
{ de: 1, à: 2, taux: 1.2 },
|
|
{ 'au-dessus de': 2, taux: 10 }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
si: '3 > 2',
|
|
alors: {
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.1 },
|
|
{ de: 1, à: 2, taux: 1.8 },
|
|
{ 'au-dessus de': 2, taux: 10 }
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 100 + 1800 + 80)
|
|
})
|
|
|
|
it('should handle max', function() {
|
|
let rawRules = [
|
|
{ nom: 'startHere', formule: { 'le maximum de': [3200, 60, 9] } }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 3200)
|
|
})
|
|
|
|
it('should handle complements', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{
|
|
nom: 'top . startHere',
|
|
formule: { complément: { cible: 'dix', montant: 93 } }
|
|
},
|
|
{ nom: 'top . dix', formule: 17 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 93 - 17)
|
|
})
|
|
|
|
it('should handle components in complements', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{
|
|
nom: 'top . startHere',
|
|
formule: {
|
|
complément: {
|
|
cible: 'dix',
|
|
composantes: [{ montant: 93 }, { montant: 93 }]
|
|
}
|
|
}
|
|
},
|
|
{ nom: 'top . dix', formule: 17 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 2 * (93 - 17))
|
|
})
|
|
|
|
it('should handle filtering on components', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{ nom: 'top . startHere', formule: 'composed [salarié]' },
|
|
{
|
|
nom: 'top . composed',
|
|
formule: {
|
|
barème: {
|
|
assiette: 2008,
|
|
multiplicateur: 1000,
|
|
composantes: [
|
|
{
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.05 },
|
|
{ de: 1, à: 2, taux: 0.4 },
|
|
{ 'au-dessus de': 2, taux: 5 }
|
|
],
|
|
attributs: { 'dû par': 'salarié' }
|
|
},
|
|
{
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.05 },
|
|
{ de: 1, à: 2, taux: 0.8 },
|
|
{ 'au-dessus de': 2, taux: 5 }
|
|
],
|
|
attributs: { 'dû par': 'employeur' }
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 50 + 400 + 40)
|
|
})
|
|
|
|
it('should compute consistent values', function() {
|
|
let rawRules = [
|
|
{ nom: 'top' },
|
|
{
|
|
nom: 'top . startHere',
|
|
formule: 'composed [salarié] + composed [employeur]'
|
|
},
|
|
{ nom: 'top . orHere', formule: 'composed' },
|
|
{
|
|
nom: 'top . composed',
|
|
formule: {
|
|
barème: {
|
|
assiette: 2008,
|
|
multiplicateur: 1000,
|
|
composantes: [
|
|
{
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.05 },
|
|
{ de: 1, à: 2, taux: 0.4 },
|
|
{ 'au-dessus de': 2, taux: 5 }
|
|
],
|
|
attributs: { 'dû par': 'salarié' }
|
|
},
|
|
{
|
|
tranches: [
|
|
{ 'en-dessous de': 1, taux: 0.05 },
|
|
{ de: 1, à: 2, taux: 0.8 },
|
|
{ 'au-dessus de': 2, taux: 5 }
|
|
],
|
|
attributs: { 'dû par': 'employeur' }
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(analyse(rules, 'orHere')(stateSelector).targets[0]).to.have.property(
|
|
'nodeValue',
|
|
100 + 1200 + 80
|
|
)
|
|
expect(
|
|
analyse(rules, 'startHere')(stateSelector).targets[0]
|
|
).to.have.property('nodeValue', 100 + 1200 + 80)
|
|
})
|
|
})
|
|
|
|
describe('Implicit parent applicability', function() {
|
|
it('should make a variable non applicable if one parent is input to false', function() {
|
|
let rawRules = [
|
|
{ nom: 'CDD', question: 'CDD ?' },
|
|
{ nom: 'CDD . surcoût', formule: 10 }
|
|
],
|
|
rules = parseAll(rawRules.map(enrichRule))
|
|
expect(
|
|
analyse(rules, 'CDD . surcoût')(name => ({ CDD: false }[name])).targets[0]
|
|
).to.have.property('nodeValue', 0)
|
|
})
|
|
})
|