0.19.0 • Published 2 years ago

graphql-fakester v0.19.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

graphql-fakester

Create stub data by querying a GraphQL schema.

This might be useful together with something like the Apollo MockProvider.

Installation

npm install graphql-fakester

Usage

import { GraphQLMock } from "graphql-fakester";

const typeDefs = `
  type Author {
    id: ID!
    firstName: String
    lastName: String
    email: String
    posts: [Post]
  }

  type Comment {
    id: ID!
    text: String!
  }

  type CommentConnectionEdge {
    cursor: String!
    node: Comment
  }

  type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
    startCursor: String
    endCursor: String
  }

  type CommentConnection {
    edges: [CommentConnectionEdge!]!
    total: Int!
    pageInfo: PageInfo!
  }

  type Post {
    id: ID!
    title: String
    text: String
    author: Author
    votes: Int
    comments(
      first: Int
      last: Int
      after: String
      before: String
    ): CommentConnection!
  }

  type Query {
    posts: [Post]
    author(id: ID!): Author
  }

  type Mutation {
    upvotePost(postId: ID!): Post
  }
`;

let mock = new GraphQLMock({ typeDefs });

const authorQuery = `
  query authorFirstName($id: ID!) {
    author(id: $id) {
      firstName
      lastName
      email
      posts {
        id
        title
      }
    }
  }
`;

let result = await mock.execute(authorQuery, { id: "42" });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "4945079106011136",
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "1828976169320448", title: "jeminode" },
        { id: "4158848130613248", title: "orimipon" },
      ],
    },
  },
});

You can also provide the query and the variables as an option object:

result = await mock.execute({ query: authorQuery, variables: { id: "42" } });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "4945079106011136",
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "1828976169320448", title: "jeminode" },
        { id: "4158848130613248", title: "orimipon" },
      ],
    },
  },
});

Overriding the default mocks

This project uses @graphql-tools/mock as its basis and can be used in a very similar way.

If you just want to hardcode an override, you can do that the following way:

mock = new GraphQLMock({
  typeDefs,
  mocks: {
    Author: {
      id: "author-0",
      firstName: "Jane",
      lastName: "Doe",
      posts: [{ title: "First post" }, {}],
    },
  },
});

result = await mock.execute(authorQuery, { id: "42" });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "4945079106011136",
      firstName: "Jane",
      lastName: "Doe",
      email: "kelecse",
      posts: [
        { id: "1828976169320448", title: "First post" },
        { id: "4158848130613248", title: "orimipon" },
      ],
    },
  },
});

In case you need to seeded generate random data from a override, you can provide a function.

The each of the top-level override function will be given a chancejs instance that can be used to generate random seeded data, a root object containing the resolved parent data, an args object containing the arguments for the query, a context and an info object containing information about the query.

See the mocking documentation for more details.

Mocking a list resolver

import { list } from "graphql-fakester";

mock = new GraphQLMock({
  typeDefs,
  mocks: {
    Author: {
      id: "author-0",
      firstName: "Jane",
      lastName: "Doe",
      posts: list(3),
    },
  },
});

result = await mock.execute(authorQuery, { id: "42" });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "4945079106011136",
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "1828976169320448", title: "jeminode" },
        { id: "4158848130613248", title: "orimipon" },
        { id: "4158848130613248", title: "orimipon" },
      ],
    },
  },
});

You can use chance to create a variable length list this way.

mock = new GraphQLMock({
  typeDefs,
  mocks: {
    Author: chance => ({
      id: "author-0",
      posts: list(chance.integer{ min: 1, max: 5 }),
    }),
  },
});

result = await mock.execute(authorQuery, { id: "42" });

expect(result, "to satisfy", {
  data: {
    author: {
      id: j4945079106011136j,
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "1828976169320448", title: "jeminode" },
        { id: "4158848130613248", title: "orimipon" },
      ],
    },
  },
});

Notice min defaults to 0 and max defaults to 10, so can just call the list function without any arguments, or only send in either min or max.

Mock a Relay connection resolver

import { connection } from "graphql-fakester";

mock = new GraphQLMock({
  typeDefs,
  mocks: {
    posts: list(1),
    CommentConnection: connection(1, { includeTotal: true }),
  },
});

const postsQuery = `
  query postsQuery {
    posts {
      id
      title
      comments(first: 1) {
        edges {
          cursor
          node {
            id
            text
          }
        }
        pageInfo {
          hasNextPage
          hasPreviousPage
          hasNextPage
          endCursor
        }
        total
      }
    }
  }
`;

result = await mock.execute(postsQuery);

expect(result, "to satisfy", {
  data: {
    posts: [
      {
        id: "4945079106011136",
        title: "herubju",
        comments: {
          edges: [
            {
              cursor: "cursor-0",
              node: { id: "6325555974635520", text: "nocpebe" },
            },
          ],
          pageInfo: {
            hasNextPage: true,
            hasPreviousPage: false,
            endCursor: "cursor-0",
          },
          total: 1,
        },
      },
    ],
  },
});

Options:

  • includeTotal (false): If a total field should be included
  • hasNextPage (true): sets the pageInfo.hasNextPage value
  • hasPreviousPage (false): sets the pageInfo.hasPreviousPage value

Overriding a special list entry

You can get a sequence number corresponding to the number of time a mock has been resolved. This can be used to respond specially for a certain index in a list:

mock = new GraphQLMock({
  typeDefs,
  mocks: {
    Author: {
      id: "author-0",
      posts: list(5),
    },
    Post: (chance, seq) =>
      seq === 3 ? { id: "post-0", title: "My very special title" } : {},
  },
});

result = await mock.execute(authorQuery, { id: authorId });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "4945079106011136",
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "6325555974635520", title: "jeminode" },
        { id: "308014672248832", title: "orimipon" },
        { id: "1702188611010560", title: "rurzilru" },
        { id: "1828976169320448", title: "My very special title" },
        { id: "4158848130613248", title: "lufzipav" },
      ],
    },
  },
});

Cycling through mocks

Sometimes it is useful to provide a cycle through a finite list of mocks. You can use the cycle utility for this purpose.

import { cycle } from "graphql-fakester";

mock = new GraphQLMock({
  typeDefs,
  mocks: {
    Author: {
      id: "author-0",
      posts: list(5),
    },
    Post: cycle(
      { id: "post-0", title: "foo" },
      (chance) => ({
        id: String(chance.natural()),
        title: `bar-${chance.word()}`,
      }),
      { id: "post-2", title: "baz" }
    ),
  },
});

result = await mock.execute(authorQuery, { id: authorId });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "author-0",
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "post-0", title: "foo" },
        { id: "308014672248832", title: "bar-ketis" },
        { id: "post-1", title: "baz" },
        { id: "post-0", title: "foo" },
        { id: "4158848130613248", title: "bar-ziluwi" },
      ],
    },
  },
});

Using a specific list of mocks

In other cases you might want to specify the first n mocks and just repeat the last one, you can do that with the values utility.

Notice that the last mock will be repeated when all the initial mocks has been used, so it is a good idea to put some randomness into the final mock.

import { values } from "graphql-fakester";

mock = new GraphQLMock({
  typeDefs,
  mocks: {
    Author: {
      id: "author-0",
      posts: list(5),
    },
    Post: values(
      { id: "post-0", title: "foo" },
      { id: "post-1", title: "bar" },
      (chance) => ({
        id: String(chance.natural()),
        title: `baz-${chance.word()}`,
      })
    ),
  },
});

result = await mock.execute(authorQuery, { id: authorId });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "author-0",
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "post-0", title: "foo" },
        { id: "post-1", title: "bar" },
        { id: "1702188611010560", title: "baz-ketis" },
        { id: "1828976169320448", title: "baz-ziluwi" },
        { id: "4158848130613248", title: "baz-zev" },
      ],
    },
  },
});

Providing custom resolvers

It is possible to create a custom resolver that can use the mock store to retrieve or update the stored mocks.

This can be useful for mocking resolvers where the arguments are important.

Here we want to make sure that when we resolve an author, we get the id we asked for:

mock = new GraphQLMock({
  typeDefs,
  resolvers: (store) => ({
    Query: {
      author: (root, { id }) => store.get("Author", id),
    },
  }),
});

result = await mock.execute(authorQuery, { id: "42" });

expect(result, "to satisfy", {
  data: {
    author: {
      id: "42",
      firstName: "herubju",
      lastName: "nocpebe",
      email: "kelecse",
      posts: [
        { id: "1828976169320448", title: "jeminode" },
        { id: "4158848130613248", title: "orimipon" },
      ],
    },
  },
});

See Handling *byId fields for more information.

Creating a preconfigured mock

class MyMock extends GraphQLMock {
  constructor(mocks) {
    super({
      typeDefs,
      mocks: [
        {
          Author: (chance) => ({
            id: String(chance.natural()),
            email: chance.email(),
            posts: list(3),
          }),
          Post: (chance) => ({
            id: String(chance.natural()),
            title: `title-${chance.word()}`,
          }),
        },
        mocks,
      ],
    });
  }
}

mock = new MyMock({
  Author: (chance) => ({
    id: "author-0",
    firstName: "Jane",
    lastName: "Doe",
  }),
});

result = await mock.execute(authorQuery, { id: authorId });

expect(result, "to satisfy", {
  data: {
    author: {
      firstName: "Jane",
      lastName: "Doe",
      email: "ketis@ziluwi.cw",
      posts: [
        { id: "6325555974635520", title: "title-ha" },
        { id: "308014672248832", title: "title-felsuh" },
      ],
    },
  },
});
0.19.0

2 years ago

0.13.0

2 years ago

0.14.0

2 years ago

0.13.1

2 years ago

0.15.0

2 years ago

0.14.1

2 years ago

0.13.2

2 years ago

0.16.0

2 years ago

0.17.0

2 years ago

0.16.1

2 years ago

0.18.0

2 years ago

0.16.2

2 years ago

0.16.2-1

2 years ago

0.10.0

2 years ago

0.11.0

2 years ago

0.9.0

2 years ago

0.12.0

2 years ago

0.8.0

2 years ago

0.12.1

2 years ago

0.12.2

2 years ago

0.5.0

2 years ago

0.4.0

2 years ago

0.7.0

2 years ago

0.6.0

2 years ago

0.3.0

2 years ago

0.2.0

2 years ago

0.1.0

2 years ago