diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 53f6f5fd7..a40d39c8a 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -86,6 +86,7 @@ export default defineConfig({
text: 'Reusability and Composition',
link: '/guide/advanced/reusability-composition'
},
+ { text: 'Testing v-model', link: '/guide/advanced/v-model' },
{ text: 'Testing Vuex', link: '/guide/advanced/vuex' },
{ text: 'Testing Vue Router', link: '/guide/advanced/vue-router' },
{ text: 'Testing Teleport', link: '/guide/advanced/teleport' },
diff --git a/docs/guide/advanced/v-model.md b/docs/guide/advanced/v-model.md
new file mode 100644
index 000000000..50dfcbc06
--- /dev/null
+++ b/docs/guide/advanced/v-model.md
@@ -0,0 +1,96 @@
+# Testing `v-model`
+
+When writing components that rely on `v-model` interaction (`update:modelValue` event), you need to handle the `event` and `props`.
+
+Check ["vmodel integration" Discussion](https://github.com/vuejs/test-utils/discussions/279) for some community solutions.
+
+Check [VueJS VModel event documentation](https://vuejs.org/guide/components/events.html#usage-with-v-model).
+
+## A Simple Example
+
+Here a simple Editor component:
+
+```js
+const Editor = {
+ props: {
+ label: String,
+ modelValue: String
+ },
+ template: `
+
+
+
`
+}
+```
+
+This component will just behave as an input component:
+
+```js
+const App {
+ components: {
+ Editor
+ },
+ template: ``
+ data(){
+ return {
+ text: 'test'
+ }
+ }
+}
+```
+
+Now when we type on the input, it will update `text` on our component.
+
+To test this behavior:
+
+```js
+test('modelValue should be updated', async () => {
+ const wrapper = mount(Editor, {
+ props: {
+ modelValue: 'initialText',
+ 'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e })
+ }
+ })
+
+ await wrapper.find('input').setValue('test')
+ expect(wrapper.props('modelValue')).toBe('test')
+})
+```
+
+# Multiple `v-model`
+
+In some situations we can have multiple `v-model` targeting specific properties.
+
+Example an Money Editor, we can have `currency` and `modelValue` properties.
+
+```js
+const MoneyEditor = {
+ template: `
+
+
+
`,
+ props: ['currency', 'modelValue']
+}
+```
+
+We can test both by:
+
+```js
+test('modelValue and currency should be updated', async () => {
+ const wrapper = mount(MoneyEditor, {
+ props: {
+ modelValue: 'initialText',
+ 'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
+ currency: '$',
+ 'onUpdate:currency': (e) => wrapper.setProps({ currency: e })
+ }
+ })
+
+ const [currencyInput, modelValueInput] = wrapper.findAll('input')
+ await modelValueInput.setValue('test')
+ await currencyInput.setValue('£')
+
+ expect(wrapper.props('modelValue')).toBe('test')
+ expect(wrapper.props('currency')).toBe('£')
+})
+```