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作成に時間がかかった為記載してみました。