DEV Community

Cover image for Testing vue-apollo Components with Jest

Testing vue-apollo Components with Jest

Natalia Tepluhina on August 17, 2018

Recently I've been working on some tests for Vue single-file components with vue-apollo queries and mutations. Unfortunately, there are not so many...
Collapse
 
danroc profile image
Daniel da Rocha

That’s a great article, Natalia, thank you.

Did you ever have to test Vue components with <apollo-query> components in it though?
How would you encapsulate the data if the query is not in the apollo property?

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

To be honest (and it's completely my personal preference) I prefer not to use Vue Apollo components. I know it's a valid way of doing things and it's a default for e.g. React; but I like my query logic separated from the template.

Perhaps I should try to test components with <ApolloQuery> and update an article though, thank you for the great question.

Collapse
 
danroc profile image
Daniel da Rocha

Yeah, I am starting to think that the benefits do not compensate the issues with both testing and with Storybook.

I am on the verge of ditching them altogether. I find it also frustrating the lack of documentation about it; while at the same time that the vue-apollo docs express the wonders of using these components, they fail to mention how to test them.

Recently there was a recommendation to use <apollo-query> components with inline gql-formatted query, as "best practice". But it stopped there, and any component written this way seems to be untestable with current tools.

Thread Thread
 
tavo1987 profile image
Edwin Ramírez • Edited

Hi Daniel, I have the same problem, do you have any progress on this?

Thread Thread
 
danroc profile image
Daniel da Rocha

No, I just ditched the components alltogether.

I am also thinking of moving on from vue-apollo, especially when Vue3 comes around. Maybe try Villus?

Thread Thread
 
tavo1987 profile image
Edwin Ramírez • Edited

I haven't tried it yet but it looks like an interesting option.

I was able to test the component is rendered and receive the correct properties, what I can't achieve is mock the data that the component returns.

My tests look like this so far:

Hello.vue

<template>
    <ApolloQuery
            v-test="{ id: 'apollo-query' }"
            :query="require('@/graphql/MY_QUERY').default"
            :variables="{ id: 1 }"
            :notify-on-network-status-change="true"
          >
      <template v-slot="{ result: { loading, error, data } }">
        <div v-if="loading">
          Loading...
        </div>
        <div v-else-if="error">An error occurred</div>
        <div v-else-if="data">{{ data.hello }}</div>
        <div v-else>No result :(</div>
      </template>
    </ApolloQuery>
</template>

Hello.spec.js

import { mount, createLocalVue } from '@vue/test-utils'
import VueApollo from 'vue-apollo'
import Hello from '@/components/Hello'

const localVue = createLocalVue()
localVue.use(VueApollo)


describe('Hello.vue', () =>() {
    test('renders an ApolloQuery component', () =>{
        const wrapper = moun(Hello, {
            localvue,
            // To remove error in render: "TypeError: Cannot read property 'loading' of undefined"
            // More info about this https://github.com/vuejs/vue-apollo/issues/609 
            $apolloData: {
              loading: false
            },
        })

        // I'm using a custom directive v-test that transform this v-test="{id: 'foo'}" to [data-test-id=foo]
        const apolloQuery = wrapper.find('[data-test-id=apollo-query]')

        expect(apolloQuery.exists()).toBe(true)
        expect(apolloQuery.props().query).toBe(require('@/graphql/MY_QUERY').default)
        expect(apolloQuery.props().variables).toEqual({ id: 1 })
        expect(apolloQuery.props().notifyOnNetworkStatusChange).toBeTruthy()
    })
})
Collapse
 
austinbv profile image
Austin Vance

You have a great series of blog posts.

One thing we have struggled to test is dynamic queries or variables in smart queries.

Vue.extend({
  name: 'TestComponent',
  apollo: {
    human: {
      query: gql`query GetHumans($ID: ID!) {
      human(id: $id) {
        name
        height
      }
    }`,
    },
    variables() {
      return {
        id: this.$route.params.id,
      };
    },
  },
});

I would love to write a test that is something like


it('gets queries for the correct user', () => {
  mount(TestComponent, {
    mocks: {
      params: {
        id: "1"
      }
    }
  })

  // expect query to be called with an ID of "1"
})

It seems like because vue-apollo isn't mounted in test we cant test the variables function directly or indirectly as it doesn't exist on the vm. Is there a way to get at the apollo section of the vm in test?

Cheers!

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

You can try to play with mocking $apollo object on mounting. I've added this section to Vue Apollo docs recently: vue-apollo.netlify.com/guide/testi...

Please let me know if it's useful for your case! If it's not, we'll try to figure out the best way to do it

Collapse
 
austinbv profile image
Austin Vance • Edited

I decided to test the variables functions directly.

the winning incantation is

const wrapper = mountVue(GroupsIndex, {
  mocks: {
    $route: {
      params: { userId: 6 },
      query: { zip: 50500 },
    },
  },
});

// @ts-ignore
expect(wrapper
  .vm
  .$options
  .apollo
  .groups
  .variables
  .bind(wrapper.vm)().zip
).toEqual(50500);

// @ts-ignore
expect(
  wrapper.
  vm.
  $options.
  apollo.
  groups.
  variables.
  bind(wrapper.vm)().userId
).toEqual(6);

I'm working a mock provider that provides access to stuff thing this so it's a bit less of a dig to test

Thanks!

Thread Thread
 
austinbv profile image
Austin Vance

I posted a short blog post for people about this

dev.to/focusedlabs/testing-apollos...