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
 
tavo1987 profile image
Edwin Ramírez

Hi Natalia, If you do it would be very helpful and should also be in the documentation

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...