'How to unit test standalone Vue composition

I have a setup similar as the example in the docs where my composition lives in a separate file from my component as follows:

// composition.js
import { onMounted } from '@vue/composition-api';

export default function useComposition() {
  onMounted(() => {
    console.log('Hello, world!');
  });
}
// component.vue
<template>...</template>

<script>
import { createComponent } from '@vue/composition-api';

export default createComponent({
  setup() {
    useComposition();
  }
})
</script>

I would like to write a separate (Jest based) test file for just the composition.js file. However, when calling the composition directly, Vue will error out (expectedly):

// composition.test.js

import useComposition from './composition';

describe('Composition', () => {
  it('Works', () => {
    useComposition();
    // Error: [vue-composition-api] "onMounted" get called outside of "setup()"
  });
});

I've tried mounting a mock composition API based component in order to provide a setup() function, but having some trouble getting it to work:

import { mount, createLocalVue } from '@vue/test-utils';
import VueCompositionAPI, { createComponent } from '@vue/composition-api';
import useComposition from './composition';

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

describe('Composition', () => {
    it('Works', () => {
        const mockComponent = createComponent({
            setup() {
                useComposition();

                return h => h('div');
            }
        });

        mount(mockComponent, { localVue });
        // [Vue warn]: Failed to mount component: template or render function not defined.
    });
});

Does anybody have any bright ideas on how to get this to work so I can write tests for my modular compositions?



Solution 1:[1]

If anyone is looking for an equivalent of react-hooks-testing-library for Vue composables, you can use this package

https://github.com/wobsoriano/vue-test-composables

Here's an example with vue-query:

import { useQuery, useQueryProvider } from 'vue-query'
import { renderComposable } from 'vue-test-composables'

function useUser() {
  return useQuery('user', () =>
    fetch('/api/user').then(
      res => res.json,
    ),
  )
}

test('useUser', async() => {
  const { result, waitFor } = renderComposable(() => useUser(), {
    provider() {
      useQueryProvider()
    },
  })

  await waitFor(() => result.isSuccess.value)

  await expect(result.data.value).resolves.toMatchObject({
    id: 1,
    username: 'johndoe',
    email: '[email protected]',
  })
})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 wobsoriano