【TS + jest + vue-test-utils】コンポーネントのメソッドが使えない件について

# 問題
Vue.jsのコンポーネントのユニットテストをTypeScript+Jest+vue-test-utilsで書いていた。
しかし、テストコードから、コンポーネントで定義したはずのメソッドが使用できなかった。

以下、VScodeでのエラーメッセージ
![スクリーンショット 2022-01-15 19.14.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936748/af17f056-75e6-a6bd-a8c4-526163efbe8e.png)



# 環境
Vue.js 2.6.11
TypeScript 4.1.5
jest 24.9.0
@vue/test-utils 1.0.3

# 該当のソースコード
```Login.vue
<template>
  <div class="login">
    <h2>ログイン</h2>
    <ValidationObserver ref="observer" v-slot="{ invalid }">
      <v-form ref="form" lazy-validation>
        <!-- errors -->
        <div class="errors" v-if="errors.length !== 0">
          <ul>
            <li v-for="e in errors" :key="e"><v-alert type="error" dense text>{{ e }}</v-alert></li>
          </ul>
        </div>
        <ValidationProvider v-slot="{ errors }" name="メールアドレス" rules="required|email|max:250">
          <v-text-field
            v-model="user.email"
            id="email"
            :counter="250"
            label="メールアドレス"
            :error-messages="errors"
            required
          ></v-text-field>
        </ValidationProvider>
        <ValidationProvider v-slot="{ errors }" name="パスワード" rules="required|min:6">
          <v-text-field
            v-model="user.password"
            type="password"
            id="password"
            label="パスワード"
            :error-messages="errors"
            required
          ></v-text-field>
        </ValidationProvider>
        <v-btn color="primary" class="login" @click="login" :disabled="invalid" data-cy-login-button>ログイン</v-btn>
      </v-form>
    </ValidationObserver>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import { required, min, email, max } from 'vee-validate/dist/rules';
import { extend, ValidationObserver, ValidationProvider, setInteractionMode } from 'vee-validate';
import User from '@/modules/users'

setInteractionMode('eager');

extend('min', {
  ...min,
  message: '{_field_}は{length}文字以上で入力してください',
});

extend('required', {
  ...required,
  message: '{_field_}を入力してください',
});

extend('max', {
  ...max,
  message: '{_field_}は{length}文字以内で入力してください',
});

extend('email', {
  ...email,
  message: '{_field_}は正しい形式で入力してください',
});

type user = {
  email: string,
  password: string
};

@Component({
  components: {
    ValidationObserver,
    ValidationProvider
  }
})

export default class Login extends Vue {
  private user: user = { email: '', password: '' };
  private errors: string[] = [];

  public login(): void {
    User.login(this.user, this);
  }
}
</script>

<style scoped>
h2 {
  text-align: center;
}

.login {
  max-width: 500px;
  text-align: center;
  margin: 0 auto;
  margin-top: 30px;
  padding-left: 10px;
  padding-right: 10px;
}
</style>
```

```login.spec.ts
import { mount, shallowMount, createLocalVue } from '@vue/test-utils';
import Login from '@/views/auth/Login.vue';
import nextTick from 'vue';
import Vuex from 'vuex';
import store from '@/store/index';
import VueRouter from 'vue-router';
import router from '@/router/index';
import axios from 'axios';

const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(VueRouter);

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

describe('Login.vue', () => {
  describe('Data', () => {
    it('sets user', () => {
      const wrapper = shallowMount(Login, { localVue });
      expect(wrapper.vm.$data.user.email).toBe('');
      expect(wrapper.vm.$data.user.password).toBe('');
    })

    it('sets errors', () => {
      const wrapper = shallowMount(Login, { localVue });
      expect(wrapper.vm.$data.errors).toEqual([]);
    })
  })

  describe('Methods', () => {
    describe('login', () => {
      const mockUser = { id: 1, name: 'foo', email: 'foo@bar.com' };
      const resp_200 = { data: { data: mockUser }, status: 200 };

      describe('when status is 200', () => {
        it('sets flash', async () => {
          mockedAxios.post.mockResolvedValueOnce(resp_200);
          const wrapper = shallowMount(Login, { store, router, localVue });
          await wrapper.vm.login();
          expect(wrapper.vm.$store.state.flash).toEqual({ msg: 'ログインしました', type: 'success' });
        })
      })
    })
  })
})
```

# 解決方法

Wrapperインターフェイスをインポートする。

```typescript:Login.vue
import { Wrapper } from '@vue/test-utils'
```

次に、wrapperオブジェクトを作成している箇所を以下のように直す。

```typescript:Login.vue
const wrapper: Wrapper<Login & { [key: string]: any}> = shallowMount(Login, { store, router, localVue });
```



# 参考記事

https://stackoverflow.com/questions/57021241/method-isnt-available-in-unit-test