Skip to content

Commit 8188784

Browse files
authored
docs(v-model): add v-model section (#1839)
1 parent 9673f47 commit 8188784

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export default defineConfig({
8686
text: 'Reusability and Composition',
8787
link: '/guide/advanced/reusability-composition'
8888
},
89+
{ text: 'Testing v-model', link: '/guide/advanced/v-model' },
8990
{ text: 'Testing Vuex', link: '/guide/advanced/vuex' },
9091
{ text: 'Testing Vue Router', link: '/guide/advanced/vue-router' },
9192
{ text: 'Testing Teleport', link: '/guide/advanced/teleport' },

docs/guide/advanced/v-model.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Testing `v-model`
2+
3+
When writing components that rely on `v-model` interaction (`update:modelValue` event), you need to handle the `event` and `props`.
4+
5+
Check ["vmodel integration" Discussion](https://github.com/vuejs/test-utils/discussions/279) for some community solutions.
6+
7+
Check [VueJS VModel event documentation](https://vuejs.org/guide/components/events.html#usage-with-v-model).
8+
9+
## A Simple Example
10+
11+
Here a simple Editor component:
12+
13+
```js
14+
const Editor = {
15+
props: {
16+
label: String,
17+
modelValue: String
18+
},
19+
template: `<div>
20+
<label>{{label}}</label>
21+
<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)">
22+
</div>`
23+
}
24+
```
25+
26+
This component will just behave as an input component:
27+
28+
```js
29+
const App {
30+
components: {
31+
Editor
32+
},
33+
template: `<editor v-model="text" label="test" />`
34+
data(){
35+
return {
36+
text: 'test'
37+
}
38+
}
39+
}
40+
```
41+
42+
Now when we type on the input, it will update `text` on our component.
43+
44+
To test this behavior:
45+
46+
```js
47+
test('modelValue should be updated', async () => {
48+
const wrapper = mount(Editor, {
49+
props: {
50+
modelValue: 'initialText',
51+
'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e })
52+
}
53+
})
54+
55+
await wrapper.find('input').setValue('test')
56+
expect(wrapper.props('modelValue')).toBe('test')
57+
})
58+
```
59+
60+
# Multiple `v-model`
61+
62+
In some situations we can have multiple `v-model` targeting specific properties.
63+
64+
Example an Money Editor, we can have `currency` and `modelValue` properties.
65+
66+
```js
67+
const MoneyEditor = {
68+
template: `<div>
69+
<input :value="currency" @input="$emit('update:currency', $event.target.value)"/>
70+
<input :value="modelValue" type="number" @input="$emit('update:modelValue', $event.target.value)"/>
71+
</div>`,
72+
props: ['currency', 'modelValue']
73+
}
74+
```
75+
76+
We can test both by:
77+
78+
```js
79+
test('modelValue and currency should be updated', async () => {
80+
const wrapper = mount(MoneyEditor, {
81+
props: {
82+
modelValue: 'initialText',
83+
'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
84+
currency: '$',
85+
'onUpdate:currency': (e) => wrapper.setProps({ currency: e })
86+
}
87+
})
88+
89+
const [currencyInput, modelValueInput] = wrapper.findAll('input')
90+
await modelValueInput.setValue('test')
91+
await currencyInput.setValue('£')
92+
93+
expect(wrapper.props('modelValue')).toBe('test')
94+
expect(wrapper.props('currency')).toBe('£')
95+
})
96+
```

0 commit comments

Comments
 (0)