@@ -14,7 +14,9 @@ import {
14
14
ComputedRef ,
15
15
shallowReactive ,
16
16
nextTick ,
17
- ref
17
+ ref ,
18
+ Ref ,
19
+ watch
18
20
} from '@vue/runtime-test'
19
21
import {
20
22
defineEmits ,
@@ -184,13 +186,17 @@ describe('SFC <script setup> helpers', () => {
184
186
foo . value = 'bar'
185
187
}
186
188
189
+ const compRender = vi . fn ( )
187
190
const Comp = defineComponent ( {
188
191
props : [ 'modelValue' ] ,
189
192
emits : [ 'update:modelValue' ] ,
190
193
setup ( props ) {
191
194
foo = useModel ( props , 'modelValue' )
192
- } ,
193
- render ( ) { }
195
+ return ( ) => {
196
+ compRender ( )
197
+ return foo . value
198
+ }
199
+ }
194
200
} )
195
201
196
202
const msg = ref ( '' )
@@ -206,6 +212,8 @@ describe('SFC <script setup> helpers', () => {
206
212
expect ( foo . value ) . toBe ( '' )
207
213
expect ( msg . value ) . toBe ( '' )
208
214
expect ( setValue ) . not . toBeCalled ( )
215
+ expect ( compRender ) . toBeCalledTimes ( 1 )
216
+ expect ( serializeInner ( root ) ) . toBe ( '' )
209
217
210
218
// update from child
211
219
update ( )
@@ -214,68 +222,212 @@ describe('SFC <script setup> helpers', () => {
214
222
expect ( msg . value ) . toBe ( 'bar' )
215
223
expect ( foo . value ) . toBe ( 'bar' )
216
224
expect ( setValue ) . toBeCalledTimes ( 1 )
225
+ expect ( compRender ) . toBeCalledTimes ( 2 )
226
+ expect ( serializeInner ( root ) ) . toBe ( 'bar' )
217
227
218
228
// update from parent
219
229
msg . value = 'qux'
230
+ expect ( msg . value ) . toBe ( 'qux' )
220
231
221
232
await nextTick ( )
222
233
expect ( msg . value ) . toBe ( 'qux' )
223
234
expect ( foo . value ) . toBe ( 'qux' )
224
235
expect ( setValue ) . toBeCalledTimes ( 1 )
236
+ expect ( compRender ) . toBeCalledTimes ( 3 )
237
+ expect ( serializeInner ( root ) ) . toBe ( 'qux' )
225
238
} )
226
239
227
- test ( 'local' , async ( ) => {
240
+ test ( 'without parent value ( local mutation) ' , async ( ) => {
228
241
let foo : any
229
242
const update = ( ) => {
230
243
foo . value = 'bar'
231
244
}
232
245
246
+ const compRender = vi . fn ( )
233
247
const Comp = defineComponent ( {
234
248
props : [ 'foo' ] ,
235
249
emits : [ 'update:foo' ] ,
236
250
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
+ }
240
257
} )
241
258
242
259
const root = nodeOps . createElement ( 'div' )
243
260
const updateFoo = vi . fn ( )
244
261
render ( h ( Comp , { 'onUpdate:foo' : updateFoo } ) , root )
262
+ expect ( compRender ) . toBeCalledTimes ( 1 )
263
+ expect ( serializeInner ( root ) ) . toBe ( '<!---->' )
245
264
246
265
expect ( foo . value ) . toBeUndefined ( )
247
266
update ( )
248
-
267
+ // when parent didn't provide value, local mutation is enabled
249
268
expect ( foo . value ) . toBe ( 'bar' )
250
269
251
270
await nextTick ( )
252
271
expect ( updateFoo ) . toBeCalledTimes ( 1 )
272
+ expect ( compRender ) . toBeCalledTimes ( 2 )
273
+ expect ( serializeInner ( root ) ) . toBe ( 'bar' )
253
274
} )
254
275
255
276
test ( 'default value' , async ( ) => {
256
277
let count : any
257
278
const inc = ( ) => {
258
279
count . value ++
259
280
}
281
+
282
+ const compRender = vi . fn ( )
260
283
const Comp = defineComponent ( {
261
284
props : { count : { default : 0 } } ,
262
285
emits : [ 'update:count' ] ,
263
286
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
+ }
267
293
} )
268
294
269
295
const root = nodeOps . createElement ( 'div' )
270
296
const updateCount = vi . fn ( )
271
297
render ( h ( Comp , { 'onUpdate:count' : updateCount } ) , root )
298
+ expect ( compRender ) . toBeCalledTimes ( 1 )
299
+ expect ( serializeInner ( root ) ) . toBe ( '0' )
272
300
273
301
expect ( count . value ) . toBe ( 0 )
274
302
275
303
inc ( )
304
+ // when parent didn't provide value, local mutation is enabled
276
305
expect ( count . value ) . toBe ( 1 )
306
+
277
307
await nextTick ( )
308
+
278
309
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' )
279
431
} )
280
432
} )
281
433
0 commit comments