@inseefr/lunatic 3.4.20 → 3.4.21
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/components/Loop/Loop.js +1 -1
- package/components/Loop/Loop.js.map +1 -1
- package/components/Loop/Loop.spec.d.ts +1 -0
- package/components/Loop/Loop.spec.js +39 -0
- package/components/Loop/Loop.spec.js.map +1 -0
- package/esm/components/Loop/Loop.js +1 -1
- package/esm/components/Loop/Loop.js.map +1 -1
- package/esm/components/Loop/Loop.spec.d.ts +1 -0
- package/esm/components/Loop/Loop.spec.js +37 -0
- package/esm/components/Loop/Loop.spec.js.map +1 -0
- package/esm/type.source.js +0 -1
- package/esm/type.source.js.map +1 -1
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.d.ts +1 -1
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.js +4 -2
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.spec.js +71 -0
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.spec.js.map +1 -1
- package/esm/use-lunatic/props/propValue.js +3 -2
- package/esm/use-lunatic/props/propValue.js.map +1 -1
- package/esm/use-lunatic/props/propValue.spec.js +48 -0
- package/esm/use-lunatic/props/propValue.spec.js.map +1 -1
- package/esm/use-lunatic/reducer/reducerInitializer.js +1 -1
- package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
- package/package.json +8 -1
- package/src/components/Loop/Loop.spec.tsx +77 -0
- package/src/components/Loop/Loop.tsx +1 -1
- package/src/type.source.ts +0 -1
- package/src/use-lunatic/commons/variables/lunatic-variables-store.spec.ts +79 -0
- package/src/use-lunatic/commons/variables/lunatic-variables-store.ts +5 -2
- package/src/use-lunatic/props/propValue.spec.ts +52 -0
- package/src/use-lunatic/props/propValue.ts +5 -2
- package/src/use-lunatic/reducer/reducerInitializer.tsx +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/type.source.js +0 -1
- package/type.source.js.map +1 -1
- package/use-lunatic/commons/variables/lunatic-variables-store.d.ts +1 -1
- package/use-lunatic/commons/variables/lunatic-variables-store.js +4 -2
- package/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
- package/use-lunatic/commons/variables/lunatic-variables-store.spec.js +94 -0
- package/use-lunatic/commons/variables/lunatic-variables-store.spec.js.map +1 -1
- package/use-lunatic/props/propValue.js +3 -2
- package/use-lunatic/props/propValue.js.map +1 -1
- package/use-lunatic/props/propValue.spec.js +48 -0
- package/use-lunatic/props/propValue.spec.js.map +1 -1
- package/use-lunatic/reducer/reducerInitializer.js +1 -1
- package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Loop } from './Loop';
|
|
4
|
+
import type { LunaticComponentProps } from '../type';
|
|
5
|
+
|
|
6
|
+
describe('Loop', () => {
|
|
7
|
+
const mockOnChange = vi.fn();
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mockOnChange.mockClear();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const getComponents = (iteration: number) => [
|
|
14
|
+
{
|
|
15
|
+
componentType: 'Input',
|
|
16
|
+
maxLength: 249,
|
|
17
|
+
id: 'nameId',
|
|
18
|
+
response: {
|
|
19
|
+
name: 'name',
|
|
20
|
+
},
|
|
21
|
+
iteration: iteration,
|
|
22
|
+
value: 'Jonathan Doe',
|
|
23
|
+
} as LunaticComponentProps<'Input'>,
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
it('render the right number of lines by default', () => {
|
|
27
|
+
render(
|
|
28
|
+
<Loop
|
|
29
|
+
value={{ name: ['John Doe', 'Jane Doe'] }}
|
|
30
|
+
handleChanges={mockOnChange}
|
|
31
|
+
label="Ceci est un test"
|
|
32
|
+
id="table"
|
|
33
|
+
lines={{ min: 4, max: 10 }}
|
|
34
|
+
iterations={2}
|
|
35
|
+
getComponents={getComponents}
|
|
36
|
+
executeExpression={() => null as any}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
expect(screen.getAllByRole('textbox')).toHaveLength(4);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('disables the remove row button when the minimum number of rows is reached', () => {
|
|
43
|
+
render(
|
|
44
|
+
<Loop
|
|
45
|
+
value={{ name: ['John Doe', 'Jane Doe', 'Alice', 'Bob'] }}
|
|
46
|
+
handleChanges={mockOnChange}
|
|
47
|
+
label="Ceci est un test"
|
|
48
|
+
id="table"
|
|
49
|
+
lines={{ min: 4, max: 10 }}
|
|
50
|
+
iterations={4}
|
|
51
|
+
getComponents={getComponents}
|
|
52
|
+
executeExpression={() => null as any}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const Button = screen.getByRole('button', { name: /remove/i });
|
|
57
|
+
expect(Button).toBeDisabled();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('enables the add row button when the maximum number of rows is not reached', () => {
|
|
61
|
+
render(
|
|
62
|
+
<Loop
|
|
63
|
+
value={{ name: ['John Doe', 'Jane Doe', 'Alice'] }}
|
|
64
|
+
handleChanges={mockOnChange}
|
|
65
|
+
label="Ceci est un test"
|
|
66
|
+
id="table"
|
|
67
|
+
lines={{ min: 2, max: 10 }}
|
|
68
|
+
iterations={3}
|
|
69
|
+
getComponents={getComponents}
|
|
70
|
+
executeExpression={() => null as any}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const Button = screen.getByRole('button', { name: /add/i });
|
|
75
|
+
expect(Button).not.toBeDisabled();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -60,7 +60,7 @@ export function Loop({
|
|
|
60
60
|
{...props}
|
|
61
61
|
errors={getComponentErrors(errors, props.id)}
|
|
62
62
|
addRow={nbRows === max ? undefined : addRow}
|
|
63
|
-
removeRow={nbRows === 1 ? undefined : removeRow}
|
|
63
|
+
removeRow={nbRows === 1 || nbRows === min ? undefined : removeRow}
|
|
64
64
|
canControlRows={min !== max && Number.isFinite(max)}
|
|
65
65
|
>
|
|
66
66
|
{times(nbRows, (n) => (
|
package/src/type.source.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import { cleaningBehaviour } from './behaviours/cleaning-behaviour';
|
|
3
|
+
import * as cleaningModule from './behaviours/cleaning-behaviour';
|
|
3
4
|
import { missingBehaviour } from './behaviours/missing-behaviour';
|
|
4
5
|
import { resizingBehaviour } from './behaviours/resizing-behaviour';
|
|
5
6
|
import { LunaticVariablesStore } from './lunatic-variables-store';
|
|
@@ -480,5 +481,83 @@ describe('lunatic-variables-store', () => {
|
|
|
480
481
|
store.set('NOM', 'Doe');
|
|
481
482
|
expect(store.get('PRENOM')).toEqual('John');
|
|
482
483
|
});
|
|
484
|
+
it('should enable cleaning when disableCleaning = false', () => {
|
|
485
|
+
const cleaningSpy = vi.spyOn(cleaningModule, 'cleaningBehaviour');
|
|
486
|
+
LunaticVariablesStore.makeFromSource(
|
|
487
|
+
{
|
|
488
|
+
components: [],
|
|
489
|
+
variables: [
|
|
490
|
+
{
|
|
491
|
+
name: 'PRENOM',
|
|
492
|
+
values: {
|
|
493
|
+
COLLECTED: 'John',
|
|
494
|
+
},
|
|
495
|
+
variableType: 'COLLECTED',
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: 'NOM',
|
|
499
|
+
values: {
|
|
500
|
+
COLLECTED: '',
|
|
501
|
+
},
|
|
502
|
+
variableType: 'COLLECTED',
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
cleaning: {
|
|
506
|
+
NOM: {
|
|
507
|
+
PRENOM: 'false',
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
COLLECTED: {
|
|
513
|
+
PRENOM: {
|
|
514
|
+
COLLECTED: 'Jane',
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
{ current: () => {} },
|
|
519
|
+
false // enable cleaning
|
|
520
|
+
);
|
|
521
|
+
expect(cleaningSpy).toHaveBeenCalled();
|
|
522
|
+
});
|
|
523
|
+
it('should disable cleaning when disableCleaning = true', () => {
|
|
524
|
+
const cleaningSpy = vi.spyOn(cleaningModule, 'cleaningBehaviour');
|
|
525
|
+
LunaticVariablesStore.makeFromSource(
|
|
526
|
+
{
|
|
527
|
+
components: [],
|
|
528
|
+
variables: [
|
|
529
|
+
{
|
|
530
|
+
name: 'PRENOM',
|
|
531
|
+
values: {
|
|
532
|
+
COLLECTED: 'John',
|
|
533
|
+
},
|
|
534
|
+
variableType: 'COLLECTED',
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
name: 'NOM',
|
|
538
|
+
values: {
|
|
539
|
+
COLLECTED: '',
|
|
540
|
+
},
|
|
541
|
+
variableType: 'COLLECTED',
|
|
542
|
+
},
|
|
543
|
+
],
|
|
544
|
+
cleaning: {
|
|
545
|
+
NOM: {
|
|
546
|
+
PRENOM: 'false',
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
COLLECTED: {
|
|
552
|
+
PRENOM: {
|
|
553
|
+
COLLECTED: 'Jane',
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
{ current: () => {} },
|
|
558
|
+
true // disable cleaning
|
|
559
|
+
);
|
|
560
|
+
expect(cleaningSpy).not.toHaveBeenCalled();
|
|
561
|
+
});
|
|
483
562
|
});
|
|
484
563
|
});
|
|
@@ -54,7 +54,8 @@ export class LunaticVariablesStore {
|
|
|
54
54
|
public static makeFromSource(
|
|
55
55
|
source: LunaticSource,
|
|
56
56
|
data: LunaticData,
|
|
57
|
-
changeHandler: RefObject<LunaticOptions['onVariableChange']
|
|
57
|
+
changeHandler: RefObject<LunaticOptions['onVariableChange']>,
|
|
58
|
+
disableCleaning?: boolean
|
|
58
59
|
) {
|
|
59
60
|
const store = new LunaticVariablesStore();
|
|
60
61
|
if (!source.variables) {
|
|
@@ -90,7 +91,9 @@ export class LunaticVariablesStore {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
store.on('change', (e) => changeHandler?.current?.(e.detail));
|
|
93
|
-
|
|
94
|
+
if (!disableCleaning) {
|
|
95
|
+
cleaningBehaviour(store, source.cleaning, sourceValues);
|
|
96
|
+
}
|
|
94
97
|
resizingBehaviour(store, source.resizing);
|
|
95
98
|
missingBehaviour(store, source.missingBlock);
|
|
96
99
|
return store;
|
|
@@ -115,4 +115,56 @@ describe('fillComponentValue', () => {
|
|
|
115
115
|
});
|
|
116
116
|
});
|
|
117
117
|
});
|
|
118
|
+
|
|
119
|
+
describe('RosterForLoop', () => {
|
|
120
|
+
const rosterForLoopComponent = {
|
|
121
|
+
id: 'loop-prenom',
|
|
122
|
+
componentType: 'RosterForLoop',
|
|
123
|
+
bindingDependencies: ['PRENOM'],
|
|
124
|
+
lines: {
|
|
125
|
+
min: {
|
|
126
|
+
value: '1',
|
|
127
|
+
type: 'VTL',
|
|
128
|
+
},
|
|
129
|
+
max: {
|
|
130
|
+
value: '10',
|
|
131
|
+
type: 'VTL',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
page: '1',
|
|
135
|
+
components: [
|
|
136
|
+
{
|
|
137
|
+
componentType: 'Input',
|
|
138
|
+
label: {
|
|
139
|
+
value: '"Prénom"',
|
|
140
|
+
type: 'VTL|MD',
|
|
141
|
+
},
|
|
142
|
+
conditionFilter: {
|
|
143
|
+
value: 'true',
|
|
144
|
+
type: 'VTL',
|
|
145
|
+
},
|
|
146
|
+
maxLength: 30,
|
|
147
|
+
bindingDependencies: ['PRENOM'],
|
|
148
|
+
id: 'prenom',
|
|
149
|
+
response: {
|
|
150
|
+
name: 'PRENOM',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
} as any as LunaticComponentDefinition<'RosterForLoop'>;
|
|
155
|
+
|
|
156
|
+
it('should correctly extract values from nested responses as arrays', () => {
|
|
157
|
+
const values = {
|
|
158
|
+
PRENOM: ['Alice', 'Bob', 'Charlie'],
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
expectFilledComponent(rosterForLoopComponent, values).toEqual(values);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should return null for missing responses', () => {
|
|
165
|
+
expectFilledComponent(rosterForLoopComponent).toEqual({
|
|
166
|
+
PRENOM: null,
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
118
170
|
});
|
|
@@ -27,8 +27,11 @@ export function getValueProp(
|
|
|
27
27
|
if (hasResponse(component)) {
|
|
28
28
|
return args.variables.get(component.response.name, iteration);
|
|
29
29
|
}
|
|
30
|
-
// For
|
|
31
|
-
if (
|
|
30
|
+
// For Loop and RosterForLoop, value will be a map of child component values
|
|
31
|
+
if (
|
|
32
|
+
component.componentType === 'Loop' ||
|
|
33
|
+
component.componentType === 'RosterForLoop'
|
|
34
|
+
) {
|
|
32
35
|
return getChildResponseValues(component.components, args.variables);
|
|
33
36
|
}
|
|
34
37
|
return null;
|