@inseefr/lunatic 3.5.3 → 3.5.5

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.
Files changed (141) hide show
  1. package/components/Input/Input.spec.js +6 -0
  2. package/components/Input/Input.spec.js.map +1 -1
  3. package/components/InputNumber/InputNumber.spec.js +6 -0
  4. package/components/InputNumber/InputNumber.spec.js.map +1 -1
  5. package/components/InputNumber/InputNumberThousand.js +1 -1
  6. package/components/InputNumber/InputNumberThousand.js.map +1 -1
  7. package/components/Textarea/Textarea.js +1 -1
  8. package/components/Textarea/Textarea.js.map +1 -1
  9. package/components/Textarea/Textarea.spec.js +7 -0
  10. package/components/Textarea/Textarea.spec.js.map +1 -1
  11. package/esm/components/Input/Input.spec.js +6 -0
  12. package/esm/components/Input/Input.spec.js.map +1 -1
  13. package/esm/components/InputNumber/InputNumber.spec.js +6 -0
  14. package/esm/components/InputNumber/InputNumber.spec.js.map +1 -1
  15. package/esm/components/InputNumber/InputNumberThousand.js +1 -1
  16. package/esm/components/InputNumber/InputNumberThousand.js.map +1 -1
  17. package/esm/components/Textarea/Textarea.js +1 -1
  18. package/esm/components/Textarea/Textarea.js.map +1 -1
  19. package/esm/components/Textarea/Textarea.spec.js +7 -0
  20. package/esm/components/Textarea/Textarea.spec.js.map +1 -1
  21. package/esm/hooks/use-track-changes.js +2 -1
  22. package/esm/hooks/use-track-changes.js.map +1 -1
  23. package/esm/stories/overview/sourceWithHierarchy.json +32 -32
  24. package/esm/type.source.d.ts +1 -1
  25. package/esm/use-lunatic/actions.d.ts +2 -0
  26. package/esm/use-lunatic/actions.js.map +1 -1
  27. package/esm/use-lunatic/commons/fill-components/fill-component.spec.js +1 -1
  28. package/esm/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -1
  29. package/esm/use-lunatic/commons/fill-components/fill-components.js +1 -1
  30. package/esm/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
  31. package/esm/use-lunatic/commons/variables/behaviours/resizing-behaviour.js +11 -7
  32. package/esm/use-lunatic/commons/variables/behaviours/resizing-behaviour.js.map +1 -1
  33. package/esm/use-lunatic/commons/variables/get-questionnaire-data.js +1 -0
  34. package/esm/use-lunatic/commons/variables/get-questionnaire-data.js.map +1 -1
  35. package/esm/use-lunatic/commons/variables/lunatic-variables-store.d.ts +18 -3
  36. package/esm/use-lunatic/commons/variables/lunatic-variables-store.js +49 -5
  37. package/esm/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
  38. package/esm/use-lunatic/commons/variables/lunatic-variables-store.spec.js +44 -0
  39. package/esm/use-lunatic/commons/variables/lunatic-variables-store.spec.js.map +1 -1
  40. package/esm/use-lunatic/reducer/reducer.js +9 -0
  41. package/esm/use-lunatic/reducer/reducer.js.map +1 -1
  42. package/esm/use-lunatic/reducer/reducerInitializer.js +1 -1
  43. package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  44. package/esm/use-lunatic/type.d.ts +3 -0
  45. package/hooks/use-track-changes.js +2 -1
  46. package/hooks/use-track-changes.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/components/Input/Input.spec.tsx +9 -0
  49. package/src/components/InputNumber/InputNumber.spec.tsx +9 -0
  50. package/src/components/InputNumber/InputNumberThousand.tsx +1 -0
  51. package/src/components/InputNumber/__snapshots__/InputNumber.spec.tsx.snap +2 -0
  52. package/src/components/Textarea/Textarea.spec.tsx +10 -0
  53. package/src/components/Textarea/Textarea.tsx +1 -0
  54. package/src/hooks/use-track-changes.ts +2 -1
  55. package/src/stories/behaviour/cleaning/loop.json +4 -4
  56. package/src/stories/behaviour/cleaning/source-loop.json +1 -1
  57. package/src/stories/behaviour/cleaning/source.json +2 -2
  58. package/src/stories/behaviour/controls/boucles-n.json +2 -2
  59. package/src/stories/behaviour/controls/simple-numeric.json +19 -19
  60. package/src/stories/behaviour/controls/simple.json +7 -7
  61. package/src/stories/behaviour/filter/source.json +3 -3
  62. package/src/stories/behaviour/filter/sourceLoop.json +3 -3
  63. package/src/stories/behaviour/missing/source.json +6 -6
  64. package/src/stories/behaviour/others/V2_DeclarationsSimples.json +14 -14
  65. package/src/stories/behaviour/others/V2_MinMaxSum_Boucles.json +5 -5
  66. package/src/stories/behaviour/others/V2_QuestSimple_Boucles.json +28 -28
  67. package/src/stories/behaviour/others/V2_TCMRallyeGames.json +24 -24
  68. package/src/stories/behaviour/others/test-dylan.json +5 -5
  69. package/src/stories/behaviour/resizing/source-resizing-cleaning.json +2 -2
  70. package/src/stories/behaviour/resizing/source.json +5 -5
  71. package/src/stories/checkbox-boolean/source.json +1 -1
  72. package/src/stories/checkbox-one/source.json +1 -1
  73. package/src/stories/checkbox-one/sourceDetail.json +1 -1
  74. package/src/stories/date-picker/source.json +1 -1
  75. package/src/stories/disabled/source.json +5 -5
  76. package/src/stories/dropdown/source.json +2 -2
  77. package/src/stories/duration/mois.json +1 -1
  78. package/src/stories/duration/time.json +1 -1
  79. package/src/stories/input-number/source-big-number.json +1 -1
  80. package/src/stories/input-number/source-euro.json +2 -2
  81. package/src/stories/overview/sourceLoop.json +12 -12
  82. package/src/stories/overview/sourceWithHierarchy.json +32 -32
  83. package/src/stories/question/source.json +2 -2
  84. package/src/stories/questionnaires/logement/source-sequence.json +216 -216
  85. package/src/stories/questionnaires/logement/source-sum.json +189 -189
  86. package/src/stories/questionnaires/logement/source.json +216 -216
  87. package/src/stories/questionnaires/recensement/source.json +85 -85
  88. package/src/stories/questionnaires/rp/source.json +8 -8
  89. package/src/stories/questionnaires/simpsons/source.json +34 -34
  90. package/src/stories/radio/source.json +1 -1
  91. package/src/stories/radio/sourceDetail.json +1 -1
  92. package/src/stories/radio/sourceHorizontal.json +1 -1
  93. package/src/stories/roundabout/source.json +3 -3
  94. package/src/stories/suggester/source-arbitrary-response.json +2 -2
  95. package/src/stories/suggester/source-error.json +2 -2
  96. package/src/stories/suggester/source-multiline.json +2 -2
  97. package/src/stories/suggester/source-option-responses.json +2 -2
  98. package/src/stories/suggester/source.json +5 -5
  99. package/src/stories/summary/source.json +4 -4
  100. package/src/stories/switch/data-forced.json +2 -2
  101. package/src/stories/switch/source.json +2 -2
  102. package/src/stories/table/source-colspan.json +1 -1
  103. package/src/stories/table/source.json +1 -1
  104. package/src/stories/table/table-dynamique.json +1 -1
  105. package/src/stories/text/source-roster.json +1 -1
  106. package/src/stories/text/source-table.json +1 -1
  107. package/src/type.source.ts +1 -1
  108. package/src/use-lunatic/actions.ts +2 -0
  109. package/src/use-lunatic/commons/fill-components/fill-component.spec.ts +1 -1
  110. package/src/use-lunatic/commons/fill-components/fill-components.ts +1 -1
  111. package/src/use-lunatic/commons/variables/behaviours/resizing-behaviour.ts +14 -6
  112. package/src/use-lunatic/commons/variables/get-questionnaire-data.ts +1 -0
  113. package/src/use-lunatic/commons/variables/lunatic-variables-store.spec.ts +49 -0
  114. package/src/use-lunatic/commons/variables/lunatic-variables-store.ts +63 -6
  115. package/src/use-lunatic/reducer/reducer.ts +11 -0
  116. package/src/use-lunatic/reducer/reducerInitializer.tsx +2 -1
  117. package/src/use-lunatic/type.ts +3 -0
  118. package/src/use-lunatic/use-lunatic.test.ts +40 -1
  119. package/stories/overview/sourceWithHierarchy.json +32 -32
  120. package/tsconfig.build.tsbuildinfo +1 -1
  121. package/type.source.d.ts +1 -1
  122. package/use-lunatic/actions.d.ts +2 -0
  123. package/use-lunatic/actions.js.map +1 -1
  124. package/use-lunatic/commons/fill-components/fill-component.spec.js +1 -1
  125. package/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -1
  126. package/use-lunatic/commons/fill-components/fill-components.js +1 -1
  127. package/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
  128. package/use-lunatic/commons/variables/behaviours/resizing-behaviour.js +11 -7
  129. package/use-lunatic/commons/variables/behaviours/resizing-behaviour.js.map +1 -1
  130. package/use-lunatic/commons/variables/get-questionnaire-data.js +1 -0
  131. package/use-lunatic/commons/variables/get-questionnaire-data.js.map +1 -1
  132. package/use-lunatic/commons/variables/lunatic-variables-store.d.ts +18 -3
  133. package/use-lunatic/commons/variables/lunatic-variables-store.js +49 -5
  134. package/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
  135. package/use-lunatic/commons/variables/lunatic-variables-store.spec.js +44 -0
  136. package/use-lunatic/commons/variables/lunatic-variables-store.spec.js.map +1 -1
  137. package/use-lunatic/reducer/reducer.js +9 -0
  138. package/use-lunatic/reducer/reducer.js.map +1 -1
  139. package/use-lunatic/reducer/reducerInitializer.js +1 -1
  140. package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  141. package/use-lunatic/type.d.ts +3 -0
@@ -14,6 +14,8 @@ export type ActionHandleChanges = {
14
14
  name: string;
15
15
  value: unknown;
16
16
  iteration?: number[];
17
+ /** Force a vector when an iteration is set and the value was a scalar **/
18
+ ignoreIterationOnScalar?: boolean;
17
19
  [extra: string]: unknown;
18
20
  }[];
19
21
  };
@@ -38,7 +38,7 @@ describe('fillComponents', () => {
38
38
  type: 'VTL|MD',
39
39
  value: '"Input label"',
40
40
  },
41
- mandatory: true,
41
+ isMandatory: true,
42
42
  maxLength: 15,
43
43
  },
44
44
  ];
@@ -49,7 +49,7 @@ export const fillComponent = (
49
49
  goNextPage: state.goNextPage,
50
50
  goPreviousPage: state.goPreviousPage,
51
51
  iteration: state.pager.iteration,
52
- required: 'mandatory' in component ? component.mandatory : false,
52
+ required: 'isMandatory' in component ? component.isMandatory : false,
53
53
  value: value,
54
54
  missingResponse: getMissingResponseProp(component, state),
55
55
  management: state.management,
@@ -41,12 +41,20 @@ export function resizingBehaviour(
41
41
 
42
42
  const newSize = forceInt(store.run(resizingInfo.size));
43
43
  for (const variableName of resizingInfo.variables) {
44
- const value = store.get(variableName);
45
- if (!Array.isArray(value) || value.length !== newSize) {
46
- store.set(variableName, resizeArrayVariable(value, newSize, null), {
44
+ // Since data can change after the resize, we need to pass a callback that will use the last value of the variable for the resize
45
+ store.enqueueSet(
46
+ variableName,
47
+ () => {
48
+ const value = store.get(variableName);
49
+ if (!Array.isArray(value) || value.length !== newSize) {
50
+ return resizeArrayVariable(value, newSize, null);
51
+ }
52
+ return value;
53
+ },
54
+ {
47
55
  cause: 'resizing',
48
- });
49
- }
56
+ }
57
+ );
50
58
  }
51
59
  });
52
60
  }
@@ -81,6 +89,6 @@ function resizePairwise(
81
89
  xSize,
82
90
  new Array(ySize).fill(null)
83
91
  );
84
- store.set(variable, resizedValue);
92
+ store.enqueueSet(variable, resizedValue);
85
93
  });
86
94
  }
@@ -7,6 +7,7 @@ export function getQuestionnaireData(
7
7
  withCalculated: boolean = false,
8
8
  variableNames?: string[]
9
9
  ): LunaticData {
10
+ store.commit();
10
11
  const result = {
11
12
  EXTERNAL: {} as Record<string, unknown>,
12
13
  CALCULATED: {} as Record<string, unknown>,
@@ -115,6 +115,27 @@ describe('lunatic-variables-store', () => {
115
115
  expect(variables.get('AGES_PLUS_NBHAB')).toEqual([4, 5, 6]);
116
116
  });
117
117
 
118
+ it('should handle transaction mode correctly', () => {
119
+ variables.set('FIRSTNAME', 'John');
120
+ expect(variables.get('FIRSTNAME')).toEqual('John');
121
+ variables.enqueueSet('FIRSTNAME', 'Jane');
122
+ expect(variables.get('FIRSTNAME')).toEqual('John');
123
+ variables.commit();
124
+ expect(variables.get('FIRSTNAME')).toEqual('Jane');
125
+ });
126
+
127
+ it('should ignore iteration when updating a scalar value', () => {
128
+ variables.set('FIRSTNAME', 'John'); // Start with a scalar value
129
+ expect(variables.get('FIRSTNAME')).toEqual('John');
130
+ variables.set('FIRSTNAME', 'Jane', {
131
+ iteration: [1],
132
+ ignoreIterationOnScalar: true,
133
+ });
134
+ expect(variables.get('FIRSTNAME')).toEqual('Jane');
135
+ variables.set('FIRSTNAME', 'Marc', { iteration: [1] });
136
+ expect(variables.get('FIRSTNAME')).toEqual([null, 'Marc']);
137
+ });
138
+
118
139
  describe('event listener', () => {
119
140
  it('should trigger onChange', () => {
120
141
  variables.set('FIRSTNAME', 'John');
@@ -273,6 +294,10 @@ describe('lunatic-variables-store', () => {
273
294
  });
274
295
 
275
296
  describe('resizing', () => {
297
+ beforeEach(() => {
298
+ variables.autoCommit = true;
299
+ });
300
+
276
301
  it('should resize variables', () => {
277
302
  variables.set('PRENOM', ['John', 'Jane']);
278
303
  variables.set('NOM', ['Doe']);
@@ -367,6 +392,10 @@ describe('lunatic-variables-store', () => {
367
392
  });
368
393
 
369
394
  describe('cleaning', () => {
395
+ beforeEach(() => {
396
+ variables.autoCommit = true;
397
+ });
398
+
370
399
  it('should clean variables', () => {
371
400
  variables.set('PRENOM', 'John');
372
401
  variables.set('NOM', 'Doe');
@@ -568,6 +597,25 @@ describe('lunatic-variables-store', () => {
568
597
  });
569
598
  });
570
599
 
600
+ describe('commit', () => {
601
+ it('should handle data change before commit', () => {
602
+ variables.set('PRENOM', []);
603
+ variables.set('NOM', []);
604
+ resizingBehaviour(variables, {
605
+ PRENOM: {
606
+ size: 'count(PRENOM)',
607
+ variables: ['NOM'],
608
+ },
609
+ });
610
+ variables.set('PRENOM', ['John', 'Jane', 'Marc']);
611
+ variables.set('NOM', ['Doe', 'Doe2', 'Doe3']);
612
+ variables.set('PRENOM', ['John', 'Jane']); // Should trigger a delayed resize
613
+ variables.set('NOM', 'New', { iteration: [1] }); // But we change a value inside the resized variable
614
+ variables.commit();
615
+ expect(variables.get('NOM') as string[][]).toEqual(['Doe', 'New']);
616
+ });
617
+ });
618
+
571
619
  describe('makeFromSource', () => {
572
620
  it('should handle initial data correctly', () => {
573
621
  const store = LunaticVariablesStore.makeFromSource(
@@ -606,6 +654,7 @@ describe('lunatic-variables-store', () => {
606
654
  );
607
655
  expect(store.get('PRENOM')).toEqual('Jane');
608
656
  store.set('NOM', 'Doe');
657
+ store.commit();
609
658
  expect(store.get('PRENOM')).toEqual('John');
610
659
  });
611
660
  it('should enable cleaning when disableCleaning = false', () => {
@@ -35,6 +35,8 @@ export type EventArgs = {
35
35
  iteration?: IterationLevel | undefined;
36
36
  /** What triggered this change. */
37
37
  cause?: 'resizing' | 'cleaning';
38
+ /** Force a vector when an iteration is set and the value was a scalar **/
39
+ ignoreIterationOnScalar?: boolean;
38
40
  /** Extra sent when setting the variable. */
39
41
  [extra: string]: unknown;
40
42
  };
@@ -46,6 +48,8 @@ export type LunaticVariablesStoreEvent<T extends keyof EventArgs> = {
46
48
  export class LunaticVariablesStore {
47
49
  private dictionary = new Map<string, LunaticVariable>();
48
50
  private eventTarget = new EventTarget();
51
+ private queue = new Map<string, () => void>();
52
+ public autoCommit = false; // Commit change instantly (used in tests)
49
53
 
50
54
  constructor() {
51
55
  interpretCount = 0;
@@ -55,12 +59,18 @@ export class LunaticVariablesStore {
55
59
  source: LunaticSource,
56
60
  data: LunaticData,
57
61
  changeHandler: RefObject<LunaticOptions['onVariableChange']>,
58
- disableCleaning?: boolean
62
+ // Disable cleaning
63
+ disableCleaning?: boolean,
64
+ // Do not delay resizing / cleaning
65
+ autoCommit?: boolean
59
66
  ) {
60
67
  const store = new LunaticVariablesStore();
61
68
  if (!source.variables) {
62
69
  return store;
63
70
  }
71
+ if (autoCommit) {
72
+ store.autoCommit = autoCommit;
73
+ }
64
74
  // Source data (picked from "variables" in the source.json)s
65
75
  const sourceValues: Record<string, unknown> = {};
66
76
  // Starting data for the form (merged with data.json or injected data)
@@ -120,13 +130,50 @@ export class LunaticVariablesStore {
120
130
  return this.dictionary.get(name)!.getValue(iteration) as T;
121
131
  }
122
132
 
133
+ /**
134
+ * Transactional setter that will change data only when `commit()` is called
135
+ */
136
+ public enqueueSet(
137
+ name: string,
138
+ value: unknown,
139
+ args: Pick<EventArgs['change'], 'iteration' | 'cause'> = {}
140
+ ) {
141
+ if (this.autoCommit) {
142
+ this.set(name, typeof value === 'function' ? value() : value, args);
143
+ return;
144
+ }
145
+ this.queue.set(name, () => {
146
+ // A function can be enqueued, we need to evaluate it to retrieve the value to set
147
+ // This is used for the resizing, where we want to resize the last version of the variable
148
+ if (typeof value === 'function') {
149
+ value = value();
150
+ }
151
+ this.set(name, value, args);
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Commit all changes in the queue
157
+ */
158
+ public commit() {
159
+ const autoCommitValue = this.autoCommit;
160
+ // Since we can have nested operation, we prevent delayed set while commiting
161
+ this.autoCommit = true;
162
+ Array.from(this.queue.values()).forEach((cb) => cb());
163
+ this.autoCommit = autoCommitValue;
164
+ this.queue.clear();
165
+ }
166
+
123
167
  /**
124
168
  * Set variable value
125
169
  */
126
170
  public set(
127
171
  name: string,
128
172
  value: unknown,
129
- args: Pick<EventArgs['change'], 'iteration' | 'cause'> = {}
173
+ args: Pick<
174
+ EventArgs['change'],
175
+ 'iteration' | 'cause' | 'ignoreIterationOnScalar'
176
+ > = {}
130
177
  ): LunaticVariable {
131
178
  if (!this.dictionary.has(name)) {
132
179
  this.dictionary.set(
@@ -146,7 +193,7 @@ export class LunaticVariablesStore {
146
193
  );
147
194
  }
148
195
  const variable = this.dictionary.get(name)!;
149
- if (variable.setValue(value, args.iteration)) {
196
+ if (variable.setValue(value, args)) {
150
197
  this.eventTarget.dispatchEvent(
151
198
  new CustomEvent('change', {
152
199
  detail: {
@@ -348,7 +395,9 @@ class LunaticVariable {
348
395
  // this.calculatedCount++;
349
396
  // Remember the value
350
397
  try {
351
- this.setValue(interpretVTL(this.expression, bindings), iteration);
398
+ this.setValue(interpretVTL(this.expression, bindings), {
399
+ iteration: iteration,
400
+ });
352
401
  } catch {
353
402
  throw new VTLInterpretationError(this.expression!, bindings);
354
403
  }
@@ -359,7 +408,11 @@ class LunaticVariable {
359
408
  /**
360
409
  * Set the value and returns true if the variable is touched
361
410
  */
362
- setValue(value: unknown, iteration?: IterationLevel): boolean {
411
+ setValue(
412
+ value: unknown,
413
+ opts: { iteration?: IterationLevel; ignoreIterationOnScalar?: boolean }
414
+ ): boolean {
415
+ const { iteration, ignoreIterationOnScalar } = opts;
363
416
  if (value === this.getSavedValue(iteration)) {
364
417
  return false;
365
418
  }
@@ -369,6 +422,10 @@ class LunaticVariable {
369
422
  }
370
423
  // We want to save a value at a specific iteration, but the value is not an array yet
371
424
  if (iteration !== undefined && !Array.isArray(this.value)) {
425
+ // Ignore the iteration since the value is not an array
426
+ if (ignoreIterationOnScalar) {
427
+ return this.setValue(value, {});
428
+ }
372
429
  this.value = [];
373
430
  }
374
431
  this.value = !Array.isArray(iteration)
@@ -403,7 +460,7 @@ class LunaticVariable {
403
460
  // Update every item of the array and look if we changed one item
404
461
  const oneValueChanged =
405
462
  times(Math.max(oldSize, newSize), (k) =>
406
- this.setValue(value[k], [k])
463
+ this.setValue(value[k], { iteration: [k] })
407
464
  ).find((v) => v) !== undefined;
408
465
  // New array is smaller, shorten the array
409
466
  if (oldSize > newSize && Array.isArray(this.value)) {
@@ -5,10 +5,21 @@ import { reduceHandleChanges } from './reduce-handle-changes';
5
5
  import { reduceGoPreviousPage } from './reduce-go-previous-page';
6
6
  import { reduceGoToPage } from './reduce-go-to-page';
7
7
 
8
+ // Actions that trigger a change in the store
9
+ const commitActions: ActionKind[] = [
10
+ ActionKind.GO_PREVIOUS_PAGE,
11
+ ActionKind.GO_NEXT_PAGE,
12
+ ActionKind.GO_TO_PAGE,
13
+ ];
14
+
8
15
  export function reducer(
9
16
  state: LunaticReducerState,
10
17
  action: Action
11
18
  ): LunaticReducerState {
19
+ if (commitActions.includes(action.type)) {
20
+ state.variables.commit();
21
+ }
22
+
12
23
  switch (action.type) {
13
24
  case ActionKind.GO_PREVIOUS_PAGE:
14
25
  return reduceGoPreviousPage(state);
@@ -67,7 +67,8 @@ export function reducerInitializer({
67
67
  source,
68
68
  data,
69
69
  onVariableChange,
70
- disableFilters
70
+ disableFilters,
71
+ source.pagination !== 'question'
71
72
  );
72
73
  const pages = checkLoops(createMapPages(source));
73
74
 
@@ -235,6 +235,8 @@ export type LunaticOptions = {
235
235
  trackChanges?: boolean;
236
236
  logger?: LunaticLogger;
237
237
  componentsOptions?: { detailAlwaysDisplayed?: boolean };
238
+ /** Commit variable change automatically for resizing / cleaning (used for testing) **/
239
+ autoCommit?: boolean;
238
240
  };
239
241
 
240
242
  /**
@@ -364,5 +366,6 @@ export type LunaticChangesHandler = (
364
366
  name: string;
365
367
  value: any;
366
368
  iteration?: number[];
369
+ ignoreIterationOnScalar?: boolean;
367
370
  }[]
368
371
  ) => void;
@@ -59,6 +59,45 @@ describe('use-lunatic()', () => {
59
59
  expect(components[0].id).toBe('kiq5xw5p');
60
60
  });
61
61
 
62
+ describe('handleChange()', () => {
63
+ it('should change variable value', () => {
64
+ const { result } = renderHook(() => useLunatic(...defaultParams));
65
+ act(() => {
66
+ result.current.handleChanges([
67
+ {
68
+ name: 'COMMENT',
69
+ value: 'Mon commentaire',
70
+ },
71
+ ]);
72
+ });
73
+ act(() => {
74
+ expect(
75
+ result.current.getData(false, ['COMMENT']).COLLECTED!.COMMENT
76
+ .COLLECTED
77
+ ).toBe('Mon commentaire');
78
+ });
79
+ });
80
+ it('should ignore iteration for scalar value', () => {
81
+ const { result } = renderHook(() => useLunatic(...defaultParams));
82
+ act(() => {
83
+ result.current.handleChanges([
84
+ {
85
+ name: 'COMMENT',
86
+ value: 'Mon commentaire 2',
87
+ iteration: [1],
88
+ ignoreIterationOnScalar: true,
89
+ },
90
+ ]);
91
+ });
92
+ act(() => {
93
+ expect(
94
+ result.current.getData(false, ['COMMENT']).COLLECTED!.COMMENT
95
+ .COLLECTED
96
+ ).toBe('Mon commentaire 2');
97
+ });
98
+ });
99
+ });
100
+
62
101
  describe('Provider', () => {
63
102
  it('should not generate a new Provider every render', () => {
64
103
  const { result } = renderHook(() => {
@@ -230,7 +269,7 @@ describe('use-lunatic()', () => {
230
269
  describe('cleaning', () => {
231
270
  it('should handle cleaning in a loop', () => {
232
271
  const { result } = renderHook(() =>
233
- useLunatic(sourceCleaningLoop as any, undefined, {})
272
+ useLunatic(sourceCleaningLoop as any, undefined)
234
273
  );
235
274
  act(() => {
236
275
  result.current.handleChanges([
@@ -38,7 +38,7 @@
38
38
  {
39
39
  "id": "j6p3dkx6",
40
40
  "componentType": "Textarea",
41
- "mandatory": true,
41
+ "isMandatory": true,
42
42
  "page": "2",
43
43
  "maxLength": 500,
44
44
  "label": {
@@ -60,7 +60,7 @@
60
60
  {
61
61
  "id": "j6p0np9q",
62
62
  "componentType": "CheckboxBoolean",
63
- "mandatory": false,
63
+ "isMandatory": false,
64
64
  "page": "3",
65
65
  "label": {
66
66
  "value": "\"➡ \" || \"If you agree to answer this questionnaire, please check the box\"",
@@ -139,7 +139,7 @@
139
139
  {
140
140
  "id": "j3343qhx",
141
141
  "componentType": "Input",
142
- "mandatory": false,
142
+ "isMandatory": false,
143
143
  "page": "4",
144
144
  "maxLength": 30,
145
145
  "label": {
@@ -173,7 +173,7 @@
173
173
  {
174
174
  "id": "j6q9h8tj",
175
175
  "componentType": "InputNumber",
176
- "mandatory": true,
176
+ "isMandatory": true,
177
177
  "page": "5",
178
178
  "min": 0,
179
179
  "max": 99,
@@ -209,7 +209,7 @@
209
209
  {
210
210
  "id": "kiq71eoi",
211
211
  "componentType": "Datepicker",
212
- "mandatory": false,
212
+ "isMandatory": false,
213
213
  "page": "6",
214
214
  "min": "1900-01-01",
215
215
  "max": "format-date(current-date(),'[Y0001]-[M01]-[D01]')",
@@ -256,7 +256,7 @@
256
256
  {
257
257
  "id": "k5nvty2o",
258
258
  "componentType": "Datepicker",
259
- "mandatory": false,
259
+ "isMandatory": false,
260
260
  "page": "7",
261
261
  "min": "1980-05",
262
262
  "label": {
@@ -302,7 +302,7 @@
302
302
  {
303
303
  "id": "k5nw1fir",
304
304
  "componentType": "Datepicker",
305
- "mandatory": false,
305
+ "isMandatory": false,
306
306
  "page": "8",
307
307
  "min": "1900",
308
308
  "max": "year-from-date(current-date())",
@@ -349,7 +349,7 @@
349
349
  {
350
350
  "id": "k5nw0w05",
351
351
  "componentType": "InputNumber",
352
- "mandatory": false,
352
+ "isMandatory": false,
353
353
  "page": "9",
354
354
  "min": 0,
355
355
  "max": 70,
@@ -386,7 +386,7 @@
386
386
  {
387
387
  "id": "k5nvu98z",
388
388
  "componentType": "InputNumber",
389
- "mandatory": false,
389
+ "isMandatory": false,
390
390
  "page": "10",
391
391
  "min": 0,
392
392
  "max": 366,
@@ -423,7 +423,7 @@
423
423
  {
424
424
  "id": "k5nw8ei1",
425
425
  "componentType": "InputNumber",
426
- "mandatory": false,
426
+ "isMandatory": false,
427
427
  "page": "11",
428
428
  "min": 0,
429
429
  "max": 12,
@@ -460,7 +460,7 @@
460
460
  {
461
461
  "id": "k5nw9dk4",
462
462
  "componentType": "InputNumber",
463
- "mandatory": false,
463
+ "isMandatory": false,
464
464
  "page": "12",
465
465
  "min": 0,
466
466
  "max": 100,
@@ -497,7 +497,7 @@
497
497
  {
498
498
  "id": "j6z06z1e",
499
499
  "componentType": "InputNumber",
500
- "mandatory": false,
500
+ "isMandatory": false,
501
501
  "page": "13",
502
502
  "min": 0,
503
503
  "max": 99,
@@ -566,7 +566,7 @@
566
566
  {
567
567
  "id": "j3343clt",
568
568
  "componentType": "Radio",
569
- "mandatory": true,
569
+ "isMandatory": true,
570
570
  "page": "15",
571
571
  "label": {
572
572
  "value": "\"➡ \" || \"In which city do the Simpsons reside?\"",
@@ -616,7 +616,7 @@
616
616
  {
617
617
  "id": "j6qdfhvw",
618
618
  "componentType": "CheckboxOne",
619
- "mandatory": false,
619
+ "isMandatory": false,
620
620
  "page": "16",
621
621
  "label": {
622
622
  "value": "\"➡ \" || \"Who is the Simpsons city mayor?\"",
@@ -670,7 +670,7 @@
670
670
  {
671
671
  "id": "j4nw5cqz",
672
672
  "componentType": "Dropdown",
673
- "mandatory": false,
673
+ "isMandatory": false,
674
674
  "page": "17",
675
675
  "label": {
676
676
  "value": "\"➡ \" || \"In which state do The Simpsons reside?\"",
@@ -811,7 +811,7 @@
811
811
  {
812
812
  "id": "j6p29i81",
813
813
  "componentType": "Table",
814
- "mandatory": false,
814
+ "isMandatory": false,
815
815
  "page": "20",
816
816
  "label": {
817
817
  "value": "\"➡ \" || \"Does Jay like the following ice cream flavours?\"",
@@ -927,7 +927,7 @@
927
927
  {
928
928
  "id": "j6qefnga",
929
929
  "componentType": "Table",
930
- "mandatory": false,
930
+ "isMandatory": false,
931
931
  "page": "21",
932
932
  "label": {
933
933
  "value": "\"➡ \" || \"Which character works in the nuclear power plant?\"",
@@ -1038,7 +1038,7 @@
1038
1038
  {
1039
1039
  "id": "j6yzoc6g",
1040
1040
  "componentType": "Table",
1041
- "mandatory": false,
1041
+ "isMandatory": false,
1042
1042
  "page": "22",
1043
1043
  "label": {
1044
1044
  "value": "\"➡ \" || \"In which city each character was born?\"",
@@ -1291,7 +1291,7 @@
1291
1291
  {
1292
1292
  "id": "j4nwc63q",
1293
1293
  "componentType": "Table",
1294
- "mandatory": false,
1294
+ "isMandatory": false,
1295
1295
  "page": "24",
1296
1296
  "label": {
1297
1297
  "value": "\"➡ \" || \"Please, specify the percentage of Jay’s expenses in the Kwik-E-Mart for each product?\"",
@@ -1473,7 +1473,7 @@
1473
1473
  {
1474
1474
  "id": "k9cg2q5t",
1475
1475
  "componentType": "Table",
1476
- "mandatory": false,
1476
+ "isMandatory": false,
1477
1477
  "page": "25",
1478
1478
  "label": {
1479
1479
  "value": "\"➡ \" || \"Please specify if Jay has bought each product in his last food shopping\"",
@@ -1776,7 +1776,7 @@
1776
1776
  {
1777
1777
  "id": "kbkjvgel",
1778
1778
  "componentType": "Table",
1779
- "mandatory": false,
1779
+ "isMandatory": false,
1780
1780
  "page": "26",
1781
1781
  "label": {
1782
1782
  "value": "\"➡ \" || \"Who did these clownings and tell us what you remember?\"",
@@ -2008,7 +2008,7 @@
2008
2008
  {
2009
2009
  "id": "j6p2lwuj",
2010
2010
  "componentType": "Table",
2011
- "mandatory": false,
2011
+ "isMandatory": false,
2012
2012
  "page": "27",
2013
2013
  "label": {
2014
2014
  "value": "\"➡ \" || \"Which of the following means of transport were used by the hero and in which country?\"",
@@ -2271,7 +2271,7 @@
2271
2271
  {
2272
2272
  "id": "j6qg8rc6",
2273
2273
  "componentType": "Table",
2274
- "mandatory": false,
2274
+ "isMandatory": false,
2275
2275
  "page": "29",
2276
2276
  "label": {
2277
2277
  "value": "\"➡ \" || \"Please, complete the following grid with your favourite characters\"",
@@ -2709,7 +2709,7 @@
2709
2709
  {
2710
2710
  "id": "jvxux0mi",
2711
2711
  "componentType": "Table",
2712
- "mandatory": false,
2712
+ "isMandatory": false,
2713
2713
  "page": "30",
2714
2714
  "label": {
2715
2715
  "value": "\"➡ \" || \"How has your feeling about the following characters evolved over time?\"",
@@ -2839,7 +2839,7 @@
2839
2839
  {
2840
2840
  "id": "jvxwy68n",
2841
2841
  "componentType": "Table",
2842
- "mandatory": false,
2842
+ "isMandatory": false,
2843
2843
  "page": "31",
2844
2844
  "label": {
2845
2845
  "value": "\"➡ \" || \"Can you tell how long Bart Simpson has been on leave for each type and whether there has been another type?\"",
@@ -3067,7 +3067,7 @@
3067
3067
  {
3068
3068
  "id": "kiq612ky",
3069
3069
  "componentType": "InputNumber",
3070
- "mandatory": false,
3070
+ "isMandatory": false,
3071
3071
  "page": "33",
3072
3072
  "min": 0,
3073
3073
  "max": 20,
@@ -3166,7 +3166,7 @@
3166
3166
  {
3167
3167
  "id": "kiq66gtw",
3168
3168
  "componentType": "Input",
3169
- "mandatory": false,
3169
+ "isMandatory": false,
3170
3170
  "page": "34",
3171
3171
  "maxLength": 30,
3172
3172
  "label": {
@@ -3202,7 +3202,7 @@
3202
3202
  {
3203
3203
  "id": "kiq5r8wu",
3204
3204
  "componentType": "InputNumber",
3205
- "mandatory": false,
3205
+ "isMandatory": false,
3206
3206
  "page": "34",
3207
3207
  "min": 0,
3208
3208
  "max": 120,
@@ -3288,7 +3288,7 @@
3288
3288
  {
3289
3289
  "id": "kiq65x3c",
3290
3290
  "componentType": "CheckboxOne",
3291
- "mandatory": false,
3291
+ "isMandatory": false,
3292
3292
  "page": "35.2",
3293
3293
  "label": {
3294
3294
  "value": "\"➡ \" || \"Is character named \" || NAME_CHAR || \" your favourite one ? \"",
@@ -3325,7 +3325,7 @@
3325
3325
  {
3326
3326
  "id": "kiq651zv",
3327
3327
  "componentType": "Textarea",
3328
- "mandatory": false,
3328
+ "isMandatory": false,
3329
3329
  "page": "35.3",
3330
3330
  "maxLength": 255,
3331
3331
  "label": {
@@ -3376,7 +3376,7 @@
3376
3376
  {
3377
3377
  "id": "j6z0z3us",
3378
3378
  "componentType": "Textarea",
3379
- "mandatory": false,
3379
+ "isMandatory": false,
3380
3380
  "page": "37",
3381
3381
  "maxLength": 255,
3382
3382
  "label": {
@@ -3412,7 +3412,7 @@
3412
3412
  {
3413
3413
  "id": "COMMENT-QUESTION",
3414
3414
  "componentType": "Textarea",
3415
- "mandatory": false,
3415
+ "isMandatory": false,
3416
3416
  "page": "39",
3417
3417
  "maxLength": 2000,
3418
3418
  "label": { "value": "\"VIII - \" || \"Comment\"", "type": "VTL|MD" },