Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
alessbell committed Aug 31, 2024
1 parent 9342016 commit a01673c
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 30 deletions.
1 change: 0 additions & 1 deletion .storybook/stories/Welcome.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ This library has `peerDependencies` listings for `msw` at `^2.0.0` and `graphql`
npm install --save-dev @apollo/graphql-testing-library msw graphql
pnpm add --save-dev @apollo/graphql-testing-library msw graphql
yarn add --dev @apollo/graphql-testing-library msw graphql
bun add --dev @apollo/graphql-testing-library msw graphql
```

## Usage
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ This library has `peerDependencies` listings for `msw` at `^2.0.0` and `graphql`
npm install --save-dev @apollo/graphql-testing-library msw graphql
pnpm add --save-dev @apollo/graphql-testing-library msw graphql
yarn add --dev @apollo/graphql-testing-library msw graphql
bun add --dev @apollo/graphql-testing-library msw graphql
```

## Usage
Expand Down
5 changes: 4 additions & 1 deletion docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export default defineConfig({
},
{
label: "Guides",
items: [{ label: "Creating a handler", slug: "creating-a-handler" }],
items: [
{ label: "Creating a handler", slug: "creating-a-handler" },
{ label: "Writing a test", slug: "writing-a-test" },
],
},
{
label: "Storybook Examples",
Expand Down
68 changes: 68 additions & 0 deletions docs/src/content/docs/creating-a-handler.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,71 @@
title: Creating a handler
# description: A guide in my new Starlight docs site.
---

import { Aside } from "@astrojs/starlight/components";

Once [Mock Service Worker](https://mswjs.io/) has been configured in your environment, you're ready to create your first request handler and begin writing mock resolvers.

Create a `handlers.ts` inside the `mocks` folder you created during MSW set-up.

## `createHandler`

Let's create a GraphQL request handler using the `createHandler` function.

<Aside type="tip">

If your project is using [GraphQL-Codegen](https://the-guild.dev/graphql/codegen) or a similar tool to generate resolver types, you can pass `Resolvers` as a generic type argument to `createHandler` to type check mock resolvers.

</Aside>

```ts
// src/mocks/handlers.ts
import { createHandler } from "@apollo/graphql-testing-library";
import typeDefs from "../../schema.graphql";
import type { Resolvers } from "../../__generated__/resolvers-types.ts";

const graphQLHandler = createHandler<Resolvers>({
typeDefs,
// Configure the mock resolvers for your handler.
// `resolvers` can be overridden in individual tests.
resolvers: {
Query: {
products: (parent, arguments, context, info) =>
Array.from({ length: 2 }, (element, index) => ({
id: `${index}`,
title: `Product ${index}`,
})),
},
},
// Mock any type in the schema directly.
// `mocks` can also be overridden in individual tests.
mocks: {
FooBarType: () => ({
foo: "bar",
baz: "qux",
}),
CustomScalar: () => "Foo bar",
String: () => "Hello world",
},
});
```

The handler `graphQLHandler` can now be passed to Mock Service Worker's [`setupServer` in Node.js](https://mswjs.io/docs/integrations/node#setup) or [`setupWorker` in the browser](). It will intercept all GraphQL operations and generate a response using your mock schema. 🚀

## Default mocks

Using the provided schema's type definitions, GraphQL Testing Library creates a mock schema under the hood with a set of default mocks:

- **Union and Interface types**: Union and Interface types are configured with a default `__resolveType` function set that selects the first possible type (can be overriden via mock `resolvers`).
- **Enum types**: Enum types return the first possible value by default (can be overridden via `mocks` option).
- **Custom scalars**: Custom scalars return `Default value for custom scalar ${typeName}` by default (can be overridden via `mocks` option).

<Aside type="note">

For full control over the creation of your mock schema, use the `createHandlerFromSchema` API instead which takes a `GraphQLSchema` instead of a `DocumentNode`.

</Aside>

## Request timing

- talk about `delay`
4 changes: 2 additions & 2 deletions docs/src/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ hero:
import { Card, CardGrid } from "@astrojs/starlight/components";

<CardGrid stagger>
<Card title="Client and framework-agnostic" icon="puzzle">
<Card title="Client- and framework-agnostic" icon="puzzle">
GraphQL Testing Library can be used to test apps built with any GraphQL
client or front-end stack.
</Card>
Expand All @@ -30,7 +30,7 @@ import { Card, CardGrid } from "@astrojs/starlight/components";
<Card title="Schema-driven testing" icon="seti:graphql" color="pink">
Goodbye hand-written response mocks, hello mock resolvers.
</Card>
<Card title="With the power of MSW" icon="rocket">
<Card title="Powered by MSW" icon="rocket">
Learn more about Mock Service Worker by exploring [the MSW
docs](https://mswjs.io/).
</Card>
Expand Down
7 changes: 0 additions & 7 deletions docs/src/content/docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,5 @@ pnpm add --save-dev @apollo/graphql-testing-library msw graphql
yarn add --dev @apollo/graphql-testing-library msw graphql
```

</TabItem>
<TabItem label="Bun">

```sh
bun add --dev @apollo/graphql-testing-library msw graphql
```

</TabItem>
</Tabs>
105 changes: 98 additions & 7 deletions docs/src/content/docs/integrations/browser.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ title: Usage in the browser
# description: A guide in my new Starlight docs site.
---

import { Tabs, TabItem } from "@astrojs/starlight/components";
import { Tabs, TabItem, Aside } from "@astrojs/starlight/components";

## With Storybook

[Mock Service Worker](https://mswjs.io/) and [GraphQL Testing Library](https://github.com/apollographql/graphql-testing-library) pair nicely with [Storybook](https://storybook.js.org/) when developing in the browser.

To get started, install the [Mock Service Worker Storybook addon](https://storybook.js.org/addons/msw-storybook-addon).
### Installation

To get started, install the [Mock Service Worker Storybook addon](https://storybook.js.org/addons/msw-storybook-addon) and configure it using the instructions in the README.

<Tabs syncKey="pkg">
<TabItem label="npm">
Expand All @@ -33,11 +35,100 @@ yarn add --dev msw-storybook-addon
```

</TabItem>
<TabItem label="Bun">
</Tabs>

```sh
bun add --dev msw-storybook-addon
### Usage

```ts
// storybook/preview.tsx
import { initialize, mswLoader } from "msw-storybook-addon";
import { HttpResponse, http } from "msw";
import { createHandler } from "@apollo/graphql-testing-library";
import typeDefs from "../../../.storybook/stories/ecommerce-schema.graphql";

// Initialize MSW
initialize();

// Provide the MSW addon loader globally
export const loaders = [mswLoader];

const defaultHandlers = {
// Initialize default handlers here, including any non-GraphQL endpoints.
// For example, let's say this app displays the status of a service by
// making a GET request to a dedicated endpoint.
apiStatus: http.get("https://status.example.com/api/status.json", () => {
return HttpResponse.json({
status: { description: "All Systems Operational!" },
});
}),
// Default handler for all GraphQL requests.
// Individual stories will overwrite this handler via the
// exported ComponentName.parameters.msw.handlers.graphql property.
graphql: createHandler({
typeDefs,
resolvers: {
Query: {
// Your mock resolvers here
},
},
}),
};

export const parameters = {
msw: {
handlers: defaultHandlers,
},
};
```

</TabItem>
</Tabs>
If your app is using a GraphQL client that relies on the presence of a provider component, like Apollo Client with `ApolloProvider`, you can provide it globally via decorator.

<Aside type="note">

In general, be wary of sharing cache instances across stories or tests. On the Apollo Client team, we advise you not to share a single `ApolloClient` instance because, even if the cache is reset, the client maintains some internal state that is not reset which could have unintended consequences.

By creating a `makeClient` function or equivalent, every test or story can use the same client configuration as your production client, but no two tests or stories share the same instance.

</Aside>

```tsx
// storybook/preview.tsx
import { ApolloProvider } from "@apollo/client";
import { Decorator } from "@storybook/react";

export const makeClient = () => {
return new ApolloClient({
cache: new InMemoryCache(),
uri: "https://example.com/graphql",
});
};

export const decorators: Decorator[] = [
(story) => <ApolloProvider client={makeClient()}>{story()}</ApolloProvider>,
];
```

Now, in individual Storybook stories, the `graphql` handler can be overridden by setting a new handler via `parameters`:

```tsx
// storybook/MyComponent.story.tsx
import { Meta, StoryObj } from "@storybook/react";
import { createHandler } from "@apollo/graphql-testing-library";
import { MyComponent } from "./MyComponent";

// You do not need to specify a default GraphQL handler,
// since it's already been set in preview.tsx
export default {
component: MyComponent,
} as Meta<typeof MyComponent>;

export const ErrorState: StoryObj<typeof MyComponent> = {
parameters: {
msw: {
handlers: {
graphql: createHandler({}),
},
},
},
};
```
24 changes: 13 additions & 11 deletions docs/src/content/docs/integrations/node.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ In order to use GraphQL Testing Library and MSW with Jest, missing Node.js globa

Create a `jest.polyfills.js` file with the following contents:

<Aside type="note">

Be sure to also install `undici`, the official fetch implementation in Node.js.

</Aside>

```ts
// jest.polyfills.js
/**
Expand Down Expand Up @@ -62,13 +68,7 @@ if (!Symbol.asyncDispose) {
}
```

This file mostly contains the [Jest polyfills recommended by MSW](https://mswjs.io/docs/faq/#requestresponsetextencoder-is-not-defined-jest), with two additions: the version above includes `ReadableStream` which is needed for incremental delivery features, and a polyfill for `Symbol.dispose` which is not available in Jest in versions before `30.0.0-alpha.3`.

<Aside type="note">

Be sure to also install `undici`, the official fetch implementation in Node.js.

</Aside>
This file mostly contains the [Jest polyfills recommended by MSW](https://mswjs.io/docs/faq/#requestresponsetextencoder-is-not-defined-jest), with two additions: the version above includes `ReadableStream` which is needed for incremental delivery features, and a polyfill for `Symbol.dispose` which is not available in Jest in versions below `30.0.0-alpha.3`.

Then, set the `setupFiles` option in `jest.config.js` to point to your `jest.polyfills.js`:

Expand All @@ -81,7 +81,7 @@ module.exports = {

Next, follow the Mock Service Worker documentation for [setting up MSW in Node.js](https://mswjs.io/docs/integrations/node).

Finally, install `@graphql-tools/jest-transform` as a dev dependency and configure Jest to transform `.gql`/`.graphql` files, since your GraphQL API's schema is needed to configure the Mock Service Worker [request handler](https://mswjs.io/docs/concepts/request-handler/) this library generates.
Finally, install `@graphql-tools/jest-transform` as a dev dependency and configure Jest to transform `.gql`/`.graphql` files, since your GraphQL API's schema document is required when [creating a request handler](/creating-a-handler).

Here are the relevant parts of your final `jest.config.js`:

Expand All @@ -105,11 +105,13 @@ module.exports = {

## With Vitest

No polyfills are needed in Vitest. In order to transform `.gql`/`.graphql` files, install `vite-plugin-graphql-loader` as a dev dependency and configure it in your `vitest.config.ts`.
Vitest does not need to be configured with any polyfills.

<Aside type="note">
In order to transform `.gql`/`.graphql` files, install `vite-plugin-graphql-loader` as a dev dependency and configure it in your `vitest.config.ts`.

<Aside type="caution">

In order to avoid the `graphql` error `Ensure that there is only one instance of "graphql" in the node_modules directory` caused by the [dual package hazard](https://nodejs.org/api/packages.html#dual-package-hazard), set [`server.deps.fallbackCJS`](https://vitest.dev/config/#server-deps-fallbackcjs) to `true`.
In order to avoid the `graphql` error `Ensure that there is only one instance of "graphql" in the node_modules directory` caused by the [dual package hazard](https://nodejs.org/api/packages.html#dual-package-hazard), please set [`server.deps.fallbackCJS`](https://vitest.dev/config/#server-deps-fallbackcjs) to `true`.

</Aside>

Expand Down
4 changes: 4 additions & 0 deletions docs/src/content/docs/writing-a-test.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: Writing a test
# description: A guide in my new Starlight docs site.
---

1 comment on commit a01673c

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines Statements Branches Functions
Coverage: 95%
94.89% (130/137) 90% (36/40) 85.71% (30/35)
Tests Skipped Failures Errors Time
6 0 💤 0 ❌ 0 🔥 3.305s ⏱️
Coverage Report (95%)
File% Stmts% Branch% Funcs% LinesUncovered Line #s
All files94.899085.7195.52 
   handlers.ts94.3193.7585.7194.18150–163
   utilities.ts95.9187.585.7197.91120

Please sign in to comment.