Nuxt+CompositionAPIのprovideとinjectに関するjest


初めに

自分のメモ用として記載しています。
端折って書いている場所もある為、ご了承ください。

provideとinjectに関しましては以下の記事や別の記事を参考にしてください。
https://qiita.com/0622okakyo/items/9d3d264f0417a1cb4923

provideとinjectを使った箇所のテスト

例えば以下のようなコンポーネントがあったとします。

親コンポーネント側でprovideを呼び出します。

親コンポーネント.vue
<template>
...
</template>

<script lang="ts">
import {
  defineComponent,
  provide,
  inject
} from '@vue/composition-api';
import {
  Key,
  Context,
  use
} from '@/components/〜/compositions/use〜.ts';

export default defineComponent({
  setup(_props, context) {
    onMounted(async () => {
      await fetchCompanyList();
    });

    provide(Key, use(context));

    const { state } = inject(
      ~Key
    ) as ~Context;

    return { state };
  }
})
</script>

子コンポーネントではinjectで状態の呼び出しなどを行なっているとします。

子コンポーネント.vue
<template>
...
</template>

<script lang="ts">
import {
  defineComponent,
  inject
} from '@vue/composition-api';
import {
  Key,
  Context,
  use
} from '@/components/〜/compositions/use〜.ts';

export default defineComponent({
  setup(_props, context) {
    const { state } = inject(
      ~Key
    ) as ~Context;

    return { state };
  }
})
</script>

composition api側ではAPIを呼び出すメソッドやKeyの設定などを行なっています。

compositions.ts
import { InjectionKey, reactive } from '@vue/composition-api';
import { storageModule } from '@/store';

export const use~ = (context: any) => {
  const $axios = context.root.$root.context.$axios;
  const state = reactive<{
    ~
  }>({
    ~
  });

  const fetch~ = async () => {
    cosnt params = {}
    await $axios
      .$get('~', { params })
      .then((res: Type) => {
        state.~ = res;
      });
  };

  return {
    state,
    fetch~
  };
};

export type ~Context = ReturnType<typeof use~>;

export const ~Key: InjectionKey<~Context> = Symbol(
  '~Context'
);

jestでテストを書く

*Vuetifyをimportしていますが、気にしないでください
親側のjestは以下のような記載で可能です。

親コンポーネントのjest.spec.ts
import Vuetify from 'vuetify';
import { mount, createLocalVue } from '@vue/test-utils';
import VueCompositionApi from '@vue/composition-api';
import * as composition from '@/components/~/compositions/use~';

import ~ from '@/components/~/~.vue';

const localVue = createLocalVue();
localVue.use(VueCompositionApi);

let vuetify: any;
let wrapper: any;

let searchCompany: jest.Mock;
let fetchCompanyList: jest.Mock;

beforeAll(() => {
  vuetify = new Vuetify();
  jest.mock('@/components/〜/compositions/use〜');
  hogeMethod = jest.fn();
  jest.spyOn(composition, 'use〜').mockReturnValue({
    state: {
      ...
    },
    hogeMethod
  }); // compositionのメソッドやstateはmock化します。
  const mountFunction = (options: any) => {
    return mount(, {
      localVue,
      vuetify,
      ...options
    });
  };
});

describe('', () => {
  describe('template', () => {
    
  });
});

ただ、子コンポーネントは親コンポーネントと違い上記の記載だけではテストが失敗します。
理由としましては、親のコンポーネントではprovideしているのでinjectしているstateなどが
読み込めるのですが、子コンポーネントではinjectのみしているのでinjectの中身が確認出来ず、
テストが失敗します。ですので、provideをmockしてあげる必要があります。

子コンポーネントのjest.spec.ts
import Vuetify from 'vuetify';
import { mount, createLocalVue } from '@vue/test-utils';
import VueCompositionApi from '@vue/composition-api';
import * as composition from '@/components/〜/compositions/〜';
import { Key } from '@/components/〜/compositions/〜';

import  from '@/components/〜/〜.vue';

const localVue = createLocalVue();
localVue.use(VueCompositionApi);

let vuetify: any;
let wrapper: any;

beforeAll(() => {
  vuetify = new Vuetify();
  const provide_mock = {
    [Key as symbol]: {
      state: {
        
      },
    } // provideするstateやmethodを記載しましょう。
  }; // ここでprovideするmockを作成しています。
  jest.mock('@/components/〜/compositions/use〜');
  jest.spyOn(composition_list, 'use〜').mockReturnValue({
    
  });
  const mountFunction = (options: any) => {
    return mount(, {
      localVue,
      vuetify,
      ...options
    });
  };
  const options = {
    provide: provide_mock, // 先ほどのmockをここで設定しています。
  };
  wrapper = mountFunction(options);
});

describe('', () => {
  
});

*composition側のテスト記載例

composition.spec.ts
import VueCompositionApi from '@vue/composition-api';
import { createLocalVue } from '@vue/test-utils';
import {  } from '@/components/〜/compositions/〜';

const localVue = createLocalVue();
localVue.use(VueCompositionApi);

jest.mock('@/store', () => ({
  storageModule: {
    ticket: 'hoge'
  }
})); // storeのmockなどはこのように設定することが可能です。

describe('useCompanyList', () => {
  const context = {
    root: {
      $root: {
        context: {
          $axios: {
            $get: jest.fn(),
            $post: jest.fn(),
            $put: jest.fn(),
            $delete: jest.fn()
          }
        }
      }
    }
  }; // $axiosのmockです。

  const {
    ~
  } = use~(context);

  test('state', () => {
    ~
  });
});

最後に

個人的にはprovideとinjectのjest作成に時間がかかった為記載してみました。