Skip to content

Commit

Permalink
add msw example
Browse files Browse the repository at this point in the history
  • Loading branch information
alessbell committed Apr 24, 2024
1 parent aebc3a5 commit 3baf29d
Showing 1 changed file with 162 additions and 8 deletions.
170 changes: 162 additions & 8 deletions docs/source/development-testing/schema-driven-testing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,167 @@ import { gql } from "@apollo/client";
gql.disableFragmentWarnings();
```

### Usage with Jest and Testing Library
### Testing with MSW

Now, let's write a test for the `Products` component using `createTestSchema`.
Now, let's write a test for the `Products` component using [MSW](https://mswjs.io/).

MSW is a powerful tool for intercepting network traffic and mocking responses. Read more about its design and philosophy [here](https://mswjs.io/blog/why-mock-service-worker/).

MSW has the concept of [handlers](https://mswjs.io/docs/best-practices/structuring-handlers/) that allow network requests to be intercepted. Let's create a handler that will intercept all GraphQL operations:

```ts title="src/__tests__/handlers.ts"
import { graphql, HttpResponse } from "msw";
import { execute } from "graphql";
import type { ExecutionResult } from "graphql";
import type { ObjMap } from "graphql/jsutils/ObjMap";
import { gql } from "@apollo/client";
import { createTestSchema } from "@apollo/client/testing/experimental";
import { makeExecutableSchema } from "@graphql-tools/schema";
import graphqlSchema from "../../../schema.graphql";

// First, create a static schema...
const staticSchema = makeExecutableSchema({ typeDefs: graphqlSchema });

// ...which is then passed as the first argument to `createTestSchema`
// along with mock resolvers and default scalar values.
export let testSchema = createTestSchema(staticSchema, {
resolvers: {
Query: {
products: () => [
{
id: "1",
title: "Blue Jays Hat",
},
],
},
},
scalars: {
Int: () => 6,
Float: () => 22.1,
String: () => "string",
},
});

export const handlers = [
// Intercept all GraphQL operations and return a response generated by the
// test schema. Add additional handlers as needed.
graphql.operation<ExecutionResult<ObjMap<unknown>, ObjMap<unknown>>>(
async ({ query, variables, operationName }) => {
const document = gql(query);

const result = await execute({
document,
operationName,
schema: testSchema,
variableValues: variables,
});

return HttpResponse.json(result);
}
),
];
```

MSW can be used in [the browser](https://mswjs.io/docs/integrations/browser), in [Node.js](https://mswjs.io/docs/integrations/node) and in [React Native](https://mswjs.io/docs/integrations/react-native). Since this example is using Jest and JSDOM to run tests in a Node.js environment, let's configure the server per the [Node.js integration guide](https://mswjs.io/docs/integrations/node):

```ts title="src/__tests__/server.ts"
import { setupServer } from "msw/node";
import { handlers } from "./handlers";

// This configures a request mocking server with the given request handlers.
export const server = setupServer(...handlers);
```

Finally, let's do server set up and teardown in the `setupTests.ts` file created in the previous step:

```ts title="setupTests.ts" {6-8}
import "@testing-library/jest-dom";
import { gql } from "@apollo/client";

gql.disableFragmentWarnings();

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
```

Finally, let's write some tests 🎉

```tsx title="src/__tests__/products.test.tsx"
import { Suspense } from "react";
import { render as rtlRender, screen } from "@testing-library/react";
import {
ApolloClient,
ApolloProvider,
NormalizedCacheObject,
} from "@apollo/client";
import { testSchema } from "./handlers";
import { Products } from "../products";
// This should be a function that returns a new ApolloClient instance
// configured just like your production Apollo Client instance - see the FAQ.
import { makeClient } from "../client";

const render = (renderedClient: ApolloClient<NormalizedCacheObject>) =>
rtlRender(
<ApolloProvider client={renderedClient}>
<Suspense fallback="Loading...">
<Products />
</Suspense>
</ApolloProvider>
);

describe("Products", () => {
test("renders", async () => {
render(makeClient());

await screen.findByText("Loading...");

// This is the data from our initial mock resolver in the test schema
// defined in the handlers file 🎉
expect(await screen.findByText(/blue jays hat/i)).toBeInTheDocument();
});

test("allows resolvers to be updated via .add", async () => {
// Calling .add on the test schema will update the resolvers
// with new data
testSchema.add({
resolvers: {
Query: {
products: () => {
return [
{
id: "2",
title: "Mets Hat",
},
];
},
},
},
});

render(makeClient());

await screen.findByText("Loading...");

// Our component now renders the new data from the updated resolver
await screen.findByText(/mets hat/i);
});

test("handles test schema resetting via .reset", async () => {
// Calling .reset on the test schema will reset the resolvers
testSchema.reset();

render(makeClient());

await screen.findByText("Loading...");

// The component now renders the initial data configured on the test schema
await screen.findByText(/blue jays hat/i);
});
});
```

### Testing by mocking fetch with `createSchemaFetch`

First, import `createSchemaFetch` and `createTestSchema` from the new `@apollo/client/testing` entrypoint. Next, import a local copy of your graph's schema: jest should be configured to transform `.gql` or `.graphql` files using `@graphql-tools/jest-transform` (see the `jest.config.ts` example configuration above.)

Expand All @@ -183,10 +341,10 @@ import {
import { makeExecutableSchema } from "@graphql-tools/schema";
import { render as rtlRender, screen } from "@testing-library/react";
import graphqlSchema from "../../../schema.graphql";
// This should be a function that returns a new ApolloClient instance
// configured just like your production Apollo Client instance - see the FAQ.
import { makeClient } from "../../client";
import {
// this should be a function that returns a new ApolloClient instance configured just like your production Apollo Client instance - see the FAQ.
import { makeClient } from "../../client";
ApolloProvider,
NormalizedCacheObject,
} from "@apollo/client";
Expand Down Expand Up @@ -279,10 +437,6 @@ describe("Products", () => {
});
```

### Usage with Jest and Mock Service Worker (MSW)



### FAQ

#### When should I use `createSchemaFetch` vs [MSW](https://mswjs.io/)?
Expand Down

0 comments on commit 3baf29d

Please sign in to comment.