LoginSignup
3
0

More than 1 year has passed since last update.

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

Posted at

問題

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

以下、VScodeでのエラーメッセージ
スクリーンショット 2022-01-15 19.14.58.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インターフェイスをインポートする。

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

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

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

参考記事

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0