@@ -14,7 +14,9 @@ import {
1414 ComputedRef ,
1515 shallowReactive ,
1616 nextTick ,
17- ref
17+ ref ,
18+ Ref ,
19+ watch
1820} from '@vue/runtime-test'
1921import {
2022 defineEmits ,
@@ -184,13 +186,17 @@ describe('SFC <script setup> helpers', () => {
184186 foo . value = 'bar'
185187 }
186188
189+ const compRender = vi . fn ( )
187190 const Comp = defineComponent ( {
188191 props : [ 'modelValue' ] ,
189192 emits : [ 'update:modelValue' ] ,
190193 setup ( props ) {
191194 foo = useModel ( props , 'modelValue' )
192- } ,
193- render ( ) { }
195+ return ( ) => {
196+ compRender ( )
197+ return foo . value
198+ }
199+ }
194200 } )
195201
196202 const msg = ref ( '' )
@@ -206,6 +212,8 @@ describe('SFC <script setup> helpers', () => {
206212 expect ( foo . value ) . toBe ( '' )
207213 expect ( msg . value ) . toBe ( '' )
208214 expect ( setValue ) . not . toBeCalled ( )
215+ expect ( compRender ) . toBeCalledTimes ( 1 )
216+ expect ( serializeInner ( root ) ) . toBe ( '' )
209217
210218 // update from child
211219 update ( )
@@ -214,68 +222,212 @@ describe('SFC <script setup> helpers', () => {
214222 expect ( msg . value ) . toBe ( 'bar' )
215223 expect ( foo . value ) . toBe ( 'bar' )
216224 expect ( setValue ) . toBeCalledTimes ( 1 )
225+ expect ( compRender ) . toBeCalledTimes ( 2 )
226+ expect ( serializeInner ( root ) ) . toBe ( 'bar' )
217227
218228 // update from parent
219229 msg . value = 'qux'
230+ expect ( msg . value ) . toBe ( 'qux' )
220231
221232 await nextTick ( )
222233 expect ( msg . value ) . toBe ( 'qux' )
223234 expect ( foo . value ) . toBe ( 'qux' )
224235 expect ( setValue ) . toBeCalledTimes ( 1 )
236+ expect ( compRender ) . toBeCalledTimes ( 3 )
237+ expect ( serializeInner ( root ) ) . toBe ( 'qux' )
225238 } )
226239
227- test ( 'local' , async ( ) => {
240+ test ( 'without parent value ( local mutation) ' , async ( ) => {
228241 let foo : any
229242 const update = ( ) => {
230243 foo . value = 'bar'
231244 }
232245
246+ const compRender = vi . fn ( )
233247 const Comp = defineComponent ( {
234248 props : [ 'foo' ] ,
235249 emits : [ 'update:foo' ] ,
236250 setup ( props ) {
237- foo = useModel ( props , 'foo' , { local : true } )
238- } ,
239- render ( ) { }
251+ foo = useModel ( props , 'foo' )
252+ return ( ) => {
253+ compRender ( )
254+ return foo . value
255+ }
256+ }
240257 } )
241258
242259 const root = nodeOps . createElement ( 'div' )
243260 const updateFoo = vi . fn ( )
244261 render ( h ( Comp , { 'onUpdate:foo' : updateFoo } ) , root )
262+ expect ( compRender ) . toBeCalledTimes ( 1 )
263+ expect ( serializeInner ( root ) ) . toBe ( '<!---->' )
245264
246265 expect ( foo . value ) . toBeUndefined ( )
247266 update ( )
248-
267+ // when parent didn't provide value, local mutation is enabled
249268 expect ( foo . value ) . toBe ( 'bar' )
250269
251270 await nextTick ( )
252271 expect ( updateFoo ) . toBeCalledTimes ( 1 )
272+ expect ( compRender ) . toBeCalledTimes ( 2 )
273+ expect ( serializeInner ( root ) ) . toBe ( 'bar' )
253274 } )
254275
255276 test ( 'default value' , async ( ) => {
256277 let count : any
257278 const inc = ( ) => {
258279 count . value ++
259280 }
281+
282+ const compRender = vi . fn ( )
260283 const Comp = defineComponent ( {
261284 props : { count : { default : 0 } } ,
262285 emits : [ 'update:count' ] ,
263286 setup ( props ) {
264- count = useModel ( props , 'count' , { local : true } )
265- } ,
266- render ( ) { }
287+ count = useModel ( props , 'count' )
288+ return ( ) => {
289+ compRender ( )
290+ return count . value
291+ }
292+ }
267293 } )
268294
269295 const root = nodeOps . createElement ( 'div' )
270296 const updateCount = vi . fn ( )
271297 render ( h ( Comp , { 'onUpdate:count' : updateCount } ) , root )
298+ expect ( compRender ) . toBeCalledTimes ( 1 )
299+ expect ( serializeInner ( root ) ) . toBe ( '0' )
272300
273301 expect ( count . value ) . toBe ( 0 )
274302
275303 inc ( )
304+ // when parent didn't provide value, local mutation is enabled
276305 expect ( count . value ) . toBe ( 1 )
306+
277307 await nextTick ( )
308+
278309 expect ( updateCount ) . toBeCalledTimes ( 1 )
310+ expect ( compRender ) . toBeCalledTimes ( 2 )
311+ expect ( serializeInner ( root ) ) . toBe ( '1' )
312+ } )
313+
314+ test ( 'parent limiting child value' , async ( ) => {
315+ let childCount : Ref < number >
316+
317+ const compRender = vi . fn ( )
318+ const Comp = defineComponent ( {
319+ props : [ 'count' ] ,
320+ emits : [ 'update:count' ] ,
321+ setup ( props ) {
322+ childCount = useModel ( props , 'count' )
323+ return ( ) => {
324+ compRender ( )
325+ return childCount . value
326+ }
327+ }
328+ } )
329+
330+ const Parent = defineComponent ( {
331+ setup ( ) {
332+ const count = ref ( 0 )
333+ watch ( count , ( ) => {
334+ if ( count . value < 0 ) {
335+ count . value = 0
336+ }
337+ } )
338+ return ( ) =>
339+ h ( Comp , {
340+ count : count . value ,
341+ 'onUpdate:count' : val => {
342+ count . value = val
343+ }
344+ } )
345+ }
346+ } )
347+
348+ const root = nodeOps . createElement ( 'div' )
349+ render ( h ( Parent ) , root )
350+ expect ( serializeInner ( root ) ) . toBe ( '0' )
351+
352+ // child update
353+ childCount ! . value = 1
354+ // not yet updated
355+ expect ( childCount ! . value ) . toBe ( 0 )
356+
357+ await nextTick ( )
358+ expect ( childCount ! . value ) . toBe ( 1 )
359+ expect ( serializeInner ( root ) ) . toBe ( '1' )
360+
361+ // child update to invalid value
362+ childCount ! . value = - 1
363+ // not yet updated
364+ expect ( childCount ! . value ) . toBe ( 1 )
365+
366+ await nextTick ( )
367+ // limited to 0 by parent
368+ expect ( childCount ! . value ) . toBe ( 0 )
369+ expect ( serializeInner ( root ) ) . toBe ( '0' )
370+ } )
371+
372+ test ( 'has parent value -> no parent value' , async ( ) => {
373+ let childCount : Ref < number >
374+
375+ const compRender = vi . fn ( )
376+ const Comp = defineComponent ( {
377+ props : [ 'count' ] ,
378+ emits : [ 'update:count' ] ,
379+ setup ( props ) {
380+ childCount = useModel ( props , 'count' )
381+ return ( ) => {
382+ compRender ( )
383+ return childCount . value
384+ }
385+ }
386+ } )
387+
388+ const toggle = ref ( true )
389+ const Parent = defineComponent ( {
390+ setup ( ) {
391+ const count = ref ( 0 )
392+ return ( ) =>
393+ toggle . value
394+ ? h ( Comp , {
395+ count : count . value ,
396+ 'onUpdate:count' : val => {
397+ count . value = val
398+ }
399+ } )
400+ : h ( Comp )
401+ }
402+ } )
403+
404+ const root = nodeOps . createElement ( 'div' )
405+ render ( h ( Parent ) , root )
406+ expect ( serializeInner ( root ) ) . toBe ( '0' )
407+
408+ // child update
409+ childCount ! . value = 1
410+ // not yet updated
411+ expect ( childCount ! . value ) . toBe ( 0 )
412+
413+ await nextTick ( )
414+ expect ( childCount ! . value ) . toBe ( 1 )
415+ expect ( serializeInner ( root ) ) . toBe ( '1' )
416+
417+ // parent change
418+ toggle . value = false
419+
420+ await nextTick ( )
421+ // localValue should be reset
422+ expect ( childCount ! . value ) . toBeUndefined ( )
423+ expect ( serializeInner ( root ) ) . toBe ( '<!---->' )
424+
425+ // child local mutation should continue to work
426+ childCount ! . value = 2
427+ expect ( childCount ! . value ) . toBe ( 2 )
428+
429+ await nextTick ( )
430+ expect ( serializeInner ( root ) ) . toBe ( '2' )
279431 } )
280432 } )
281433
0 commit comments