Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit fef75b2

Browse files
committed
ajoute un utilitaire pour tester un arbre
1 parent 6150570 commit fef75b2

File tree

3 files changed

+127
-59
lines changed

3 files changed

+127
-59
lines changed

packages/api/src/business/rules-demarches/machine-helper.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { AnyMachineSnapshot, createActor, EventObject, MachineSnapshot, StateMac
22
import { CaminoCommonContext, DBEtat, Etape, Intervenant, intervenants, tags } from './machine-common'
33
import { DemarchesStatutsIds, DemarcheStatutId } from 'camino-common/src/static/demarchesStatuts'
44
import { CaminoDate } from 'camino-common/src/date'
5-
import { OmitDistributive } from 'camino-common/src/typescript-tools'
5+
import { isNotNullNorUndefined, OmitDistributive } from 'camino-common/src/typescript-tools'
66

77
type CaminoState<CaminoContext extends CaminoCommonContext, CaminoEvent extends EventObject> = MachineSnapshot<CaminoContext, CaminoEvent, any, any, any, any, any>
88

@@ -214,28 +214,31 @@ export abstract class CaminoMachine<CaminoContext extends CaminoCommonContext, C
214214
return intervenants.filter(r => responsables.includes(tags.responsable[r]))
215215
}
216216

217+
public possibleNextEvents(state: CaminoState<CaminoContext, CaminoEvent>, date: CaminoDate): CaminoEvent[] {
218+
return getNextEvents(state)
219+
.filter((event: string) => this.isEvent(event))
220+
.flatMap(event => {
221+
const events = this.toPotentialCaminoXStateEvent(event, date)
222+
223+
return events.filter(event => {
224+
return state.can(event) && state.status !== 'done'
225+
})
226+
})
227+
.filter(isNotNullNorUndefined)
228+
.toSorted((a, b) => a.type.localeCompare(b.type))
229+
}
230+
217231
public possibleNextEtapes(etapes: readonly Etape[], date: CaminoDate): (OmitDistributive<Etape, 'date' | 'titreTypeId' | 'demarcheTypeId'> & { mainStep: boolean })[] {
218232
const state = this.assertGoTo(etapes)
219233

220-
if (state !== undefined) {
221-
return getNextEvents(state)
222-
.filter((event: string) => this.isEvent(event))
223-
.flatMap(event => {
224-
const events = this.toPotentialCaminoXStateEvent(event, date)
225-
226-
return events
227-
.filter(event => {
228-
return state.can(event) && state.status !== 'done'
229-
})
230-
.flatMap(event => this.caminoXStateEventToEtapes(event))
231-
})
232-
.filter(event => event !== undefined)
234+
if (isNotNullNorUndefined(state)) {
235+
return this.possibleNextEvents(state, date).flatMap(this.caminoXStateEventToEtapes).filter(isNotNullNorUndefined)
233236
}
234237

235238
return []
236239
}
237240
}
238241

239-
export function getNextEvents(snapshot: AnyMachineSnapshot): string[] {
242+
function getNextEvents(snapshot: AnyMachineSnapshot): string[] {
240243
return [...new Set([...snapshot._nodes.flatMap(sn => sn.ownEvents)])]
241244
}

packages/api/src/business/rules-demarches/machine-test-helper.ts

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { CaminoCommonContext, Etape } from './machine-common'
22
import { Actor, EventObject, createActor } from 'xstate'
3-
import { CaminoMachine, getNextEvents } from './machine-helper'
3+
import { CaminoMachine } from './machine-helper'
44
import { expect } from 'vitest'
55
import { CaminoDate, dateAddDays, toCaminoDate } from 'camino-common/src/date'
66
import { EtapeTypeEtapeStatutValidPair } from 'camino-common/src/static/etapesTypesEtapesStatuts'
7-
import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools'
7+
import { isNotNullNorUndefined, onlyUnique } from 'camino-common/src/typescript-tools'
8+
import { DemarchesStatuts } from 'camino-common/src/static/demarchesStatuts'
89
interface CustomMatchers<R = unknown> {
910
canOnlyTransitionTo<T extends EventObject, C extends CaminoCommonContext>(context: { machine: CaminoMachine<C, T>; date: CaminoDate }, _events: T['type'][]): R
1011
}
@@ -19,21 +20,18 @@ declare global {
1920
interface InverseAsymmetricMatchers extends CustomMatchers {}
2021
}
2122
}
23+
2224
expect.extend({
2325
canOnlyTransitionTo<T extends EventObject, C extends CaminoCommonContext>(
2426
service: Actor<CaminoMachine<C, T>['machine']>,
2527
{ machine, date }: { machine: CaminoMachine<C, T>; date: CaminoDate },
2628
events: T['type'][]
2729
) {
2830
events = events.toSorted()
29-
const passEvents: (typeof events)[number][] = getNextEvents(service.getSnapshot())
30-
.filter((event: string) => machine.isEvent(event))
31-
.filter((event: (typeof events)[number]) => {
32-
const events = machine.toPotentialCaminoXStateEvent(event, date)
33-
34-
return events.some(event => service.getSnapshot().can(event) && service.getSnapshot().status !== 'done')
35-
})
36-
.toSorted()
31+
const passEvents = machine
32+
.possibleNextEvents(service.getSnapshot(), date)
33+
.map(({ type }) => type)
34+
.filter(onlyUnique)
3735

3836
if (passEvents.length !== events.length || passEvents.some((entry, index) => entry !== events[index])) {
3937
return {
@@ -62,14 +60,10 @@ export const interpretMachine = <T extends EventObject, C extends CaminoCommonCo
6260
throw new Error(
6361
`Error: cannot execute step: '${JSON.stringify(etapeAFaire)}' after '${JSON.stringify(
6462
etapes.slice(0, i).map(etape => etape.etapeTypeId + '_' + etape.etapeStatutId)
65-
)}'. The event ${JSON.stringify(event)} should be one of '${getNextEvents(service.getSnapshot())
66-
.filter(event => machine.isEvent(event))
67-
.filter((event: EventObject['type']) => {
68-
const events = machine.toPotentialCaminoXStateEvent(event, etapeAFaire.date)
69-
70-
return events.some(event => service.getSnapshot().can(event) && service.getSnapshot().status !== 'done')
71-
})
72-
.toSorted()}'`
63+
)}'. The event ${JSON.stringify(event)} should be one of '${machine
64+
.possibleNextEvents(service.getSnapshot(), etapeAFaire.date)
65+
.map(({ type }) => type)
66+
.filter(onlyUnique)}'`
7367
)
7468
}
7569
service.send(event)
@@ -78,6 +72,50 @@ export const interpretMachine = <T extends EventObject, C extends CaminoCommonCo
7872
return service
7973
}
8074

75+
export const getEventsTree = <T extends EventObject, C extends CaminoCommonContext>(
76+
machine: CaminoMachine<C, T>,
77+
initDate: `${number}-${number}-${number}`,
78+
etapes: readonly (EtapeTypeEtapeStatutValidPair & Omit<Etape, 'date' | 'etapeTypeId' | 'etapeStatutId' | 'titreTypeId' | 'demarcheTypeId'> & { addDays?: number })[]
79+
): string[] => {
80+
const { service, dateFin } = setDateAndOrderAndInterpretMachine(machine, initDate, [])
81+
const passEvents: T['type'][] = machine
82+
.possibleNextEvents(service.getSnapshot(), dateFin)
83+
.map(({ type }) => type)
84+
.filter(onlyUnique)
85+
86+
const steps = [
87+
{
88+
type: 'RIEN',
89+
visibilite: service.getSnapshot().context.visibilite,
90+
demarcheStatut: DemarchesStatuts[service.getSnapshot().context.demarcheStatut].nom,
91+
events: passEvents,
92+
},
93+
...etapes.map((_etape, index) => {
94+
const etapesToLaunch = etapes.slice(0, index + 1)
95+
const { service, dateFin, etapes: etapesWithDates } = setDateAndOrderAndInterpretMachine(machine, initDate, etapesToLaunch)
96+
97+
const passEvents: T['type'][] = machine
98+
.possibleNextEvents(service.getSnapshot(), dateFin)
99+
.map(({ type }) => type)
100+
.filter(onlyUnique)
101+
const event = machine.eventFrom(etapesWithDates[etapesWithDates.length - 1])
102+
103+
return {
104+
type: event.type,
105+
visibilite: service.getSnapshot().context.visibilite,
106+
demarcheStatut: DemarchesStatuts[service.getSnapshot().context.demarcheStatut].nom,
107+
events: passEvents,
108+
}
109+
}),
110+
]
111+
112+
const maxPadType = Math.max(...steps.map(({ type }) => type.length))
113+
114+
return steps.map(step => {
115+
return `${step.type.padEnd(maxPadType, ' ')} (${step.visibilite.padEnd(14, ' ')}, ${step.demarcheStatut.padEnd(23, ' ')}) -> [${step.events.join(',')}]`
116+
})
117+
}
118+
81119
export const setDateAndOrderAndInterpretMachine = <T extends EventObject, C extends CaminoCommonContext>(
82120
machine: CaminoMachine<C, T>,
83121
initDate: `${number}-${number}-${number}`,

0 commit comments

Comments
 (0)