Skip to content

Commit

Permalink
Update readme and storybook (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
alessbell authored Jun 14, 2024
1 parent 26f11e0 commit b95c0d3
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 229 deletions.
20 changes: 10 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ jobs:
version: 9
run_install: true

# - name: Create release PR or publish to npm + GitHub
# id: changesets
# if: steps.check_files.outputs.files_exists == 'false'
# uses: changesets/action@v1
# with:
# version: pnpm run changeset-version
# publish: pnpm run changeset-publish
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create release PR or publish to npm + GitHub
id: changesets
if: steps.check_files.outputs.files_exists == 'false'
uses: changesets/action@v1
with:
version: pnpm run changeset-version
publish: pnpm run changeset-publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
16 changes: 11 additions & 5 deletions .storybook/stories/ApolloComponent.stories.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import type { Meta, StoryObj } from "@storybook/react";
import { within, expect, waitFor } from "@storybook/test";
import ApolloComponent from "./components/apollo-client/ApolloComponent.js";
import {
ApolloApp,
ApolloAppWithDefer as AppWithDefer,
} from "./components/apollo-client/ApolloComponent.js";
import { createHandler } from "../../src/handlers";
import { schemaWithMocks } from "../../src/__tests__/mocks/handlers";
import { Canvas } from "@storybook/blocks";

const { handler } = createHandler(schemaWithMocks);

const meta = {
title: "Example/ApolloComponent",
component: ApolloComponent,
title: "Example/Apollo",
component: ApolloApp,
parameters: {
layout: "centered",
msw: {
Expand All @@ -17,13 +21,15 @@ const meta = {
},
},
},
} satisfies Meta<typeof ApolloComponent>;
} satisfies Meta<typeof ApolloApp>;

export default meta;

export { AppWithDefer };

type Story = StoryObj<typeof meta>;

export const Primary: Story = {
export const App: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(
Expand Down
15 changes: 10 additions & 5 deletions .storybook/stories/RelayComponent.stories.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type { Meta, StoryObj } from "@storybook/react";
import { within, expect, waitFor } from "@storybook/test";
import RelayComponent from "./components/relay/RelayComponent.js";
import {
RelayApp,
RelayAppWithDefer as AppWithDefer,
} from "./components/relay/RelayComponent.js";
import { createHandler } from "../../src/handlers";
import { schemaWithMocks } from "../../src/__tests__/mocks/handlers";

const { handler } = createHandler(schemaWithMocks);

const meta = {
title: "Example/RelayComponent",
component: RelayComponent,
title: "Example/Relay",
component: RelayApp,
parameters: {
layout: "centered",
msw: {
Expand All @@ -17,13 +20,15 @@ const meta = {
},
},
},
} satisfies Meta<typeof RelayComponent>;
} satisfies Meta<typeof RelayApp>;

export default meta;

export { AppWithDefer };

type Story = StoryObj<typeof meta>;

export const Primary: Story = {
export const App: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(
Expand Down
73 changes: 70 additions & 3 deletions .storybook/stories/Welcome.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,75 @@ import { Meta } from "@storybook/blocks";

<Meta title="GraphQL Testing Library" />

# GraphQL Testing Library
<div align="center">
<h1>GraphQL Testing Library</h1>

GraphQL Testing Library provides generic utilities for creating [Mock Service Worker](https://mswjs.io/) handlers for any GraphQL API. MSW is also the [Testing Library-recommended](https://testing-library.com/docs/react-testing-library/example-intro/#full-example) way to declaratively mock API communication in your tests without stubbing `window.fetch`.
{/* <a href="https://www.apollographql.com/"><img src="https://raw.githubusercontent.com/apollographql/apollo-client-devtools/main/assets/apollo-wordmark.svg" height="100" alt="Apollo Client" /></a> */}

> This project is not affiliated with the ["Testing Library"](https://github.com/testing-library) ecosystem that this project is clearly inspired from.
<p>Testing utilities that encourage good practices for apps built with GraphQL.</p>

</div>
<hr />

**GraphQL Testing Library** provides utilities that make it easy to generate [Mock Service Worker](https://mswjs.io/) handlers for any GraphQL API.

MSW is the [Testing Library-recommended](https://testing-library.com/docs/react-testing-library/example-intro/#full-example) way to declaratively mock API communication in your tests without stubbing `window.fetch`.

This library currently supports incremental delivery features `@defer` and `@stream` out of the box, with plans to support subscriptions over multipart HTTP as well as other transports such as WebSockets, [currently in beta in MSW](https://github.com/mswjs/msw/discussions/2010).

> This project is not affiliated with the ["Testing Library"](https://github.com/testing-library) ecosystem that inspired it. We're just fans :)

## Installation

This library has `peerDependencies` listings for `msw` at `^2.0.0` and `graphql` at `^15.0.0 || ^16.0.0`. Install them along with this library using your preferred package manager:

```
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

### `createHandler`

```typescript
import { createHandler } from "@apollo/graphql-testing-library";

// We suggest using @graphql-tools/mock and @graphql-tools/schema
// to create a schema with mock resolvers.
// See https://the-guild.dev/graphql/tools/docs/mocking for more info.
import { addMocksToSchema } from "@graphql-tools/mock";
import { makeExecutableSchema } from "@graphql-tools/schema";
import typeDefs from "./schema.graphql";

// Create an executable schema
const schema = makeExecutableSchema({ typeDefs });

// Add mock resolvers
const schemaWithMocks = addMocksToSchema({
schema,
resolvers: {
Query: {
products: () =>
Array.from({ length: 5 }, (_element, id) => ({
id: `product-${id}`,
})),
},
},
});

// `createHandler` returns an object with `handler` and `replaceSchema`
// functions: `handler` is a MSW handler that will intercept all GraphQL
// operations, and `replaceSchema` allows you to replace the mock schema
// the `handler` use to resolve requests against.
const { handler, replaceSchema } = createHandler(schemaWithMocks, {
// It accepts a config object as the second argument where you can specify a
// delay min and max, which will add random delays to your tests within the /
// threshold to simulate a real network connection.
// Default: delay: { min: 300, max: 300 }
delay: { min: 200, max: 500 },
});
```
74 changes: 65 additions & 9 deletions .storybook/stories/components/apollo-client/ApolloComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Suspense } from "react";
import { Suspense, type ReactNode } from "react";
import type { TypedDocumentNode } from "@apollo/client";
import {
gql,
Expand All @@ -9,8 +9,8 @@ import {
HttpLink,
useSuspenseQuery,
} from "@apollo/client";
import { Container } from "../Container.js";
import { Product, Reviews } from "../Product.js";
import { Container } from "../Container.js";

const httpLink = new HttpLink({
uri: "https://main--hack-the-e-commerce.apollographos.net/graphql",
Expand All @@ -25,14 +25,38 @@ export const makeClient = () =>

export const client = makeClient();

const QUERY: TypedDocumentNode<{
const APP_QUERY: TypedDocumentNode<{
products: {
id: string;
title: string;
mediaUrl: string;
description: string;
reviews: Array<{ rating: number; id: string; content: string }>;
}[];
}> = gql`
query AppQuery {
products {
id
reviews {
id
rating
content
}
title
mediaUrl
description
}
}
`;

const APP_QUERY_WITH_DEFER: TypedDocumentNode<{
products: {
id: string;
title: string;
mediaUrl: string;
description: string;
reviews?: Array<{ rating: number; id: string; content: string }>;
}[];
}> = gql`
query AppQuery {
products {
Expand All @@ -51,18 +75,34 @@ const QUERY: TypedDocumentNode<{
}
`;

export default function App() {
function Wrapper({ children }: { children: ReactNode }) {
return (
<ApolloProvider client={client}>
<Suspense fallback={<h1>Loading...</h1>}>
<Main />
</Suspense>
<Suspense fallback={<h1>Loading...</h1>}>{children}</Suspense>
</ApolloProvider>
);
}

export function Main() {
const { data } = useSuspenseQuery(QUERY);
export function ApolloApp() {
return (
<Wrapper>
<App />
</Wrapper>
);
}

export function ApolloAppWithDefer() {
return (
<Wrapper>
<AppWithDefer />
</Wrapper>
);
}

export function App() {
// Use useSuspenseQuery here because we want to demo the loading experience
// with/without defer.
const { data } = useSuspenseQuery(APP_QUERY);

return (
<Container>
Expand All @@ -74,3 +114,19 @@ export function Main() {
</Container>
);
}

export function AppWithDefer() {
// Use useSuspenseQuery here because we want to demo the loading experience
// with/without defer.
const { data } = useSuspenseQuery(APP_QUERY_WITH_DEFER);

return (
<Container>
{data.products.map((product) => (
<Product key={product.id} product={product}>
<Reviews reviews={product.reviews || []} />
</Product>
))}
</Container>
);
}
Loading

0 comments on commit b95c0d3

Please sign in to comment.