Testing vue-apollo Components with Jest
Tags: vue, graphql, testing
Published: 2018-08-17 12:01:00

---
title: Testing vue-apollo Components with Jest
published: true
cover_image: https://thepracticaldev.s3.amazonaws.com/i/qnkal6v9mtwxn79y0agg.png
description: My approach to testing Vue components containing vue-apollo queries and mutations with Jest
tags: #vue #graphql #testing
---
Recently I've been working on some tests for Vue single-file components with [vue-apollo](https://github.com/Akryum/vue-apollo) queries and mutations. Unfortunately, there are not so many guides on the topic so I decided to share my experience. This article doesn't pretend to be a best-practice but I hope it will help people to start testing [GraphQL](https://www.graphql.com/) + [Apollo](https://www.apollographql.com/) in Vue with Jest.

> vue-apollo is a library that integrates Apollo in Vue components with declarative queries

##Project overview

I added vue-apollo tests to my simple [demo application](https://github.com/NataliaTepluhina/VV-GraphQL-workshop). It contains an `App.vue` component with one query for fetching the list of Vue core team members and two mutations: one to create a new member entry and another to delete it. Full GraphQL schema could be found in `apollo-server/schema.graphql` file.

For component unit testing I used [Jest](https://jestjs.io/) and [vue-test-utils](https://github.com/vuejs/vue-test-utils). 

If you have a look at `tests` folder, you might notice project already had a basic test for `App.vue`:

```js
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuetify from 'vuetify';
import App from '../../src/App';

describe('App', () => {
  let localVue;
  beforeEach(() => {
    localVue = createLocalVue();
    localVue.use(Vuetify, {});
  });

  test('is a Vue instance', () => {
    const wrapper = shallowMount(App, { localVue });
    expect(wrapper.isVueInstance()).toBeTruthy();
  });
});
```
This project uses Vuetify, so I added it to `localVue` to prevent warnings about its custom components. Also, there is a simple check if component is a Vue instance. Now it's time to write some vue-apollo-related tests!

##Simple tests

At first, when I was searching for any pointers about how to test vue-apollo queries and mutations, I found this comment by vue-apollo author, [Guillaume Chau](https://guillaume-chau.info/)

{% github https://github.com/Akryum/vue-apollo/issues/244#issuecomment-375646919 %}

So I decided to start testing my component using this advice. Let's create a new test case:

```js
  test('displayed heroes correctly with query data', () => {
    const wrapper = shallowMount(App, { localVue });
  });
```

After this we need to save a correct response to the wrapper data and check if component renders correctly. To get the response structure we can check a query in project schema:

```js
type VueHero {
    id: ID!
    name: String!
    image: String
    github: String
    twitter: String
}

type Query {
  allHeroes: [VueHero]
}
```
So `allHeroes` query shoud return an array of `VueHero` entries and every single field type is specified. Now it's easy to mock the data inside our wrapper:

```js
wrapper.setData({
  allHeroes: [
    {
      id: 'some-id',
      name: 'Evan You',
      image:
        'https://pbs.twimg.com/profile_images/888432310504370176/mhoGA4uj_400x400.jpg',
      twitter: 'youyuxi',
      github: 'yyx990803',
    },
  ],
});
```
Awesome, our data is mocked! Now it's time to check if it's rendered correctly. For this purpose I used a Jest snapshot feature: a test expects that component will match the given snapshot. Final test case looks like this:

```js
test('displayed heroes correctly with query data', () => {
    const wrapper = shallowMount(App, { localVue });
    wrapper.setData({
      allHeroes: [
        {
          id: 'some-id',
          name: 'Evan You',
          image:
            'https://pbs.twimg.com/profile_images/888432310504370176/mhoGA4uj_400x400.jpg',
          twitter: 'youyuxi',
          github: 'yyx990803',
        },
      ],
    });
    expect(wrapper.element).toMatchSnapshot();
});
```
If you run it a couple of times, you will see test passes (nothing surprising here, with a given set of data component renders in the same way every time). This is how the heroes grid in the snapshot looks like at this moment:

```html
<v-layout-stub
        class="hero-cards-layout"
        tag="div"
        wrap=""
      >
        <v-flex-stub
          class="hero-cards"
          md3=""
          tag="div"
          xs12=""
        >
          <v-card-stub
            height="100%"
            tag="div"
          >
            <v-card-media-stub
              height="250px"
              src="https://pbs.twimg.com/profile_images/888432310504370176/mhoGA4uj_400x400.jpg"
            />
             
            <v-card-title-stub
              class="hero-title"
              primarytitle="true"
            >
              <div>
                <h3
                  class="title"
                >
                  Evan You
                </h3>
                 
                <div
                  class="hero-icons"
                >
                  <a
                    href="https://github.com/yyx990803"
                    target="_blank"
                  >
                    <i
                      class="fab fa-github"
                    />
                  </a>
                   
                  <a
                    href="https://twitter.com/youyuxi"
                    target="_blank"
                  >
                    <i
                      class="fab fa-twitter"
                    />
                  </a>
                </div>
              </div>
            </v-card-title-stub>
             
            <v-card-actions-stub>
              <v-spacer-stub />
               
              <v-btn-stub
                activeclass="v-btn--active"
                icon="true"
                ripple="true"
                tag="button"
                type="button"
              >
                <v-icon-stub>
                  delete
                </v-icon-stub>
              </v-btn-stub>
            </v-card-actions-stub>
          </v-card-stub>
        </v-flex-stub>
      </v-layout-stub>
```

Let's move to mutation tests now. We're going to check if `$apollo` method `mutate` is called in our Vue component method `addHero()`. There is no data needed to perform this check, because we don't expect any kind of a result here: we just want to be sure a mutation was called. In a new test case we mock `$apollo` as shown in the comment above, call `addHero()` method and then expect `mutate` to be called:

```js
  test('called Apollo mutation in addHero() method', () => {
    const mutate = jest.fn();
    const wrapper = mount(App, {
      localVue,
      mocks: {
        $apollo: {
          mutate,
        },
      },
    });
    wrapper.vm.addHero();
    expect(mutate).toBeCalled();
  });
```

Now we have simple tests coverage for GraphQL query and mutation.

##Mocking GraphQL schema

I really wanted to see how my queries are called in a more 'real-life' environment and I've found the solution in [this chapter](https://www.apollographql.com/docs/graphql-tools/mocking.html) of Apollo docs. The idea is to mock the actual GraphQL schema and call queries and mutations against it.

This part is a bit more complicated and requires more work but from my point of view this way of testing GraphQL calls give you more precise results. Let's start with creating a new `mockSchema.js` file in `tests` folder and importing required method from `graphql-tools`:

```js
import { makeExecutableSchema } from 'graphql-tools';
```
To create a schema I simply copied a part with all types from `apollo-server/schema.graphql`:

```js
const schema = `
  type VueHero {
    id: ID!
    name: String!
    image: String
    github: String
    twitter: String
  }

  input HeroInput {
    name: String!
    image: String
    github: String
    twitter: String
  }


  type Query {
    allHeroes: [VueHero]
  }

  type Mutation {
    addHero(hero: HeroInput!): VueHero!
    deleteHero(name: String!): Boolean
  } 
`;
```
Now we can create executable schema with imported `makeExecutableSchema` method. We should pass our schema as `typeDefs` parameter:

```js
export default makeExecutableSchema({
  typeDefs: schema,
});
```
One more thing we need for testing is adding mock functions to schema. Let's do it in our `App.spec.js` file:

```js
import { addMockFunctionsToSchema } from 'graphql-tools';
import schema from '../mockSchema';
...
describe('App', () => {
  let localVue;
  beforeEach(() => {
    localVue = createLocalVue();
    localVue.use(Vuetify, {});
    addMockFunctionsToSchema({
      schema,
    });
  });
  ...
}):
```
Now we're ready to test the query.

##Testing query with a mocked schema

Let's create a new test case and add a query string to it (you can always check your schema if you're not sure what format should query have):

```js
const query = `
  query {
    allHeroes {
      id
      name
      twitter
      github
      image
    }
  }
`;
```
Please notice we don't use `gql` template literal tag from Apollo here because we will do GraphQL call without including Apollo. We also will set component data after resolving a promise:

```js
graphql(schema, query).then(result => {
  wrapper.setData(result.data);
  expect(wrapper.element).toMatchSnapshot();
});
```
>At this moment you can delete a previous snapshot and comment/delete a previous query test case

The whole test case should look like this:

```js
test('called allHeroes query with mocked schema', () => {
	const query = `
	  query {
	    allHeroes {
	      id
	      name
	      twitter
	      github
	      image
	    }
	  }
	`;
	const wrapper = shallowMount(App, { localVue });
	graphql(schema, query).then(result => {
	  wrapper.setData(result.data);
	  expect(wrapper.element).toMatchSnapshot();
	});
});
```
After running it if you check the snapshot file, you might realise all response fields are equal to 'Hello World'. Why does it happen?

The issue is without mocking GraphQL resolvers we will always have a generic response (number of entries will always be 2, all integers will be negative and all strings are `Hello World`). But this generic test is good enough to check response structure.

>GraphQL resolvers are a set of application specific functions that interact with your underlying datastores according to the query and mutation operations described in your schema.

If you check `apollo-server/resolvers` file, you can see that real resolvers are working with data in our database. But test environment doesn't know anything about database, so we need to mock resolvers as well.

##Realistic mocking

Let's create `mockResolvers.js` file in our `test` folder. First thing to add there is a resolver for `allHeroes` query:

```js
export default {
  Query: {
    allHeroes: () => [
      {
        id: '-pBE1JAyz',
        name: 'Evan You',
        image:
          'https://pbs.twimg.com/profile_images/888432310504370176/mhoGA4uj_400x400.jpg',
        twitter: 'youyuxi',
        github: 'yyx990803',
      },
    ],
  },
};
```
Now this query will always return the same array with a single entry. Let's add resolvers to the schema in `mockSchema.js`:

```js
import resolvers from './mockResolvers';
...
export default makeExecutableSchema({
  typeDefs: schema,
  resolvers,
});
```
We also need to change `addMockFunctionsToSchema` call in out test suite: in order to keep resolvers not overwritten with mock data, we need to set `preserveResolvers` property to `true`

```js
addMockFunctionsToSchema({
  schema,
  preserveResolvers: true,
});
```
Delete previous snapshot and try to run a test. Now we can see a realistic data provided with our resolver in a new snapshot.

We can also add other expectation, because right now we know an exact response structure. Say, we can check if `allHeroes` array length is equal 1.

Final version of this test case:

```js
test('called allHeroes query with mocked schema', () => {
	const query = `
	  query {
	    allHeroes {
	      id
	      name
	      twitter
	      github
	      image
	    }
	  }
	`;
	const wrapper = shallowMount(App, { localVue });
	graphql(schema, query).then(result => {
	  wrapper.setData(result.data);
	  expect(result.data.allHeroes.length).toEqual(1);
	  expect(wrapper.element).toMatchSnapshot();
	});
});
```

##Testing mutation with mocked schema

Now let's test a mutation with our mocked schema too. In the new test case create a mutation string constant:

```js
test('called Apollo mutation in addHero() method', () => {
	const mutation = `
	    mutation {
	      addHero(hero: {
	        name: "TestName",
	        twitter: "TestTwitter",
	        github: "TestGithub",
	        image: "TestImage",
	      }) {
	        id
	        name
	        twitter
	        github
	        image
	      }
	    }
	`;
});
```
We will pass custom strings as parameters and await for the response. To define this response, let's add a mutation resolver to our `mockResolvers` file:

```js
Mutation: {
	addHero: (_, { hero }) => ({
	  id: 1,
	  name: hero.name,
	  image: hero.image || '',
	  twitter: hero.twitter || '',
	  github: hero.github || '',
	}),
},
```
So our `addHero` mutation will return exactly the same hero we passed as its parameter with an `id` equal to `1`.

Now we can add a GraphQL query to the test case:

```js
graphql(schema, mutation).then(result => {
  expect(result.data.addHero).toBeDefined();
  expect(result.data.addHero.name).toEqual('TestName');
});
```

We didn't check changes to the Vue component instance here but feel free to modify component data with a response.

Full mutation test case:

```js
test('called addHero mutation with mocked schema', () => {
	const mutation = `
	    mutation {
	      addHero(hero: {
	        name: "TestName",
	        twitter: "TestTwitter",
	        github: "TestGithub",
	        image: "TestImage",
	      }) {
	        id
	        name
	        twitter
	        github
	        image
	      }
	    }
	`;
	graphql(schema, mutation).then(result => {
	  expect(result.data.addHero).toBeDefined();
	  expect(result.data.addHero.name).toEqual('TestName');
	});
});
```

Now our test suit has a basic test for `mutate` call and two 'advanced' tests with a mocked GraphQL schema.

If you want to check the project version with all tests, there is a [`testing` branch](https://github.com/NataliaTepluhina/VV-GraphQL-workshop/tree/testing) here.