Parcourir la source

test: add dynamic model tests for input, textarea, select, checkbox, and radio

daiwei il y a 4 mois
Parent
commit
38e3daf8f6
1 fichiers modifiés avec 182 ajouts et 0 suppressions
  1. 182 0
      packages/runtime-vapor/__tests__/directives/vModel.spec.ts

+ 182 - 0
packages/runtime-vapor/__tests__/directives/vModel.spec.ts

@@ -1,12 +1,14 @@
 import { reactive, ref } from '@vue/reactivity'
 import { reactive, ref } from '@vue/reactivity'
 import {
 import {
   applyCheckboxModel,
   applyCheckboxModel,
+  applyDynamicModel,
   applyRadioModel,
   applyRadioModel,
   applySelectModel,
   applySelectModel,
   applyTextModel,
   applyTextModel,
   delegate,
   delegate,
   delegateEvents,
   delegateEvents,
   on,
   on,
+  renderEffect,
   setClass,
   setClass,
   setProp,
   setProp,
   setValue,
   setValue,
@@ -1002,4 +1004,184 @@ describe('directive: v-model', () => {
     await nextTick()
     await nextTick()
     expect(data.value).toEqual('使用拼音输入')
     expect(data.value).toEqual('使用拼音输入')
   })
   })
+
+  describe('applyDynamicModel', () => {
+    test('input + dynamic type', async () => {
+      const spy = vi.fn()
+      const inputType = ref<string>('text')
+
+      const data = ref<string | null | undefined>('')
+      const { host } = define(() => {
+        const n0 = template('<input />')() as HTMLInputElement
+        delegateEvents('input')
+        renderEffect(() => setProp(n0, 'type', inputType.value))
+        applyDynamicModel(
+          n0,
+          () => data.value,
+          val => (data.value = val),
+        )
+        delegate(n0, 'input', () => spy(data.value))
+        return n0
+      }).render()
+
+      const input = host.querySelector('input')!
+      expect(input.value).toEqual('')
+
+      input.value = 'foo'
+      triggerEvent('input', input)
+      await nextTick()
+      expect(data.value).toEqual('foo')
+      expect(spy).toHaveBeenCalledWith('foo')
+
+      data.value = 'bar'
+      await nextTick()
+      expect(input.value).toEqual('bar')
+
+      data.value = undefined
+      await nextTick()
+      expect(input.value).toEqual('')
+    })
+
+    test('should work with textarea', async () => {
+      const data = ref<string>('')
+      const { host } = define(() => {
+        const t0 = template('<textarea />')
+        const n0 = t0() as HTMLInputElement
+        applyDynamicModel(
+          n0,
+          () => data.value,
+          val => (data.value = val),
+        )
+        return n0
+      }).render()
+
+      const input = host.querySelector('textarea')!
+
+      input.value = 'foo'
+      triggerEvent('input', input)
+      await nextTick()
+      expect(data.value).toEqual('foo')
+
+      data.value = 'bar'
+      await nextTick()
+      expect(input.value).toEqual('bar')
+    })
+
+    test('should work with select', async () => {
+      const spy = vi.fn()
+      const data = ref<string | null>('')
+      const { host } = define(() => {
+        const t0 = template(
+          '<select><option>red</option><option>green</option><option>blue</option></select>',
+        )
+        const n0 = t0() as HTMLSelectElement
+        applyDynamicModel(
+          n0,
+          () => data.value,
+          val => (data.value = val),
+        )
+        on(n0, 'change', () => spy(data.value))
+        return n0
+      }).render()
+
+      const select = host.querySelector('select')!
+      expect(select.value).toEqual('')
+
+      select.value = 'red'
+      triggerEvent('change', select)
+      await nextTick()
+      expect(data.value).toEqual('red')
+      expect(spy).toHaveBeenCalledWith('red')
+
+      data.value = 'blue'
+      await nextTick()
+      expect(select.value).toEqual('blue')
+    })
+
+    test('should work with checkbox', async () => {
+      const data = ref<boolean | null>(null)
+      const { host } = define(() => {
+        const t0 = template('<input type="checkbox" />')
+        const n0 = t0() as HTMLInputElement
+        applyDynamicModel(
+          n0,
+          () => data.value,
+          val => (data.value = val),
+        )
+        return n0
+      }).render()
+
+      const input = host.querySelector('input') as HTMLInputElement
+
+      input.checked = true
+      triggerEvent('change', input)
+      await nextTick()
+      expect(data.value).toEqual(true)
+
+      data.value = false
+      await nextTick()
+      expect(input.checked).toEqual(false)
+
+      data.value = true
+      await nextTick()
+      expect(input.checked).toEqual(true)
+
+      input.checked = false
+      triggerEvent('change', input)
+      await nextTick()
+      expect(data.value).toEqual(false)
+    })
+
+    test('should work with radio', async () => {
+      const data = ref<string | null>(null)
+      let n1: HTMLInputElement, n2: HTMLInputElement
+      define(() => {
+        const t0 = template(
+          `<div>` +
+            `<input type="radio" value="foo">` +
+            `<input type="radio" value="bar">` +
+            `</div>`,
+        )
+        const n0 = t0() as HTMLInputElement
+        ;[n1, n2] = Array.from(n0.children) as Array<HTMLInputElement>
+
+        applyDynamicModel(
+          n1,
+          () => data.value,
+          val => (data.value = val),
+        )
+        applyDynamicModel(
+          n2,
+          () => data.value,
+          val => (data.value = val),
+        )
+        return n0
+      }).render()
+
+      n1!.checked = true
+      triggerEvent('change', n1!)
+      await nextTick()
+      expect(data.value).toEqual('foo')
+
+      n2!.checked = true
+      triggerEvent('change', n2!)
+      await nextTick()
+      expect(data.value).toEqual('bar')
+
+      data.value = null
+      await nextTick()
+      expect(n1!.checked).toEqual(false)
+      expect(n2!.checked).toEqual(false)
+
+      data.value = 'foo'
+      await nextTick()
+      expect(n1!.checked).toEqual(true)
+      expect(n2!.checked).toEqual(false)
+
+      data.value = 'bar'
+      await nextTick()
+      expect(n1!.checked).toEqual(false)
+      expect(n2!.checked).toEqual(true)
+    })
+  })
 })
 })