vuejs / vue-test-utils-typescript-example

Example project using TypeScript, Jest + vue-test-utils together
61 stars 31 forks source link

Wrapper type correct? #3

Closed tuvokki closed 5 years ago

tuvokki commented 5 years ago

Hi, i a real-world scenario I have the following class in my vue file (adapted to the example provided in this project):

<template>
...
</template>

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
import { Prop } from 'vue-property-decorator';

@Component({})
export default class HelloWorld extends Vue {
    @Prop()
    private msg: string;
}
</script>

<style scoped>
...
</style>

My test is as follows:

import { shallowMount } from '@vue/test-utils';

describe('HelloWorld.vue', () => {
    let wrapper: any; // <-- any is the wrong type here!!
    let msg: string;

    beforeEach(() => {
        msg = 'new message';
        wrapper = shallowMount<HelloWorld>(HelloWorld, {
            propsData: { msg },
        });
    });

    it('renders props', () => {
        expect(wrapper.text()).toMatch(msg);
    });
});

I have typed the wraper as any here because that works (i.e. does not give a red squiggly line in my editor), but the shallowMount method returns a Wrapper<Wrapper>. Typing the wrapper as any does not give me the benefits of code completion etc.

As what type should I type the wrapper so that I can use the correct typing in the remainder of the test? I tried Wrapper, Wrapper<Wrapper>, Wrapper<HelloWorld> but nothing worked.

eddyerburgh commented 5 years ago

Pass a Vue class type to the Wrapper type:

import { shallowMount, Wrapper } from "@vue/test-utils";
import Vue from "vue";

let wrapper: Wrapper<Vue>

You can see the full typings for Vue Test Utils in the @vue/test-utils source code

ClarissaAudrey commented 3 years ago

Hey, this thread is very useful. However this type made me unable to access any of my component's property. Any idea how to fix this?

igonzalezprs commented 3 years ago

@ClarissaAudrey Quoting user @ktsn (here):

wrapper.vm is typed as Vue because TypeScript cannot know the component type in .vue files - we usually annotate them like this to avoid compilation error https://github.com/Microsoft/TypeScript-Vue-Starter#single-file-components. If the components are written in normal .ts file, wrapper.vm should be inferred correctly.

Vetur (and probably WebStorm) have their own language service which can deal with .vue files but they only affect .vue files. That means components imported in .vue are typed correctly while components imported in .ts are not.

To be available typed components in .ts, we should use TypeScript plugin vue-ts-plugin or generate .d.ts for each .vue file by using vuetype. But they are still experimental and might not be able to be used in practical projects.

If you don't mind not having intellisense for your component's properties, you can try to do it this way (suggested by user @3nuc):

import { shallowMount, Wrapper } from "@vue/test-utils";

describe("test", () => {
  let wrapper: Wrapper<YourComponentHere & { [key: string]: any }>;
  it("does something", () => {
    expect(wrapper.vm.someThingWhatever).toBe(true);
  });
});