In my React storybooks, I want to be able to toy around with components that use graphQL queries and mutations (implemented with Apollo).
This works fine using MockedProvider, as long as I specify in-advance the exact mutations, including their inputs.
I want to know if it is possible/how to not specify the inputs in advance, to accept any inputs.
export const MyComponent = () => (
<Mutation mutation={gql`some mutation`}>
{(doMutation, { loading, error, data }) => (
<Button onClick={()=> doMutation({input: {
someInput: Math.rand()*10 // Would be fine if this was 1.
}}) />
{data ? <>Result: {data.someResult}</> : null}
)
</Mutation>
)
storiesOf('MyComponent', module)
.add('some story', () => (
<StaticRouter context={{}}>
<MockedProvider
mocks={[
{
request: {
query: gql`some query...`,
variables: { input: { someInput: '1' } },
},
result: { data: { someResult: '1' } },
},
]}
addTypename={true}
>
<MyComponent />
</MockedProvider>
</StaticRouter>
))
In the pseudo-example above, the storybook will work fine if I send '1' as my input, but will not work for any other number - the mock must match exactly or I get "no more mocked responses for someMutation with variables {...}".
This is not a problem in tests, but in storybooks it'd be nice to be able to test with any values.
I found a way to do what I wanted, albeit not using MockedProvider
.
First, convert to hooks.
export const MyComponent = () => {
const [doMutation, {loading, data, error}] = useMutation(gql`some mutation`)
return (
<Button onClick={()=> doMutation({input: {
someInput: Math.rand()*10 // Would be fine if this was 1.
}}) />
{data ? <>Result: {data.someResult}</> : null}
);
}
Now dependency-inject the mutation hook, using react-magnetic-di
export const useMyMutation = () => useMutation(gql`some mutation`)
export const MyComponent = () => {
di(useMyMutation)
const [doMutation, {loading, data, error}] = useMyMutation() // Will be the in-scope variable `useMyMutation` from above unless expressly injected during stories/tests.
return (
<Button onClick={()=> doMutation({input: {
someInput: Math.rand()*10 // Would be fine if this was 1.
}}) />
{data ? <>Result: {data.someResult}</> : null}
);
}
Now you can write stories/tests with custom implementations.
export const useMockMyMutation = injectable(
myMutation, // imported from the component, types are checked against it.
() => [function thisWillBeDoMutation(){}, {loading: false, data: {}, error: null}])
storiesOf('MyComponent', module)
.add('some story', () => (
<StaticRouter context={{}}>
<DiProvider target={MyComponent} use={[useMockMyMutation]}>
<MyComponent />
</DiProvider>
</StaticRouter>
))
So we directly supply any function for the doMutation, and you can make that change the values used for loading
/data
/error
etc. if you need to.
We've made a lot of tooling to make it a bit more streamlined, so extracting this example was a bit tricky so you'll need to do a bit of playing around with react-magnetic-di; but this is the gist of it.
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With