vendredi 15 novembre 2019

Testing client resolvers in Apollo Client

I have the following tiny fullstack Apollo project with the following schema:

const { gql } = require('apollo-server');

const typeDefs = gql`
  type Query {
    books: [Book]
  }

  type Book {
    id: Int
    name: String
    published: Int
    author: Author
  }

  type Author {
    id: Int
    name: String
  }
 `;

module.exports = typeDefs;

I created a query for fetching the books:

export const GET_BOOKS = gql`
  query GetBooks {
    books {
      id
      name
      published
      author {
        id
        name
      }
    }
  }
`;

I created a client resolver that extends a new query which provides the authors:

import gql from 'graphql-tag';
import {GET_BOOKS} from "./components/Books";

export const typeDefs = gql`
  extend type Query {
    authors: [Author]
  }
`;

const getAuthors = (books) => {
  return books.reduce((authors, {author}) => {
      return authors.set(author.id, author);
  }, new Map());
};

export const resolvers = {
  Query: {
    authors: async (_, __, { client }) => {
      const {data} = await client.query({query: GET_BOOKS});
      return [...getAuthors(data.books)].map(([, author]) => author);
    },
  },
};

I have the component Authors that shows the authors based on the client query:

import React from 'react';
import { useQuery } from '@apollo/react-hooks';
import gql from 'graphql-tag';
import ShowDataComponent from "./ShowDataComponent";

export const GET_AUTHORS = gql`
  query GetAuthors {
    authors @client {
      id
      name
    }
  }
`;

export default function Authors() {
  const { data, loading, error } = useQuery(GET_AUTHORS);
  if (loading) return <div>Loading ...</div>;
  if (error) return <ShowDataComponent label="Authors" data={error}/>;

  return <ShowDataComponent label="Authors" data={data}/>
}

Then, it works as expected. However, given a mocked server books query GET_BOOKS I want to test that the component Authors works well. I passed the client resolvers to the MockedProvider component without any result:

export const Tolkien = () => ({
  id: 2,
  name: 'John Ronald Reuel Tolkien'
});

export const Orwell = () => ({
  id: 3,
  name: 'George Orwell'
});

const BooksMock = () => [{
  id: 1,
  name: 'The Hobbit',
  published: 1954,
  author: Tolkien()
}, {
  id: 1,
  name: 'Nineteen Eighty-Four',
  published: 1949,
  author: Orwell()
}];

describe('Books', () => {
  afterEach(cleanup);

  it('renders books', async () => {
    const cache = new InMemoryCache({ addTypename: false });
    const books = BooksMock();
    const mocks = [
      {
        request: { query: GET_AUTHORS },
        result: {
          data: {
            books,
          },
        },
      },
    ];
    const { container } = await render(
      <MockedProvider
        mocks={mocks}
        cache={cache}
        resolvers={resolvers}
      >
        <Authors/>
      </MockedProvider>
    );
    await wait(() => expect(container.textContent).toContain(Orwell().name));
    await wait(() => expect(container.textContent).toContain(Tolkien().name));
  });
});

However Authors component remains loading. I'm not sure if I'm doing something wrong or MockedProvider is not able to do this kind of tests.

Aucun commentaire:

Enregistrer un commentaire