diff --git a/docs/snippets/angular/apollo-module.mock-apollo-module.ts.mdx b/docs/snippets/angular/apollo-module.mock-apollo-module.ts.mdx new file mode 100644 index 000000000000..a4ff6cb2d888 --- /dev/null +++ b/docs/snippets/angular/apollo-module.mock-apollo-module.ts.mdx @@ -0,0 +1,39 @@ +```ts +// mock-graphql.module.ts + +import { NgModule } from '@angular/core'; +import { APOLLO_OPTIONS } from 'apollo-angular'; +import { ApolloClientOptions, InMemoryCache } from '@apollo/client/core'; +import { HttpLink } from 'apollo-angular/http'; + +// See here for docs https://apollo-angular.com/docs/get-started + +const uri = 'https://your-graphql-endpoint'; +export function createApollo(httpLink: HttpLink): ApolloClientOptions { + return { + link: httpLink.create({ uri }), + cache: new InMemoryCache(), + defaultOptions: { + watchQuery: { + fetchPolicy: 'no-cache', + errorPolicy: 'all', + }, + query: { + fetchPolicy: 'no-cache', + errorPolicy: 'all', + }, + }, + }; +} + +@NgModule({ + providers: [ + { + provide: APOLLO_OPTIONS, + useFactory: createApollo, + deps: [HttpLink], + }, + ], +}) +export class MockGraphQLModule {} +``` diff --git a/docs/snippets/angular/document-screen-fetch.ts.mdx b/docs/snippets/angular/document-screen-fetch.ts.mdx new file mode 100644 index 000000000000..ccaddf887db9 --- /dev/null +++ b/docs/snippets/angular/document-screen-fetch.ts.mdx @@ -0,0 +1,48 @@ +```ts +// YourPage.component.ts + +import { Component, OnInit } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Component({ + selector: 'document-screen', + template: ` +
+

There was an error fetching the data!

+

Loading...

+
+ + + + +
+
+ `, +}) +export default class DocumentScreen implements OnInit { + user: any = { id: 0, name: 'Some User' }; + + document: any = { id: 0, title: 'Some Title' }; + + subdocuments: any = []; + + error = false; + loading = true; + + constructor(private http: HttpClient) {} + + ngOnInit() { + this.http.get('https://your-restful-endpoint').subscribe({ + next: (data) => { + this.loading = false; + this.user = data.user; + this.document = data.document; + this.documents.data.subdocuments; + }, + error: (error) => { + this.error = true; + }, + }); + } +} +``` diff --git a/docs/snippets/angular/document-screen-with-graphql.ts.mdx b/docs/snippets/angular/document-screen-with-graphql.ts.mdx new file mode 100644 index 000000000000..be521f486212 --- /dev/null +++ b/docs/snippets/angular/document-screen-with-graphql.ts.mdx @@ -0,0 +1,69 @@ +```ts +// YourPage.component.ts + +import { Component, OnInit } from '@angular/core'; +import { Apollo } from 'apollo-angular'; +import gql from 'graphql-tag'; + +@Component({ + selector: 'document-screen', + template: ` +
Loading...
+
There was an error fetching the data!
+
+ + + + +
+ `, +}) +export class SampleGraphqlComponent implements OnInit { + user: any = { id: 0, name: 'Some User' }; + + document: any = { id: 0, title: 'Some Title' }; + + subdocuments: any = []; + + error = ''; + loading = true; + + constructor(private apollo: Apollo) {} + ngOnInit() { + this.apollo + .watchQuery({ + query: gql` + query AllInfoQuery { + user { + userID + name + } + document { + id + userID + title + brief + status + } + subdocuments { + id + userID + title + content + status + } + } + `, + }) + .valueChanges.subscribe((result: any) => { + this.user = result?.data?.user; + this.document = result?.data?.document; + this.subdocuments = result?.data?.subdocuments; + this.loading = result.loading; + + // Errors is an array and we're getting the first item only + this.error = result.errors[0].message; + }); + } +} +``` diff --git a/docs/snippets/angular/documentscreen-story-msw-graphql-query.ts.mdx b/docs/snippets/angular/documentscreen-story-msw-graphql-query.ts.mdx new file mode 100644 index 000000000000..16849250c632 --- /dev/null +++ b/docs/snippets/angular/documentscreen-story-msw-graphql-query.ts.mdx @@ -0,0 +1,106 @@ +```ts +// YourPage.stories.ts + +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; + +import { Story, Meta, moduleMetadata } from '@storybook/angular'; + +import { graphql } from 'msw'; + +import DocumentScreen from './YourPage.component'; +import DocumentList from './DocumentList.component'; +import DocumentHeader from './DocumentHeader.component'; +import PageLayout from './PageLayout.component'; + +import { MockGraphQLModule } from './mock-graphql.module'; + +export default { + component: DocumentScreen, + decorators: [ + moduleMetadata({ + declarations: [DocumentList, DocumentHeader, PageLayout], + imports: [CommonModule, HttpClientModule, MockGraphQLModule], + }), + ], + title: 'Mock GraphQL query with Storybook and MSW', +} as Meta; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate: Story = (args) => ({ + props: args, +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res(ctx.data(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res( + ctx.delay(800), + ctx.errors([ + { + message: 'Access denied', + }, + ]) + ); + }), + ], +}; +``` diff --git a/docs/snippets/angular/documentscreen-story-msw-rest-request.ts.mdx b/docs/snippets/angular/documentscreen-story-msw-rest-request.ts.mdx new file mode 100644 index 000000000000..5ae41166c1b6 --- /dev/null +++ b/docs/snippets/angular/documentscreen-story-msw-rest-request.ts.mdx @@ -0,0 +1,97 @@ +```ts +// YourPage.stories.ts + +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; + +import { Story, Meta, moduleMetadata } from '@storybook/angular'; + +import { rest } from 'msw'; + +import DocumentScreen from './YourPage.component'; +import DocumentList from './DocumentList.component'; +import DocumentHeader from './DocumentHeader.component'; +import PageLayout from './PageLayout.component'; + +export default { + component: DocumentScreen, + decorators: [ + moduleMetadata({ + declarations: [DocumentList, DocumentHeader, PageLayout], + imports: [CommonModule, HttpClientModule], + }), + ], + title: 'Mock Rest request with Storybook and MSW', +} as Meta; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate: Story = (args) => ({ + props: args, +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + rest.get('https://your-restful-endpoint', (_req, res, ctx) => { + return res(ctx.json(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + rest.get('https://your-restful-endpoint', (_req, res, ctx) => { + return res(ctx.delay(800), ctx.status(403)); + }), + ], +}; +``` diff --git a/docs/snippets/react/component-story-with-query.js.mdx b/docs/snippets/react/component-story-with-query.js.mdx deleted file mode 100644 index e866c9bcd525..000000000000 --- a/docs/snippets/react/component-story-with-query.js.mdx +++ /dev/null @@ -1,25 +0,0 @@ -```js -// my-component-with-query.stories.js | my-component-with-query.stories.jsx - -import MyComponentThatHasAQuery, { MyQuery } from '../component-that-has-a-query'; - -const Template = (args) => ; - -export const LoggedOut = Template.bind({}); -LoggedOut.parameters = { - apolloClient: { - mocks: [ - { - request: { - query: MyQuery, - }, - result: { - data: { - viewer: null, - }, - }, - }, - ], - }, -}; -``` \ No newline at end of file diff --git a/docs/snippets/react/document-screen-fetch.js.mdx b/docs/snippets/react/document-screen-fetch.js.mdx new file mode 100644 index 000000000000..d42d8fdc76c7 --- /dev/null +++ b/docs/snippets/react/document-screen-fetch.js.mdx @@ -0,0 +1,57 @@ +```js +// YourPage.js | YourPage.jsx | YourPage.ts | YourPage.tsx + +import React, { useState, useEffect } from 'react'; + +import PageLayout from './PageLayout'; +import DocumentHeader from './DocumentHeader'; +import DocumentList from './DocumentList'; + +// Example hook to retrieve data from an external endpoint +function useFetchData() { + const [status, setStatus] = useState('idle'); + const [data, setData] = useState([]); + useEffect(() => { + setStatus('loading'); + fetch('https://your-restful-endpoint') + .then((res) => { + if (!res.ok) { + throw new Error(res.statusText); + } + return res; + }) + .then((res) => res.json()) + .then((data) => { + setStatus('sucess'); + setData(data); + }) + .catch(() => { + setStatus('error'); + }); + }, []); + return { + status, + data, + }; +} +function DocumentScreen() { + const { status, data } = useFetchData(); + + const { user, document, subdocuments } = data; + + if (status === 'loading') { + return

Loading...

; + } + if (status === 'error') { + return

There was an error fetching the data!

; + } + return ( + + + + + ); +} + +export default DocumentScreen; +``` diff --git a/docs/snippets/react/document-screen-with-graphql.js.mdx b/docs/snippets/react/document-screen-with-graphql.js.mdx new file mode 100644 index 000000000000..2fe252a02b29 --- /dev/null +++ b/docs/snippets/react/document-screen-with-graphql.js.mdx @@ -0,0 +1,56 @@ +```js +// YourPage.js | YourPage.jsx | YourPage.ts | YourPage.tsx + +import React from 'react'; + +import { useQuery, gql } from '@apollo/client'; + +const AllInfoQuery = gql` + query AllInfo { + user { + userID + name + } + document { + id + userID + title + brief + status + } + subdocuments { + id + userID + title + content + status + } + } +`; + +function useFetchInfo() { + const { loading, error, data } = useQuery(AllInfoQuery); + + return { loading, error, data }; +} + +function DocumentScreen() { + const { loading, error, data } = useFetchInfo(); + + if (loading) { + return

Loading...

; + } + + if (error) { + return

There was an error fetching the data!

; + } + + return ( + + + + + ); +} +export default DocumentScreen; +``` diff --git a/docs/snippets/react/documentscreen-story-msw-graphql-query.js.mdx b/docs/snippets/react/documentscreen-story-msw-graphql-query.js.mdx new file mode 100644 index 000000000000..7841013d01b2 --- /dev/null +++ b/docs/snippets/react/documentscreen-story-msw-graphql-query.js.mdx @@ -0,0 +1,111 @@ +```js +// YourPage.stories.js | YourPage.stories.jsx | YourPage.stories.ts | YourPage.stories.tsx + +import React from 'react'; + +import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'; + +import { graphql } from 'msw'; + +import DocumentScreen from './DocumentScreen'; + +export default { + component: DocumentScreen, + title: 'Mock GraphQL query with Storybook and MSW', +}; + +const mockedClient = new ApolloClient({ + uri: 'https://your-graphql-endpoint', + cache: new InMemoryCache(), + defaultOptions: { + watchQuery: { + fetchPolicy: 'no-cache', + errorPolicy: 'all', + }, + query: { + fetchPolicy: 'no-cache', + errorPolicy: 'all', + }, + }, +}); + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate = () => ( + + + +); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res(ctx.data(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res( + ctx.delay(800), + ctx.errors([ + { + message: 'Access denied', + }, + ]) + ); + }), + ], +}; +``` diff --git a/docs/snippets/react/documentscreen-story-msw-rest-request.js.mdx b/docs/snippets/react/documentscreen-story-msw-rest-request.js.mdx new file mode 100644 index 000000000000..d89a0ab9e49a --- /dev/null +++ b/docs/snippets/react/documentscreen-story-msw-rest-request.js.mdx @@ -0,0 +1,83 @@ +```js +// YourPage.stories.js | YourPage.stories.jsx | YourPage.stories.ts | YourPage.stories.tsx + +import React from 'react'; + +import { rest } from 'msw'; + +import DocumentScreen from './DocumentScreen'; + +export default { + component: DocumentScreen, + title: 'Mock Rest request with Storybook and MSW', +}; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate = () => ; + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + rest.get('https://your-restful-endpoint/', (_req, res, ctx) => { + return res(ctx.json(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + rest.get('https://your-restful-endpoint', (_req, res, ctx) => { + return res(ctx.delay(800), ctx.status(403)); + }), + ], +}; +``` diff --git a/docs/snippets/svelte/apollo-wrapper-component.with-mock-implementation.js.mdx b/docs/snippets/svelte/apollo-wrapper-component.with-mock-implementation.js.mdx new file mode 100644 index 000000000000..2793daec07b6 --- /dev/null +++ b/docs/snippets/svelte/apollo-wrapper-component.with-mock-implementation.js.mdx @@ -0,0 +1,29 @@ +```html + + + + +
+ +
+``` diff --git a/docs/snippets/svelte/document-screen-fetch.js.mdx b/docs/snippets/svelte/document-screen-fetch.js.mdx new file mode 100644 index 000000000000..f29ea5ebc88f --- /dev/null +++ b/docs/snippets/svelte/document-screen-fetch.js.mdx @@ -0,0 +1,47 @@ +```html + + + + +{#if status === "error"} +

There was an error fetching the data!

+{/if} +{#if status === "loading"} +

Loading...

+{:else} + + + + +{/if} +``` diff --git a/docs/snippets/svelte/document-screen-with-grapqhl.js.mdx b/docs/snippets/svelte/document-screen-with-grapqhl.js.mdx new file mode 100644 index 000000000000..051c2c64f593 --- /dev/null +++ b/docs/snippets/svelte/document-screen-with-grapqhl.js.mdx @@ -0,0 +1,46 @@ +```html + + + + +{#if $infoResult.loading} +

Loading...

+{:else if $infoResult.error} +

There was an error fetching the data!

+{:else} + + + + +{/if} +``` diff --git a/docs/snippets/svelte/documentscreen-story-msw-graphql-query.js.mdx b/docs/snippets/svelte/documentscreen-story-msw-graphql-query.js.mdx new file mode 100644 index 000000000000..2005122bfe1e --- /dev/null +++ b/docs/snippets/svelte/documentscreen-story-msw-graphql-query.js.mdx @@ -0,0 +1,92 @@ +```js +// YourPage.stories.js + +import { graphql } from 'msw'; + +import DocumentScreen from './DocumentScreen.svelte'; +import MockApolloWrapperClient from './MockApolloWrapperClient.svelte'; + +export default { + component: DocumentScreen, + decorators: [() => MockGraphqlProvider], + title: 'Mock GraphQL query with Storybook and MSW', +}; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate = (args) => ({ + Component: DocumentScreen, + props: args, +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res(ctx.data(TestData)); + }), + ], +}; +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res( + ctx.delay(800), + ctx.errors([ + { + message: 'Access denied', + }, + ]) + ); + }), + ], +}; +``` diff --git a/docs/snippets/svelte/documentscreen-story-msw-rest-request.js.mdx b/docs/snippets/svelte/documentscreen-story-msw-rest-request.js.mdx new file mode 100644 index 000000000000..953003799733 --- /dev/null +++ b/docs/snippets/svelte/documentscreen-story-msw-rest-request.js.mdx @@ -0,0 +1,83 @@ +```js +// YourPage.stories.js + +import DocumentScreen from './DocumentScreen.svelte'; + +import { rest } from 'msw'; +export default { + component: DocumentScreen, + title: 'Mock Rest request with Storybook and MSW', +}; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate = (args) => ({ + Component: DocumentScreen, + props: args, +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + rest.get('https://your-restful-endpoint', (_req, res, ctx) => { + return res(ctx.json(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + rest.get('https://your-restful-endpoint', (_req, res, ctx) => { + return res(ctx.delay(800), ctx.status(403)); + }), + ], +}; +``` diff --git a/docs/snippets/vue/apollo-wrapper-component.with-mock-implementation-3.js.mdx b/docs/snippets/vue/apollo-wrapper-component.with-mock-implementation-3.js.mdx new file mode 100644 index 000000000000..50ad3324eb03 --- /dev/null +++ b/docs/snippets/vue/apollo-wrapper-component.with-mock-implementation-3.js.mdx @@ -0,0 +1,41 @@ +```html + + + + + +``` diff --git a/docs/snippets/vue/document-screen-fetch.3.js.mdx b/docs/snippets/vue/document-screen-fetch.3.js.mdx new file mode 100644 index 000000000000..d39177051566 --- /dev/null +++ b/docs/snippets/vue/document-screen-fetch.3.js.mdx @@ -0,0 +1,54 @@ +```html + + + + +``` diff --git a/docs/snippets/vue/document-screen-with-graphql.3.js.mdx b/docs/snippets/vue/document-screen-with-graphql.3.js.mdx new file mode 100644 index 000000000000..650d7bfd4e88 --- /dev/null +++ b/docs/snippets/vue/document-screen-with-graphql.3.js.mdx @@ -0,0 +1,53 @@ +```html + + + + + +``` diff --git a/docs/snippets/vue/documentscreen-story-msw-graphql-query.3.js.mdx b/docs/snippets/vue/documentscreen-story-msw-graphql-query.3.js.mdx new file mode 100644 index 000000000000..24024e5b3bf6 --- /dev/null +++ b/docs/snippets/vue/documentscreen-story-msw-graphql-query.3.js.mdx @@ -0,0 +1,95 @@ +```js +// YourPage.stories.js + +import DocumentScreen from './DocumentScreen.vue'; +import WrapperComponent from './ApolloWrapperClient.vue'; + +import { graphql } from 'msw'; + +export default { + component: DocumentScreen, + title: 'Mock GraphQL query with Storybook and MSW', +}; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate = (args) => ({ + components: { DocumentScreen, WrapperComponent }, + setup() { + return { args }; + }, + template: '', +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res(ctx.data(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res( + ctx.delay(800), + ctx.errors([ + { + message: 'Access denied', + }, + ]) + ); + }), + ], +}; +``` diff --git a/docs/snippets/vue/documentscreen-story-msw-rest-request.3.js.mdx b/docs/snippets/vue/documentscreen-story-msw-rest-request.3.js.mdx new file mode 100644 index 000000000000..c4ee4e0b44fb --- /dev/null +++ b/docs/snippets/vue/documentscreen-story-msw-rest-request.3.js.mdx @@ -0,0 +1,87 @@ +```js +// YourPage.stories.js + +import { rest } from 'msw'; + +import DocumentScreen from './DocumentScreen.vue'; + +export default { + component: DocumentScreen, + title: 'Mock Rest request with Storybook and MSW', +}; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate = (args) => ({ + components: { DocumentScreen }, + setup() { + return { args }; + }, + template: '', +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + rest.get('https://your-restful-endpoint/', (_req, res, ctx) => { + return res(ctx.json(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + rest.get('https://your-restful-endpoint/', (_req, res, ctx) => { + return res(ctx.delay(800), ctx.status(403)); + }), + ], +}; +``` diff --git a/docs/workflows/build-pages-with-storybook.md b/docs/workflows/build-pages-with-storybook.md index 715b0cc0b661..93b0d7c20f7c 100644 --- a/docs/workflows/build-pages-with-storybook.md +++ b/docs/workflows/build-pages-with-storybook.md @@ -7,13 +7,13 @@ Storybook helps you build any component, from small “atomic” components to c There are many ways to build pages in Storybook. Here are common patterns and solutions. - Pure presentational pages. -- Connected components (e.g. network requests, context, browser environment). +- Connected components (e.g., network requests, context, browser environment). ## Pure presentational pages Teams at the BBC, The Guardian, and the Storybook maintainers themselves build pure presentational pages. If you take this approach, you don't need to do anything special to render your pages in Storybook. -It's straightforward to write components to be fully presentational all the way up to the screen level. That makes it easy to show in Storybook. The idea is you then do all the messy “connected” logic in a single wrapper component in your app outside of Storybook. You can see an example of this approach in the [Data](https://storybook.js.org/tutorials/intro-to-storybook/react/en/data/) chapter of the Intro to Storybook tutorial. +It's straightforward to write components to be fully presentational up to the screen level. That makes it easy to show in Storybook. The idea is that you do all the messy “connected” logic in a single wrapper component in your app outside of Storybook. You can see an example of this approach in the [Data](https://storybook.js.org/tutorials/intro-to-storybook/react/en/data/) chapter of the Intro to Storybook tutorial. The benefits: @@ -22,9 +22,9 @@ The benefits: The downsides: -- Your existing app may not be structured in this way and it may be difficult to change it. +- Your existing app may not be structured in this way, and it may be difficult to change it. -- Fetching data in one place means that you need to drill it down to the components that actually use it. This can be natural in a page that composes one big GraphQL query (for instance), but in other data fetching approaches may make this less appropriate. +- Fetching data in one place means that you need to drill it down to the components that use it. This can be natural in a page that composes one big GraphQL query (for instance), but other data fetching approaches may make this less appropriate. - It's less flexible if you want to load data incrementally in different places on the screen. @@ -64,23 +64,90 @@ In such cases it is natural to use [args composition](../writing-stories/args.md -This approach is particularly useful when the various subcomponents export a complex list of different stories, which you can pick and choose to build realistic scenarios for your screen-level stories without repeating yourself. By reusing the data and taking a Don't-Repeat-Yourself(DRY) philosophy, your story maintenance burden is minimal. +This approach is beneficial when the various subcomponents export a complex list of different stories. You can pick and choose to build realistic scenarios for your screen-level stories without repeating yourself. Your story maintenance burden is minimal by reusing the data and taking a Don't-Repeat-Yourself(DRY) philosophy. ## Mocking connected components -If you need to render a connected component in Storybook, you can mock the network requests that it makes to fetch its data. There are various layers in which you can do that. +If you need to render a connected component in Storybook, you can mock the network requests to fetch its data. There are various layers in which you can do that. ### Mocking providers -If you are using a provider that supplies data via the context, you can wrap your story in a decorator that supplies a mocked version of that provider. For example, in the [Screens](https://storybook.js.org/tutorials/intro-to-storybook/react/en/screen/) chapter of the Intro to Storybook tutorial we mock a Redux provider with mock data. +If you are using a provider that supplies data via the context, you can wrap your story in a decorator that provides a mocked version of that provider. For example, in the [Screens](https://storybook.js.org/tutorials/intro-to-storybook/react/en/screen/) chapter of the Intro to Storybook tutorial, we mock a Redux provider with mock data. -Additionally, there may be addons that supply such providers and nice APIs to set the data they provide. For instance [`storybook-addon-apollo-client`](https://www.npmjs.com/package/storybook-addon-apollo-client) provides this API: +### Mocking API Services + +Connected applications such as Twitter, Instagram, amongst others, are everywhere, consuming data either from REST or GraphQL endpoints. If you're working in an application that relies on either of these data providers, you can add Mock Service Worker (MSW) via [Storybook's MSW addon](https://storybook.js.org/addons/msw-storybook-addon) to mock data alongside your app and stories. + +[Mock Service Worker](https://mswjs.io/) is an API mocking library. It relies on service workers to capture network requests and provides mocked data in response. The MSW addon adds this functionality into Storybook, allowing you to mock API requests in your stories. + +#### Mocking REST requests with MSW addon + +If you're working with pure presentational screens, adding stories through [args composition](#args-composition-for-presentational-screens) is recommended. You can easily encode all the data via [args](../writing-stories/args.md), removing the need for handling it with "wrapper components". However, this approach loses its flexibility if the screen's data is retrieved from a RESTful endpoint within the screen itself. For instance, if your screen had a similar implementation to retrieve a list of documents: + + + + + + + +To test your screen with the mocked data, you could write a similar set of stories: + + + + + + + +
+đź’ˇ Note: This example details how you can mock the REST request with fetch. Similar HTTP clients such as axios can be used as well. +
+ +The mocked data (i.e., `TestData`) will be injected via [parameters](./writing-stories/parameters), enabling you to configure it per-story basis. + +#### Mocking GraphQL queries with MSW addon + +In addition to mocking RESTful requests, the other noteworthy feature of the [MSW addon](https://msw-sb.vercel.app/?path=/story/guides-introduction--page) is the ability to mock incoming data from any of the mainstream [GraphQL](https://www.apollographql.com/docs/react/integrations/integrations/) clients (e.g., [Apollo Client](https://www.apollographql.com/docs/), [URQL](https://formidable.com/open-source/urql/) or [React Query](https://react-query.tanstack.com/)). For instance, if your screen retrieves the user's information and a list of documents based on a query result, you could have a similar implementation: + + + + + + + +To test your screen with the GraphQL mocked data, you could write the following stories: @@ -88,11 +155,12 @@ Additionally, there may be addons that supply such providers and nice APIs to se ### Mocking imports -It is also possible to mock imports directly, as you might in a unit test, using webpack’s aliasing. This is extremely useful if your component makes network requests directly with third-party libraries. +It is also possible to mock imports directly, as you might in a unit test, using Webpack’s aliasing. It's advantageous if your component makes network requests directly with third-party libraries. We're going to use [isomorphic-fetch](https://www.npmjs.com/package/isomorphic-fetch) as an example. -Let's start by creating our own mock, which we'll use later with a [decorator](../writing-stories/decorators#global-decorators). Create a new file called `isomorphic-fetch.js` inside a directory called `__mocks__` (we'll leave the location to you, don't forget to adjust the imports to your needs) and add the following code inside: +Inside a directory called `__mocks__`, create a new file called +`isomorphic-fetch.js` with the following code: @@ -104,7 +172,7 @@ Let's start by creating our own mock, which we'll use later with a [decorator](. -The above code creates a decorator which reads story-specific data off the story's [parameters](../writing-stories/parameters), allowing you to configure the mock on a per-story basis. +The code above creates a decorator which reads story-specific data off the story's [parameters](../writing-stories/parameters), enabling you to configure the mock on a per-story basis. To use the mock in place of the real import, we use [webpack aliasing](https://webpack.js.org/configuration/resolve/#resolvealias): @@ -118,7 +186,7 @@ To use the mock in place of the real import, we use [webpack aliasing](https://w -Add the decorator you've just implemented to your [storybook/preview.js](../configure/overview.md#configure-story-rendering) (if you don't have it already, you'll need to create the file): +Add the decorator you've just implemented to your [storybook/preview.js](../configure/overview.md#configure-story-rendering): @@ -130,7 +198,7 @@ Add the decorator you've just implemented to your [storybook/preview.js](../conf -Once that configuration is complete, we can set the mock values in a specific story. Let's borrow an example from this [blog post](https://medium.com/@edogc/visual-unit-testing-with-react-storybook-and-fetch-mock-4594d3a281e6): +Finally, we can set the mock values in a specific story. Let's borrow an example from this [blog post](https://medium.com/@edogc/visual-unit-testing-with-react-storybook-and-fetch-mock-4594d3a281e6): @@ -147,17 +215,17 @@ Once that configuration is complete, we can set the mock values in a specific st ### Specific mocks -Another mocking approach is to use libraries that intercept calls at a lower level. For instance you can use [`fetch-mock`](https://www.npmjs.com/package/fetch-mock) to mock fetch requests specifically, or [`msw`](https://www.npmjs.com/package/msw) to mock all kinds of network traffic. +Another mocking approach is to use libraries that intercept calls at a lower level. For instance, you can use [`fetch-mock`](https://www.npmjs.com/package/fetch-mock) to mock fetch requests specifically. -Similar to the import mocking above, once you have a mock you’ll still want to set the return value of the mock on a per-story basis. Do this in Storybook with a decorator that reads story parameters. +Like the [import mocking](##mocking-imports) above, once you have a mock, you’ll still want to set the return value of the mock per-story basis. Do this in Storybook with a [decorator](../writing-stories/decorators.md) that reads the story's [parameters](../writing-stories/parameters.md). ### Avoiding mocking dependencies -It's possible to mostly avoid mocking the dependencies of connected "container" components entirely through passing them around via props, or React context. However, it necessitates a strict split of container and presentational component logic. For example, if you have a component that is responsible for data fetching logic and rendering DOM, it will need to be mocked as previously described. +It's possible to avoid mocking the dependencies of connected "container" components entirely by passing them around via props or React context. However, it requires a strict split of the container and presentational component logic. For example, if you have a component responsible for data fetching logic and rendering DOM, it will need to be mocked as previously described. -It’s common to import and embed container components in amongst presentational components. However, as we discovered earlier, in order to also render them within Storybook, we’ll likely have to mock their dependencies or the imports themselves. +It’s common to import and embed container components amongst presentational components. However, as we discovered earlier, to render them within Storybook, we’ll likely have to mock their dependencies or the imports themselves. -Not only can this quickly grow to become a tedious task, it’s also very difficult to mock container components that use local state. So, a solution to this problem is instead of importing containers directly, instead create a React context that provides the container components. This allows you to freely embed container components as usual, at any level in the component hierarchy without worrying about subsequently mocking their dependencies; since we can simply swap out the containers themselves with their mocked presentational counterpart. +Not only can this quickly grow to become a tedious task, but it’s also challenging to mock container components that use local states. So, instead of importing containers directly, a solution to this problem is to create a React context that provides the container components. It allows you to freely embed container components as usual, at any level in the component hierarchy without worrying about subsequently mocking their dependencies; since we can swap out the containers themselves with their mocked presentational counterpart. We recommend dividing context containers up over specific pages or views in your app. For example, if you had a `ProfilePage` component, you might set up a file structure as follows: @@ -170,13 +238,13 @@ ProfilePageContext.js
-It’s also often useful to setup a “global” container context, (perhaps named `GlobalContainerContext`) for container components that may be rendered on every page of your app, and adding it to the top level of your application. While it’s possible to place every container within this global context, it should only provide containers that are required globally. +It’s also often helpful to set up a “global” container context (perhaps named `GlobalContainerContext`) for container components that may be rendered on every page of your app and adding them to the top level of your application. While it’s possible to place every container within this global context, it should only provide globally required containers.
Let’s look at an example implementation of this approach. -First we’ll need to create a React context, and we can name it `ProfilePageContext`. It does nothing more than export a React context: +First, create a React context, and name it `ProfilePageContext`. It does nothing more than export a React context: @@ -222,7 +290,7 @@ If the same context applies to all `ProfilePage` stories, we can also use a [dec #### Providing containers to your application -Now, in context of your application, you’ll need to provide `ProfilePage` with all of the container components it requires by wrapping it with `ProfilePageContext.Provider`: +Now, in the context of your application, you’ll need to provide `ProfilePage` with all of the container components it requires by wrapping it with `ProfilePageContext.Provider`: For example, in Next.js, this would be your `pages/profile.js` component. @@ -238,7 +306,7 @@ For example, in Next.js, this would be your `pages/profile.js` component. #### Mocking global containers in Storybook -If you’ve setup `GlobalContainerContext`, in order to provide context to all stories you’ll need to set up a decorator within Storybook’s `preview.js`. For example: +If you’ve set up `GlobalContainerContext`, you’ll need to set up a decorator within Storybook’s `preview.js` to provide context to all stories. For example: diff --git a/docs/workflows/faq.md b/docs/workflows/faq.md index 8cb21dfc3a9c..6d794531ca57 100644 --- a/docs/workflows/faq.md +++ b/docs/workflows/faq.md @@ -10,8 +10,12 @@ In case you are having trouble with Angular Ivy you can deactivate it in your `m ```javascript module.exports = { - stories: [/* ... */], - addons: [/* ... */], + stories: [ + /* ... */ + ], + addons: [ + /* ... */ + ], angularOptions: { enableIvy: false, }, @@ -32,7 +36,7 @@ npm test -- --coverage --collectCoverageFrom='["src/**/*.{js,jsx}","!src/**/stor 💡 Note: If you're using yarn as a package manager, you'll need to adjust the command accordingly. -### I see `ReferenceError: React is not defined` when using storybooks with Next.js +### I see `ReferenceError: React is not defined` when using Storybook with Next.js Next automatically defines `React` for all of your files via a babel plugin. In Storybook, you can solve this either by: @@ -59,19 +63,22 @@ module.exports = { Fast refresh is an opt-in feature that can be used in Storybook React. There are two ways that you can enable it, go ahead and pick one: -* You can set a `FAST_REFRESH` environment variable in your `.env` file: +- You can set a `FAST_REFRESH` environment variable in your `.env` file: + ``` FAST_REFRESH=true ``` -* Or you can set the following properties in your `.storybook/main.js` files: +- Or you can set the following properties in your `.storybook/main.js` files: + ```js module.exports = { reactOptions: { fastRefresh: true, - } + }, }; ``` +
đź’ˇ Note: Fast Refresh only works in development mode with React 16.10 or higher.
@@ -81,6 +88,7 @@ module.exports = { A common error is that an addon tries to access the "channel", but the channel is not set. It can happen in a few different cases: 1. You're trying to access addon channel (e.g., by calling `setOptions`) in a non-browser environment like Jest. You may need to add a channel mock: + ```js import { addons, mockChannel } from '@storybook/addons'; @@ -110,12 +118,11 @@ class MyComponent extends Component { }; } // ... -}; +} export const defaultView = () => ; ``` - ### Why aren't Controls visible in the Canvas panel but visible in the Docs panel? If you're adding Storybook's dependencies manually, make sure you include the [`@storybook/addon-controls`](https://www.npmjs.com/package/@storybook/addon-controls) dependency in your project and reference it in your `.storybook/main.js` as follows: @@ -142,16 +149,16 @@ Starting with Storybook version 6.0, we've introduced some great features aimed With this, we would like to point out that if you plan on using addons created by our fantastic community, you need to consider that some of those addons might be working with an outdated version of Storybook. -We're actively working in providing a better way to address this situation, but in the meantime, we would ask a bit of caution on your end so that you don't run into unexpected problems. Let us know by creating an issue in the [Storybook repo](https://github.com/storybookjs/storybook/issues) so that we can gather information and create a curated list with those addons to help not only you but the rest of the community. +We're actively working to provide a better way to address this situation, but in the meantime, we would ask for a bit of caution on your end so that you don't run into unexpected problems. Let us know by creating an issue in the [Storybook repo](https://github.com/storybookjs/storybook/issues) so that we can gather information and create a curated list with those addons to help not only you but the rest of the community. ### Is it possible to browse the documentation for past versions of Storybook? With the release of version 6.0, we updated our documentation as well. That doesn't mean that the old documentation was removed. We kept it to help you with your Storybook migration process. Use the content from the table below in conjunction with our migration guide . -We're only covering version 5.3 and 5.0 as they were important milestones for Storybook. If you want to go back in time a little more, you'll have to check the specific release in the monorepo. +We're only covering versions 5.3 and 5.0 as they were important milestones for Storybook. If you want to go back in time a little more, you'll have to check the specific release in the monorepo. | Section | Page | Current Location | Version 5.3 location | Version 5.0 location | -|------------------|--------------------------------------------|------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| ---------------- | ------------------------------------------ | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | Get Started | Install | [See current documentation](../get-started/install.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide) | | | What's a story | [See current documentation](../get-started/whats-a-story.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | | | Browse Stories | [See current documentation](../get-started/browse-stories.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | @@ -201,18 +208,17 @@ We're only covering version 5.3 and 5.0 as they were important milestones for St | | Frameworks | [See current documentation](../api/new-frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | | | CLI options | [See current documentation](../api/cli-options.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/cli-options) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/cli-options) | -
With the release of version 5.3, we've updated how you can write your stories more compactly and easily. It doesn't mean that the storiesOf format has been removed. For the time being, we're still supporting it, and we have documentation for it. But be advised that this is bound to change in the future.
### What icons are available for my toolbar or my addon? -With the [`@storybook/components`](https://www.npmjs.com/package/@storybook/components) package, you get a set of icons that you can use to customize your own UI. Use the table below as a reference while writing your addon or defining your Storybook global types. +With the [`@storybook/components`](https://www.npmjs.com/package/@storybook/components) package, you get a set of icons that you can use to customize your UI. Use the table below as a reference while writing your addon or defining your Storybook global types. Go through this [story](https://5a375b97f4b14f0020b0cda3-wbeulgbetj.chromatic.com/?path=/story/basics-icon--labels) to see how the icons look. | accessibility | accessibilityalt | add | admin | alert | -|----------------|------------------|--------------|--------------|---------------| +| -------------- | ---------------- | ------------ | ------------ | ------------- | | arrowdown | arrowleft | arrowleftalt | arrowright | arrowrightalt | | arrowup | back | basket | batchaccept | batchdeny | | beaker | bell | bitbucket | book | bookmark | @@ -245,10 +251,9 @@ Go through this [story](https://5a375b97f4b14f0020b0cda3-wbeulgbetj.chromatic.co | useradd | useralt | users | video | watch | | wrench | youtube | zoom | zoomout | zoomreset | - ### I see a "No Preview" error with a Storybook production build -If you're using the `serve` package to verify your production build of Storybook, you'll get that error. It relates how `serve` handles rewrites. For instance, `/iframe.html` is rewritten into `/iframe`, and you'll get that error. +If you're using the `serve` package to verify your production build of Storybook, you'll get that error. It relates to how `serve` handles rewrites. For instance, `/iframe.html` is rewritten into `/iframe`, and you'll get that error. We recommend that you use [http-server](https://www.npmjs.com/package/http-server) instead and use the following command to preview Storybook: @@ -272,7 +277,48 @@ If you run into a situation where this is not the case, you can adjust the `conf See our documentation on how to customize the [Storyshots configuration](./snapshot-testing.md). - ### Why are my MDX stories not working in IE11? Currently there's an issue when using MDX stories with IE11. This issue does not apply to [DocsPage](../writing-docs/docs-page.md). If you're interested in helping us fix this issue, read our Contribution guidelines and submit a pull request. + +### Why are my mocked GraphQL queries failing with Storybook's MSW addon? + +If you're working with Vue 3, you'll need to install [`@vue/apollo-composable`](https://www.npmjs.com/package/@vue/apollo-composable). With Svelte, you'll need to install [`@rollup/plugin-replace`](https://www.npmjs.com/package/@rollup/plugin-replace) and update your `rollup.config` file to the following: + +```js +// rollup.config + +// Boilerplate imports + +import replace from '@rollup/plugin-replace'; +const production = !process.env.ROLLUP_WATCH; + +// Remainder rollup.config implementation + +export default { + input: 'src/main.js', + output: { + sourcemap: true, + format: 'iife', + name: 'app', + file: 'public/build/bundle.js', + }, + plugins: [ + // Other plugins + + // Configures the replace plugin to allow Grapqhl Queries to work properly + replace({ + 'process.env.NODE_ENV': JSON.stringify('development'), + }), +}; +``` + +With Angular, the most common issue is the placement of the `mockServiceWorker.js` file. Use this [example](https://github.com/mswjs/examples/tree/master/examples/rest-angular/) as a point of reference. + +### Can I use other GraphQL providers with Storybook's MSW addon? + +Yes, check the [addon's examples](https://github.com/mswjs/msw-storybook-addon/tree/master/packages/docs/src/demos) to learn how to integrate different providers. + +### Can I mock GraphQL mutations with Storybook's MSW addon? + +No, currently, the MSW addon only has support for GraphQL queries. If you're interested in including this feature, open an issue in the [MSW addon repository](https://github.com/mswjs/msw-storybook-addon) and follow up with the maintainer. \ No newline at end of file