@rsuci/shared-form-components 1.0.86 → 1.0.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/form-renderer/FormRenderer.d.ts.map +1 -1
- package/dist/components/form-renderer/FormRenderer.js +24 -33
- package/dist/components/form-renderer/GroupeInstanceTabs.d.ts +2 -2
- package/dist/components/form-renderer/GroupeInstanceTabs.d.ts.map +1 -1
- package/dist/components/form-renderer/GroupeInstanceTabs.js +4 -22
- package/dist/hooks/useFormInstances.js +8 -8
- package/dist/hooks/useFormRenderer.d.ts.map +1 -1
- package/dist/hooks/useFormRenderer.js +55 -12
- package/dist/lib/__tests__/groupeInstanceManager.test.d.ts +6 -0
- package/dist/lib/__tests__/groupeInstanceManager.test.d.ts.map +1 -0
- package/dist/lib/__tests__/groupeInstanceManager.test.js +454 -0
- package/dist/lib/utils/groupeInstanceManager.d.ts +15 -4
- package/dist/lib/utils/groupeInstanceManager.d.ts.map +1 -1
- package/dist/lib/utils/groupeInstanceManager.js +102 -207
- package/dist/lib/utils/interpolateVariableLabel.d.ts.map +1 -1
- package/dist/lib/utils/interpolateVariableLabel.js +1 -35
- package/package.json +1 -1
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests unitaires pour GroupeInstanceManager
|
|
3
|
+
* Couvre le comptage, l'ajout/suppression, la validation et les scénarios d'intégration
|
|
4
|
+
*/
|
|
5
|
+
import { GroupeInstanceManager } from '../utils/groupeInstanceManager';
|
|
6
|
+
// === Helpers de création de données de test ===
|
|
7
|
+
function createVariable(code, overrides = {}) {
|
|
8
|
+
return {
|
|
9
|
+
id: Math.floor(Math.random() * 10000),
|
|
10
|
+
code,
|
|
11
|
+
designation: `Variable ${code}`,
|
|
12
|
+
typeCode: 'STRING',
|
|
13
|
+
groupeCode: 'TEST_GROUP',
|
|
14
|
+
ordre: 1,
|
|
15
|
+
estObligatoire: false,
|
|
16
|
+
estVisible: true,
|
|
17
|
+
...overrides
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function createGroupe(overrides = {}) {
|
|
21
|
+
return {
|
|
22
|
+
code: 'TEST_GROUP',
|
|
23
|
+
designation: 'Groupe Test',
|
|
24
|
+
ordre: 1,
|
|
25
|
+
estMultiple: false,
|
|
26
|
+
variables: [createVariable('S1_01'), createVariable('S1_02')],
|
|
27
|
+
...overrides
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createMultipleGroupe(overrides = {}) {
|
|
31
|
+
return createGroupe({
|
|
32
|
+
estMultiple: true,
|
|
33
|
+
codeVariable: 'S0_23',
|
|
34
|
+
...overrides
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function createInstance(numero, reponses = {}) {
|
|
38
|
+
return {
|
|
39
|
+
numeroInstance: numero,
|
|
40
|
+
libelle: `Groupe Test ${numero}`,
|
|
41
|
+
estComplete: false,
|
|
42
|
+
reponses
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createResponse(variableCode, valeur, numeroMembre) {
|
|
46
|
+
return {
|
|
47
|
+
variableId: Math.floor(Math.random() * 10000),
|
|
48
|
+
variableCode,
|
|
49
|
+
valeur,
|
|
50
|
+
numeroMembre,
|
|
51
|
+
dateModification: new Date()
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function createControlResponse(value) {
|
|
55
|
+
return {
|
|
56
|
+
S0_23: createResponse('S0_23', value)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// === Tests ===
|
|
60
|
+
describe('GroupeInstanceManager', () => {
|
|
61
|
+
describe('getMaxInstances', () => {
|
|
62
|
+
it('devrait retourner 1 pour un groupe non multiple', () => {
|
|
63
|
+
const groupe = createGroupe({ estMultiple: false });
|
|
64
|
+
expect(GroupeInstanceManager.getMaxInstances(groupe, {})).toBe(1);
|
|
65
|
+
});
|
|
66
|
+
it('devrait retourner 1 pour un groupe multiple sans codeVariable', () => {
|
|
67
|
+
const groupe = createGroupe({ estMultiple: true, codeVariable: undefined });
|
|
68
|
+
expect(GroupeInstanceManager.getMaxInstances(groupe, {})).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
it('devrait retourner la valeur numerique de la variable de controle', () => {
|
|
71
|
+
const groupe = createMultipleGroupe();
|
|
72
|
+
const responses = createControlResponse(3);
|
|
73
|
+
expect(GroupeInstanceManager.getMaxInstances(groupe, responses)).toBe(3);
|
|
74
|
+
});
|
|
75
|
+
it('devrait parser une valeur string de la variable de controle', () => {
|
|
76
|
+
const groupe = createMultipleGroupe();
|
|
77
|
+
const responses = {
|
|
78
|
+
S0_23: createResponse('S0_23', '5')
|
|
79
|
+
};
|
|
80
|
+
expect(GroupeInstanceManager.getMaxInstances(groupe, responses)).toBe(5);
|
|
81
|
+
});
|
|
82
|
+
it('devrait retourner 1 si aucune reponse pour la variable de controle', () => {
|
|
83
|
+
const groupe = createMultipleGroupe();
|
|
84
|
+
expect(GroupeInstanceManager.getMaxInstances(groupe, {})).toBe(1);
|
|
85
|
+
});
|
|
86
|
+
it('devrait trouver la reponse par variableCode quand la cle directe manque', () => {
|
|
87
|
+
const groupe = createMultipleGroupe();
|
|
88
|
+
const responses = {
|
|
89
|
+
'some_other_key': createResponse('S0_23', 4)
|
|
90
|
+
};
|
|
91
|
+
expect(GroupeInstanceManager.getMaxInstances(groupe, responses)).toBe(4);
|
|
92
|
+
});
|
|
93
|
+
it('devrait retourner strictement la valeur de controle (pas gonflee par instances existantes)', () => {
|
|
94
|
+
// Apres Fix 1c: getMaxInstances ne doit PAS gonfler au-dela de la variable de controle
|
|
95
|
+
const groupe = createMultipleGroupe({
|
|
96
|
+
instances: [createInstance(1), createInstance(2), createInstance(3), createInstance(4), createInstance(5)]
|
|
97
|
+
});
|
|
98
|
+
const responses = createControlResponse(3);
|
|
99
|
+
// Le max devrait etre 3 (valeur de controle), pas 5 (nombre d'instances)
|
|
100
|
+
expect(GroupeInstanceManager.getMaxInstances(groupe, responses)).toBe(3);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('getInstancesCount', () => {
|
|
104
|
+
it('devrait retourner 1 pour un groupe non multiple', () => {
|
|
105
|
+
const groupe = createGroupe({ estMultiple: false });
|
|
106
|
+
expect(GroupeInstanceManager.getInstancesCount(groupe, {})).toBe(1);
|
|
107
|
+
});
|
|
108
|
+
it('devrait retourner le nombre d\'instances si elles existent', () => {
|
|
109
|
+
const groupe = createMultipleGroupe({
|
|
110
|
+
instances: [createInstance(1), createInstance(2), createInstance(3)]
|
|
111
|
+
});
|
|
112
|
+
expect(GroupeInstanceManager.getInstancesCount(groupe, {})).toBe(3);
|
|
113
|
+
});
|
|
114
|
+
it('devrait utiliser le fallback par numeroMembre quand instances est vide', () => {
|
|
115
|
+
const groupe = createMultipleGroupe({ instances: undefined });
|
|
116
|
+
const responses = {
|
|
117
|
+
'S1_01_1': createResponse('S1_01', 'val1', 1),
|
|
118
|
+
'S1_01_2': createResponse('S1_01', 'val2', 2),
|
|
119
|
+
'S1_02_1': createResponse('S1_02', 'val3', 1),
|
|
120
|
+
'S1_02_2': createResponse('S1_02', 'val4', 2),
|
|
121
|
+
};
|
|
122
|
+
expect(GroupeInstanceManager.getInstancesCount(groupe, responses)).toBe(2);
|
|
123
|
+
});
|
|
124
|
+
it('devrait retourner au minimum 1', () => {
|
|
125
|
+
const groupe = createMultipleGroupe({ instances: undefined });
|
|
126
|
+
expect(GroupeInstanceManager.getInstancesCount(groupe, {})).toBe(1);
|
|
127
|
+
});
|
|
128
|
+
it('ne devrait PAS fausser le comptage avec des codes variables contenant des chiffres', () => {
|
|
129
|
+
// Apres Fix 1a: le parsing de cles "S1_01" ne doit pas creer un faux instance numero 1
|
|
130
|
+
const groupe = createMultipleGroupe({
|
|
131
|
+
instances: [createInstance(1), createInstance(2)]
|
|
132
|
+
});
|
|
133
|
+
// Meme s'il y a des cles avec des formats ambigus, instances.length prime
|
|
134
|
+
expect(GroupeInstanceManager.getInstancesCount(groupe, {})).toBe(2);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe('createInstance', () => {
|
|
138
|
+
it('devrait creer une instance avec le bon numero et libelle', () => {
|
|
139
|
+
const groupe = createMultipleGroupe();
|
|
140
|
+
const instance = GroupeInstanceManager.createInstance(groupe, 3);
|
|
141
|
+
expect(instance.numeroInstance).toBe(3);
|
|
142
|
+
expect(instance.libelle).toBe('Groupe Test 3');
|
|
143
|
+
expect(instance.estComplete).toBe(false);
|
|
144
|
+
expect(instance.reponses).toEqual({});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
describe('initializeInstances', () => {
|
|
148
|
+
it('devrait creer au moins 1 instance si aucune reponse', () => {
|
|
149
|
+
const groupe = createMultipleGroupe();
|
|
150
|
+
const responses = createControlResponse(3);
|
|
151
|
+
const instances = GroupeInstanceManager.initializeInstances(groupe, responses);
|
|
152
|
+
expect(instances.length).toBeGreaterThanOrEqual(1);
|
|
153
|
+
});
|
|
154
|
+
it('devrait creer des instances basees sur les reponses existantes avec numeroMembre', () => {
|
|
155
|
+
const groupe = createMultipleGroupe();
|
|
156
|
+
const responses = {
|
|
157
|
+
...createControlResponse(3),
|
|
158
|
+
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
159
|
+
'S1_02_1': createResponse('S1_02', '25', 1),
|
|
160
|
+
'S1_01_2': createResponse('S1_01', 'Bob', 2),
|
|
161
|
+
'S1_02_2': createResponse('S1_02', '30', 2),
|
|
162
|
+
};
|
|
163
|
+
const instances = GroupeInstanceManager.initializeInstances(groupe, responses);
|
|
164
|
+
expect(instances.length).toBe(2);
|
|
165
|
+
});
|
|
166
|
+
it('ne devrait PAS muter l\'objet responses original', () => {
|
|
167
|
+
const groupe = createMultipleGroupe();
|
|
168
|
+
const responses = {
|
|
169
|
+
...createControlResponse(2),
|
|
170
|
+
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
171
|
+
};
|
|
172
|
+
const originalKeys = Object.keys(responses).sort();
|
|
173
|
+
GroupeInstanceManager.initializeInstances(groupe, responses);
|
|
174
|
+
expect(Object.keys(responses).sort()).toEqual(originalKeys);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
describe('canAddInstance', () => {
|
|
178
|
+
it('devrait retourner false pour un groupe non multiple', () => {
|
|
179
|
+
const groupe = createGroupe({ estMultiple: false });
|
|
180
|
+
const result = GroupeInstanceManager.canAddInstance(groupe, {});
|
|
181
|
+
expect(result.canProceed).toBe(false);
|
|
182
|
+
});
|
|
183
|
+
it('devrait retourner true si currentCount < maxInstances', () => {
|
|
184
|
+
const groupe = createMultipleGroupe({
|
|
185
|
+
instances: [createInstance(1)]
|
|
186
|
+
});
|
|
187
|
+
const responses = createControlResponse(3);
|
|
188
|
+
const result = GroupeInstanceManager.canAddInstance(groupe, responses);
|
|
189
|
+
expect(result.canProceed).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
it('devrait retourner false si currentCount >= maxInstances', () => {
|
|
192
|
+
const groupe = createMultipleGroupe({
|
|
193
|
+
instances: [createInstance(1), createInstance(2), createInstance(3)]
|
|
194
|
+
});
|
|
195
|
+
const responses = createControlResponse(3);
|
|
196
|
+
const result = GroupeInstanceManager.canAddInstance(groupe, responses);
|
|
197
|
+
expect(result.canProceed).toBe(false);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
describe('canRemoveInstance', () => {
|
|
201
|
+
it('devrait retourner true si plus de 1 instance', () => {
|
|
202
|
+
const groupe = createMultipleGroupe({
|
|
203
|
+
instances: [createInstance(1), createInstance(2)]
|
|
204
|
+
});
|
|
205
|
+
const result = GroupeInstanceManager.canRemoveInstance(groupe, {});
|
|
206
|
+
expect(result.canProceed).toBe(true);
|
|
207
|
+
});
|
|
208
|
+
it('devrait retourner false si 1 seule instance', () => {
|
|
209
|
+
const groupe = createMultipleGroupe({
|
|
210
|
+
instances: [createInstance(1)]
|
|
211
|
+
});
|
|
212
|
+
const result = GroupeInstanceManager.canRemoveInstance(groupe, {});
|
|
213
|
+
expect(result.canProceed).toBe(false);
|
|
214
|
+
});
|
|
215
|
+
it('devrait retourner false si aucune instance', () => {
|
|
216
|
+
const groupe = createMultipleGroupe({
|
|
217
|
+
instances: []
|
|
218
|
+
});
|
|
219
|
+
const result = GroupeInstanceManager.canRemoveInstance(groupe, {});
|
|
220
|
+
expect(result.canProceed).toBe(false);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe('addInstance', () => {
|
|
224
|
+
it('devrait ajouter une instance et retourner success=true', () => {
|
|
225
|
+
const groupe = createMultipleGroupe({
|
|
226
|
+
instances: [createInstance(1)]
|
|
227
|
+
});
|
|
228
|
+
const responses = createControlResponse(3);
|
|
229
|
+
const result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
230
|
+
expect(result.success).toBe(true);
|
|
231
|
+
expect(result.instance).toBeDefined();
|
|
232
|
+
expect(result.instance.numeroInstance).toBe(2);
|
|
233
|
+
});
|
|
234
|
+
it('ne devrait PAS muter le groupe original (immutabilite)', () => {
|
|
235
|
+
const groupe = createMultipleGroupe({
|
|
236
|
+
instances: [createInstance(1)]
|
|
237
|
+
});
|
|
238
|
+
const originalLength = groupe.instances.length;
|
|
239
|
+
const responses = createControlResponse(3);
|
|
240
|
+
const result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
241
|
+
expect(result.success).toBe(true);
|
|
242
|
+
// Apres Fix 2a: le groupe original ne doit PAS avoir ete mute
|
|
243
|
+
expect(groupe.instances.length).toBe(originalLength);
|
|
244
|
+
// Le nouveau groupe doit etre retourne dans updatedGroupe
|
|
245
|
+
expect(result.updatedGroupe).toBeDefined();
|
|
246
|
+
expect(result.updatedGroupe.instances.length).toBe(originalLength + 1);
|
|
247
|
+
});
|
|
248
|
+
it('devrait refuser si deja au maximum', () => {
|
|
249
|
+
const groupe = createMultipleGroupe({
|
|
250
|
+
instances: [createInstance(1), createInstance(2)]
|
|
251
|
+
});
|
|
252
|
+
const responses = createControlResponse(2);
|
|
253
|
+
const result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
254
|
+
expect(result.success).toBe(false);
|
|
255
|
+
expect(result.error).toBeDefined();
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
describe('removeInstance', () => {
|
|
259
|
+
it('devrait supprimer une instance et retourner success=true', () => {
|
|
260
|
+
const groupe = createMultipleGroupe({
|
|
261
|
+
instances: [createInstance(1), createInstance(2)]
|
|
262
|
+
});
|
|
263
|
+
const responses = {
|
|
264
|
+
...createControlResponse(2),
|
|
265
|
+
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
266
|
+
'S1_01_2': createResponse('S1_01', 'Bob', 2),
|
|
267
|
+
};
|
|
268
|
+
const result = GroupeInstanceManager.removeInstance(groupe, 1, responses);
|
|
269
|
+
expect(result.success).toBe(true);
|
|
270
|
+
});
|
|
271
|
+
it('ne devrait PAS muter le groupe original ni les reponses (immutabilite)', () => {
|
|
272
|
+
const groupe = createMultipleGroupe({
|
|
273
|
+
instances: [createInstance(1), createInstance(2)]
|
|
274
|
+
});
|
|
275
|
+
const responses = {
|
|
276
|
+
...createControlResponse(2),
|
|
277
|
+
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
278
|
+
'S1_01_2': createResponse('S1_01', 'Bob', 2),
|
|
279
|
+
};
|
|
280
|
+
const originalGroupeInstancesLength = groupe.instances.length;
|
|
281
|
+
const originalResponsesKeys = Object.keys(responses).sort();
|
|
282
|
+
const result = GroupeInstanceManager.removeInstance(groupe, 1, responses);
|
|
283
|
+
expect(result.success).toBe(true);
|
|
284
|
+
// Apres Fix 2b: le groupe original ne doit PAS avoir ete mute
|
|
285
|
+
expect(groupe.instances.length).toBe(originalGroupeInstancesLength);
|
|
286
|
+
// Les reponses originales ne doivent PAS avoir ete mutees
|
|
287
|
+
expect(Object.keys(responses).sort()).toEqual(originalResponsesKeys);
|
|
288
|
+
// Les nouveaux objets doivent etre retournes
|
|
289
|
+
expect(result.updatedGroupe).toBeDefined();
|
|
290
|
+
expect(result.updatedResponses).toBeDefined();
|
|
291
|
+
});
|
|
292
|
+
it('devrait refuser si 1 seule instance', () => {
|
|
293
|
+
const groupe = createMultipleGroupe({
|
|
294
|
+
instances: [createInstance(1)]
|
|
295
|
+
});
|
|
296
|
+
const result = GroupeInstanceManager.removeInstance(groupe, 1, {});
|
|
297
|
+
expect(result.success).toBe(false);
|
|
298
|
+
});
|
|
299
|
+
it('devrait reordonner les instances apres suppression (2 supprime de [1,2,3] → [1,2])', () => {
|
|
300
|
+
const groupe = createMultipleGroupe({
|
|
301
|
+
instances: [createInstance(1), createInstance(2), createInstance(3)]
|
|
302
|
+
});
|
|
303
|
+
const responses = {
|
|
304
|
+
...createControlResponse(3),
|
|
305
|
+
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
306
|
+
'S1_01_2': createResponse('S1_01', 'Bob', 2),
|
|
307
|
+
'S1_01_3': createResponse('S1_01', 'Charlie', 3),
|
|
308
|
+
};
|
|
309
|
+
const result = GroupeInstanceManager.removeInstance(groupe, 2, responses);
|
|
310
|
+
expect(result.success).toBe(true);
|
|
311
|
+
// Apres Fix 2b+2c: verifier via updatedGroupe
|
|
312
|
+
const updatedGroupe = result.updatedGroupe;
|
|
313
|
+
if (updatedGroupe) {
|
|
314
|
+
expect(updatedGroupe.instances.length).toBe(2);
|
|
315
|
+
expect(updatedGroupe.instances[0].numeroInstance).toBe(1);
|
|
316
|
+
expect(updatedGroupe.instances[1].numeroInstance).toBe(2);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
it('devrait mettre a jour les cles de reponses apres reordonnancement', () => {
|
|
320
|
+
const groupe = createMultipleGroupe({
|
|
321
|
+
instances: [createInstance(1), createInstance(2), createInstance(3)]
|
|
322
|
+
});
|
|
323
|
+
const responses = {
|
|
324
|
+
...createControlResponse(3),
|
|
325
|
+
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
326
|
+
'S1_01_2': createResponse('S1_01', 'Bob', 2),
|
|
327
|
+
'S1_01_3': createResponse('S1_01', 'Charlie', 3),
|
|
328
|
+
};
|
|
329
|
+
const result = GroupeInstanceManager.removeInstance(groupe, 1, responses);
|
|
330
|
+
expect(result.success).toBe(true);
|
|
331
|
+
// Apres Fix 2b+2c: verifier via updatedResponses
|
|
332
|
+
const updatedResponses = result.updatedResponses;
|
|
333
|
+
if (updatedResponses) {
|
|
334
|
+
// Instance 2 (Bob) → instance 1, Instance 3 (Charlie) → instance 2
|
|
335
|
+
expect(updatedResponses['S1_01_1']?.valeur).toBe('Bob');
|
|
336
|
+
expect(updatedResponses['S1_01_2']?.valeur).toBe('Charlie');
|
|
337
|
+
expect(updatedResponses['S1_01_3']).toBeUndefined();
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
describe('canModifyControlVariable', () => {
|
|
342
|
+
it('devrait retourner true si newValue >= existingInstances', () => {
|
|
343
|
+
const groupe = createMultipleGroupe({
|
|
344
|
+
instances: [createInstance(1), createInstance(2)]
|
|
345
|
+
});
|
|
346
|
+
const result = GroupeInstanceManager.canModifyControlVariable('S0_23', 3, [groupe], {});
|
|
347
|
+
expect(result.canProceed).toBe(true);
|
|
348
|
+
});
|
|
349
|
+
it('devrait retourner true si newValue = existingInstances (egal)', () => {
|
|
350
|
+
const groupe = createMultipleGroupe({
|
|
351
|
+
instances: [createInstance(1), createInstance(2)]
|
|
352
|
+
});
|
|
353
|
+
const result = GroupeInstanceManager.canModifyControlVariable('S0_23', 2, [groupe], {});
|
|
354
|
+
expect(result.canProceed).toBe(true);
|
|
355
|
+
});
|
|
356
|
+
it('devrait retourner false si newValue < existingInstances', () => {
|
|
357
|
+
const groupe = createMultipleGroupe({
|
|
358
|
+
instances: [createInstance(1), createInstance(2), createInstance(3)]
|
|
359
|
+
});
|
|
360
|
+
const result = GroupeInstanceManager.canModifyControlVariable('S0_23', 2, [groupe], {});
|
|
361
|
+
expect(result.canProceed).toBe(false);
|
|
362
|
+
});
|
|
363
|
+
it('devrait retourner true si aucun groupe n\'utilise cette variable', () => {
|
|
364
|
+
const groupe = createMultipleGroupe({
|
|
365
|
+
codeVariable: 'OTHER_VAR',
|
|
366
|
+
instances: [createInstance(1), createInstance(2)]
|
|
367
|
+
});
|
|
368
|
+
const result = GroupeInstanceManager.canModifyControlVariable('S0_23', 1, [groupe], {});
|
|
369
|
+
expect(result.canProceed).toBe(true);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
describe('isInstanceComplete', () => {
|
|
373
|
+
it('devrait retourner true quand toutes les variables obligatoires sont remplies', () => {
|
|
374
|
+
const groupe = createMultipleGroupe({
|
|
375
|
+
variables: [
|
|
376
|
+
createVariable('S1_01', { estObligatoire: true }),
|
|
377
|
+
createVariable('S1_02', { estObligatoire: false })
|
|
378
|
+
]
|
|
379
|
+
});
|
|
380
|
+
const instance = createInstance(1, {
|
|
381
|
+
S1_01: createResponse('S1_01', 'Alice', 1)
|
|
382
|
+
});
|
|
383
|
+
expect(GroupeInstanceManager.isInstanceComplete(instance, groupe)).toBe(true);
|
|
384
|
+
});
|
|
385
|
+
it('devrait retourner false quand une variable obligatoire manque', () => {
|
|
386
|
+
const groupe = createMultipleGroupe({
|
|
387
|
+
variables: [
|
|
388
|
+
createVariable('S1_01', { estObligatoire: true }),
|
|
389
|
+
createVariable('S1_02', { estObligatoire: true })
|
|
390
|
+
]
|
|
391
|
+
});
|
|
392
|
+
const instance = createInstance(1, {
|
|
393
|
+
S1_01: createResponse('S1_01', 'Alice', 1)
|
|
394
|
+
});
|
|
395
|
+
expect(GroupeInstanceManager.isInstanceComplete(instance, groupe)).toBe(false);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
describe('scenarios integration', () => {
|
|
399
|
+
it('S0_23=2, creer 2 instances, supprimer 1, ajouter 1 → doit fonctionner', () => {
|
|
400
|
+
// Setup: S0_23=2, 2 instances
|
|
401
|
+
let groupe = createMultipleGroupe({
|
|
402
|
+
instances: [createInstance(1), createInstance(2)]
|
|
403
|
+
});
|
|
404
|
+
let responses = {
|
|
405
|
+
...createControlResponse(2),
|
|
406
|
+
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
407
|
+
'S1_01_2': createResponse('S1_01', 'Bob', 2),
|
|
408
|
+
};
|
|
409
|
+
// Supprimer instance 1
|
|
410
|
+
const removeResult = GroupeInstanceManager.removeInstance(groupe, 1, responses);
|
|
411
|
+
expect(removeResult.success).toBe(true);
|
|
412
|
+
// Utiliser les objets mis a jour si disponibles (apres Fix 2)
|
|
413
|
+
const updatedGroupe = removeResult.updatedGroupe || groupe;
|
|
414
|
+
const updatedResponses = removeResult.updatedResponses || responses;
|
|
415
|
+
// Ajouter une nouvelle instance
|
|
416
|
+
const addResult = GroupeInstanceManager.addInstance(updatedGroupe, updatedResponses);
|
|
417
|
+
expect(addResult.success).toBe(true);
|
|
418
|
+
});
|
|
419
|
+
it('S0_23=3, creer 3 instances, tenter d\'ajouter → doit bloquer', () => {
|
|
420
|
+
const groupe = createMultipleGroupe({
|
|
421
|
+
instances: [createInstance(1), createInstance(2), createInstance(3)]
|
|
422
|
+
});
|
|
423
|
+
const responses = createControlResponse(3);
|
|
424
|
+
const result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
425
|
+
expect(result.success).toBe(false);
|
|
426
|
+
});
|
|
427
|
+
it('cycle complet ajout/suppression/ajout avec immutabilite', () => {
|
|
428
|
+
// Debut: 1 instance, max 3
|
|
429
|
+
let groupe = createMultipleGroupe({
|
|
430
|
+
instances: [createInstance(1)]
|
|
431
|
+
});
|
|
432
|
+
let responses = createControlResponse(3);
|
|
433
|
+
// Ajouter instance 2
|
|
434
|
+
let result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
435
|
+
expect(result.success).toBe(true);
|
|
436
|
+
groupe = result.updatedGroupe || groupe;
|
|
437
|
+
// Ajouter instance 3
|
|
438
|
+
result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
439
|
+
expect(result.success).toBe(true);
|
|
440
|
+
groupe = result.updatedGroupe || groupe;
|
|
441
|
+
// Tenter d'ajouter instance 4 → refuse
|
|
442
|
+
result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
443
|
+
expect(result.success).toBe(false);
|
|
444
|
+
// Supprimer instance 2
|
|
445
|
+
const removeResult = GroupeInstanceManager.removeInstance(groupe, 2, responses);
|
|
446
|
+
expect(removeResult.success).toBe(true);
|
|
447
|
+
groupe = removeResult.updatedGroupe || groupe;
|
|
448
|
+
responses = removeResult.updatedResponses || responses;
|
|
449
|
+
// Ajouter a nouveau → doit fonctionner
|
|
450
|
+
result = GroupeInstanceManager.addInstance(groupe, responses);
|
|
451
|
+
expect(result.success).toBe(true);
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
});
|
|
@@ -15,6 +15,8 @@ export declare class GroupeInstanceManager {
|
|
|
15
15
|
static getMinInstances(groupe: GroupeFormulaire): number;
|
|
16
16
|
/**
|
|
17
17
|
* Compte le nombre d'instances existantes pour un groupe
|
|
18
|
+
* Source de vérité : groupe.instances.length
|
|
19
|
+
* Fallback par numeroMembre uniquement pour l'initialisation
|
|
18
20
|
*/
|
|
19
21
|
static getInstancesCount(groupe: GroupeFormulaire, responses: Record<string, EnqueteReponse>): number;
|
|
20
22
|
/**
|
|
@@ -42,18 +44,23 @@ export declare class GroupeInstanceManager {
|
|
|
42
44
|
*/
|
|
43
45
|
static canModifyControlVariable(variableCode: string, newValue: number, groupesMultiples: GroupeFormulaire[], responses: Record<string, EnqueteReponse>): ConstraintValidationResult;
|
|
44
46
|
/**
|
|
45
|
-
* Ajoute une nouvelle instance à un groupe
|
|
47
|
+
* Ajoute une nouvelle instance à un groupe (immutable)
|
|
48
|
+
* Retourne un nouveau groupe sans muter l'original
|
|
46
49
|
*/
|
|
47
50
|
static addInstance(groupe: GroupeFormulaire, responses: Record<string, EnqueteReponse>): {
|
|
48
51
|
success: boolean;
|
|
49
52
|
instance?: GroupeInstance;
|
|
53
|
+
updatedGroupe?: GroupeFormulaire;
|
|
50
54
|
error?: string;
|
|
51
55
|
};
|
|
52
56
|
/**
|
|
53
|
-
* Supprime une instance d'un groupe
|
|
57
|
+
* Supprime une instance d'un groupe (immutable)
|
|
58
|
+
* Retourne de nouveaux objets sans muter les originaux
|
|
54
59
|
*/
|
|
55
60
|
static removeInstance(groupe: GroupeFormulaire, instanceNumber: number, responses: Record<string, EnqueteReponse>): {
|
|
56
61
|
success: boolean;
|
|
62
|
+
updatedGroupe?: GroupeFormulaire;
|
|
63
|
+
updatedResponses?: Record<string, EnqueteReponse>;
|
|
57
64
|
error?: string;
|
|
58
65
|
};
|
|
59
66
|
/**
|
|
@@ -81,8 +88,12 @@ export declare class GroupeInstanceManager {
|
|
|
81
88
|
progressPercentage: number;
|
|
82
89
|
};
|
|
83
90
|
/**
|
|
84
|
-
* Réorganise les numéros d'instances après suppression
|
|
91
|
+
* Réorganise les numéros d'instances après suppression (immutable)
|
|
92
|
+
* Retourne de nouveaux objets sans muter les originaux
|
|
85
93
|
*/
|
|
86
|
-
static reorderInstances(
|
|
94
|
+
static reorderInstances(instances: GroupeInstance[], responses: Record<string, EnqueteReponse>, groupe: GroupeFormulaire): {
|
|
95
|
+
reorderedInstances: GroupeInstance[];
|
|
96
|
+
reorderedResponses: Record<string, EnqueteReponse>;
|
|
97
|
+
};
|
|
87
98
|
}
|
|
88
99
|
//# sourceMappingURL=groupeInstanceManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groupeInstanceManager.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/groupeInstanceManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,cAAc,EAEd,0BAA0B,EAE3B,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,qBAAqB;IAEhC;;;OAGG;IACH,MAAM,CAAC,eAAe,CACpB,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GACxC,MAAM;
|
|
1
|
+
{"version":3,"file":"groupeInstanceManager.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/groupeInstanceManager.ts"],"names":[],"mappings":"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"}
|