typescriptvue.jsvuejs3vue-test-utilsvitest

Testing vue3 computed properties with TypeScript SFC


I am trying to write a test, using vitest, to assert a computed property in a vue3 component that is defined with script setup.

Consider a simple component:

// simple.vue
<script lang="ts" setup>
import { computed } from 'vue';

const hello = computed((): string => {
  return 'Hello';
});
</script>

<template>
  {{ hello }}
</template>

My test is like this:

describe('Hello', () => {
  it('should compute hello', () => {
    const wrapper = mount(Hello);
    expect(wrapper.vm.hello).toBe('Hello');
  });
});

This test actually works as expected when run using vitest, so functionally things seem to be working well.

However, VSCode cannot see the computed properties on the vm object:

enter image description here

It is able to see normal properties (e.g., those defined with the defineProps macro). Is this just a problem with VSCode-specific tooling, or is there another way I should be going about testing computed properties in vue3 components?

If this is the preferred method, is there a way to pull in the types of the computed properties (similar to how the types of the defined props seem to be pulled in)?

I have tried the technique described in this Vue Testing Handbook, but this doesn't work at all and I assume it must be specific to vue2.


Solution

  • From Vue docs:

    Components using <script setup> are closed by default - i.e. the public instance of the component, which is retrieved via template refs or $parent chains, will not expose any of the bindings declared inside <script setup>.

    This also affects the type of the wrapper.vm in Vue Test Utils, such that it only includes public or exposed props of the <script setup> component.

    In your case, use the defineExpose() compiler macro to expose hello:

    <script lang="ts" setup>
    import { computed } from 'vue';
    
    const hello = computed((): string => {
      return 'Hello';
    });
         👇
    defineExpose({ hello });
    </script>
    

    screenshot