1+ import  { 
2+   render 
3+ }  from  '@testing-library/preact/pure' ; 
4+ 
5+ import  {  JSFunctionField  }  from  '../../../../../src/render/components/form-fields/JSFunctionField' ; 
6+ 
7+ import  {  MockFormContext  }  from  '../helper' ; 
8+ 
9+ import  {  act  }  from  'preact/test-utils' ; 
10+ 
11+ import  { 
12+   createFormContainer 
13+ }  from  '../../../../TestHelper' ; 
14+ 
15+ let  container ; 
16+ 
17+ describe ( 'JSFunctionField' ,  function ( )  { 
18+ 
19+   beforeEach ( function ( )  { 
20+     container  =  createFormContainer ( ) ; 
21+   } ) ; 
22+ 
23+ 
24+   afterEach ( function ( )  { 
25+     container . remove ( ) ; 
26+   } ) ; 
27+ 
28+ 
29+   it ( 'should evaluate with setValue' ,  async  function ( )  { 
30+ 
31+     // given 
32+     const  onChangeSpy  =  sinon . spy ( ) ; 
33+     const  field  =  defaultField ; 
34+     const  passedData  =  {  value  : 42  } ; 
35+ 
36+     const  services  =  { 
37+       expressionLanguage : { 
38+         isExpression : ( )  =>  true , 
39+         evaluate : ( )  =>  { 
40+           return  passedData ; 
41+         } 
42+       } 
43+     } ; 
44+ 
45+     // when 
46+     act ( ( )  =>  { 
47+       createJSFunctionField ( {  field,  onChange : onChangeSpy ,  services } ) ; 
48+     } ) ; 
49+ 
50+     // wait for the iframe to compute the expression and pass it back 
51+     await  new  Promise ( r  =>  setTimeout ( r ,  100 ) ) . then ( ( )  =>  { 
52+ 
53+       // then 
54+       expect ( onChangeSpy ) . to . be . calledOnce ; 
55+       expect ( onChangeSpy ) . to . be . calledWith ( {  field,  value : 42  } ) ; 
56+     } ) ; 
57+ 
58+   } ) ; 
59+ 
60+ 
61+   it ( 'should evaluate with return' ,  async  function ( )  { 
62+ 
63+     // given 
64+     const  onChangeSpy  =  sinon . spy ( ) ; 
65+     const  field  =  { 
66+       ...defaultField , 
67+       jsFunction : 'return data.value' 
68+     } ; 
69+     const  passedData  =  {  value  : 42  } ; 
70+ 
71+     const  services  =  { 
72+       expressionLanguage : { 
73+         isExpression : ( )  =>  true , 
74+         evaluate : ( )  =>  { 
75+           return  passedData ; 
76+         } 
77+       } 
78+     } ; 
79+ 
80+     // when 
81+     act ( ( )  =>  { 
82+       createJSFunctionField ( {  field,  onChange : onChangeSpy ,  services } ) ; 
83+     } ) ; 
84+ 
85+     // wait for the iframe to compute the expression and pass it back 
86+     await  new  Promise ( r  =>  setTimeout ( r ,  100 ) ) . then ( ( )  =>  { 
87+ 
88+       // then 
89+       expect ( onChangeSpy ) . to . be . calledOnce ; 
90+       expect ( onChangeSpy ) . to . be . calledWith ( {  field,  value : 42  } ) ; 
91+     } ) ; 
92+ 
93+   } ) ; 
94+ 
95+ 
96+   it ( 'should evaluate multiple times when using interval' ,  async  function ( )  { 
97+ 
98+     // given 
99+     const  onChangeSpy  =  sinon . spy ( ) ; 
100+     const  field  =  { 
101+       ...defaultField , 
102+       computeOn : 'interval' , 
103+       interval : 100 
104+     } ; 
105+     const  passedData  =  {  value  : 42  } ; 
106+ 
107+     const  services  =  { 
108+       expressionLanguage : { 
109+         isExpression : ( )  =>  true , 
110+         evaluate : ( )  =>  { 
111+           return  passedData ; 
112+         } 
113+       } 
114+     } ; 
115+ 
116+     // when 
117+     act ( ( )  =>  { 
118+       createJSFunctionField ( {  field,  onChange : onChangeSpy ,  services } ) ; 
119+     } ) ; 
120+ 
121+     // wait for the iframe to compute the expression and pass it back 
122+     await  new  Promise ( r  =>  setTimeout ( r ,  500 ) ) . then ( ( )  =>  { 
123+ 
124+       // then 
125+ 
126+       // deliberately underestimating the number of calls to account for potential timing issues 
127+       expect ( onChangeSpy . callCount  >  3 ) . to . be . true ; 
128+       expect ( onChangeSpy ) . to . be . calledWith ( {  field,  value : 42  } ) ; 
129+     } ) ; 
130+ 
131+ 
132+   } ) ; 
133+ 
134+ } ) ; 
135+ 
136+ // helpers ////////// 
137+ 
138+ const  defaultField  =  { 
139+   type : 'script' , 
140+   key : 'jsfunction' , 
141+   jsFunction : 'setValue(data.value)' , 
142+   computeOn : 'load' 
143+ } ; 
144+ 
145+ function  createJSFunctionField ( {  services,  ...restOptions  }  =  { } )  { 
146+   const  options  =  { 
147+     field : defaultField , 
148+     onChange : ( )  =>  { } , 
149+     ...restOptions 
150+   } ; 
151+ 
152+   return  render ( 
153+     < MockFormContext 
154+       services = {  services  } 
155+       options = {  options  } > 
156+       < JSFunctionField 
157+         field = {  options . field  } 
158+         onChange = {  options . onChange  }  /> 
159+     </ MockFormContext > ,  { 
160+       container : options . container  ||  container . querySelector ( '.fjs-form' ) 
161+     } 
162+   ) ; 
163+ } 
0 commit comments