Skip to content

Vitest 4 - Vue v-model marked as uncovered #9053

@jeanvt

Description

@jeanvt

Describe the bug

I upgraded to vitest 4, and my coverage suddenly dropped from 90% to 80%, with the same tests set.
The main reason for that is the v-model directive that was previously marked as covered, but is now mostly uncovered.

It looks like if the model value is not entirely re-assigned in the child component, v-model is not considered covered. See reproduction below.

I understand that v-model is meant for 2-way binding, and in case of 1-way binding I could actually use a simple prop.
But my application architecture is composed of many nested bloc components and they all have the same structure, using v-model. Some of these blocks don't always reassign their model value, but I don't think it should be considered as uncovered code.

Is there a way to revert to the previous behavior ? Otherwise, can I exclude all v-model directives from code coverage ?

Reproduction

ChildComponent.vue

<template>
  <div>{{ model.data }}</div>
</template>

<script setup lang="ts">
import { onBeforeMount } from "vue";

const props = defineProps<{
  reassignFullObject?: boolean;
}>();
const model = defineModel<{ data: string }>({ required: true });

onBeforeMount(() => {
  if (props.reassignFullObject) {
    model.value = { data: model.value.data + " modified" };
  } else {
    model.value.data = model.value.data + " modified";
  }
});
</script>

ParentComponent.vue

<template>
  <div>
    <ChildComponent
      v-model="someData1"
      :reassign-full-object="false"
    />
    <ChildComponent
      v-model="someData2"
      :reassign-full-object="true"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

const someData1 = ref({ data: "data1" });
const someData2 = ref({ data: "data2" });
</script>

test

import { describe, it, expect } from "vitest";
import { flushPromises, mount } from "@vue/test-utils";
import ParentComponent from "@/components/blocs/ParentComponent.vue";
import { nextTick } from "vue";

describe("ParentComponent", () => {
  it("renders", async () => {
    const wrapper = mount(ParentComponent);
    await nextTick();
    await flushPromises();
    expect(wrapper.html()).toContain("data1 modified");
    expect(wrapper.html()).toContain("data2 modified");
  });
});
Image

System Info

System:
    OS: Linux 5.15 Ubuntu 24.04.2 LTS 24.04.2 LTS (Noble Numbat)
    CPU: (16) x64 13th Gen Intel(R) Core(TM) i7-1360P
    Memory: 7.79 GB / 19.54 GB
    Container: Yes
    Shell: 5.9 - /usr/bin/zsh
  Binaries:
    Node: 22.19.0 - /usr/bin/node
    npm: 11.5.2 - /usr/bin/npm
  npmPackages:
    @vitejs/plugin-vue: 6.0.1 => 6.0.1 
    @vitejs/plugin-vue-jsx: 5.1.1 => 5.1.1 
    @vitest/coverage-v8: 4.0.10 => 4.0.10 
    @vitest/ui: 4.0.10 => 4.0.10 
    vite: 7.1.12 => 7.1.12 
    vitest: 4.0.10 => 4.0.10 
    vitest-sonar-reporter: 3.0.0 => 3.0.0

Used Package Manager

npm

Validations

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions