-
Notifications
You must be signed in to change notification settings - Fork 786
How to use the MockedProvider #1711
Comments
Yes, have run into a similar but slightly different issue. For enzyme, use In our situation, we would see the loader component but didn't have a way to check the child component. This is how we workaround it...
|
There's some discussion of this over at enzyme issue #728 as well. It seems the issue is that MockedProvider's mocked queries are still async, and the Promises returned aren't accessible (are they?) to the test framework. I haven't tried this, but perhaps you could put your expectations inside a handler for the Promise returned by a call to MockedProvider's .props.client.resetStore() ? A bit convoluted (and you'd do your query twice), but it might be an improvement over messing with timeouts or trying to find something an enzyme selector can grab onto to assure the data has all been delivered to the component... |
Finally got it to work it('will render data', async () => {
const mocks = [
{
request: { query },
result: { data: { hello: 'world' } }
}
]
const wrapper = mount(
<MockedProvider mocks={mocks}>
<TestCompHoc />
</MockedProvider>
)
await new Promise(resolve => setTimeout(resolve))
wrapper.update()
expect(wrapper).toContainReact(<h1>Hello world</h1>)
}) @fc Next tick doesn't work but for some reason setTimeout does. TL:DR; await Anyway this doesn't really solve the bigger issue of no documentation on how to test graphql HOC components. The docs page doesn't even mention testing this seems like a glaring omission. |
@andrew-w-ross Just finished a blog post on testing to help out: http://blog.dideric.is/2018/03/18/Testing-apollo-containers/. |
In my case it wasn't working because Apollo adds
As is done in the example here: |
...although it looks like that will no longer be necessary in the next version: |
@mbrowne Any eta on documentation? |
I think probably only the core Apollo team can answer that |
Thanks @andrew-w-ross something similar we're using with react-test-renderer:
And in a test:
|
Note that there's an optional |
While I can't speak for the Apollo team, I suppose this whole thing should be considered an experimental API. |
@teeeg Thanks, It's a neater solution. I also didn't know about |
facing the same issue MockedProvider is rendering loading when executing synchronously but it doesn't render anything when running async using jest. Jest debug confirms this <MockedProvider mocks={{...}} addTypename={false}>
<ApolloProvider client={{...}}>
<WithQuery orgId={1} modelId={1} userId={1} territories={{...}} dataSource="ds1" problemUnit="pUnit">
<Query query={{...}} notifyOnNetworkStatusChange={true} displayName="DataDistributionQuery" context={{...}} variables={{...}} />
</WithQuery>
</ApolloProvider>
</MockedProvider> |
@gandhiamarnadh Did you try my solution above with waiting and then updating the render? await new Promise(resolve => setTimeout(resolve))
wrapper.update() |
@andrew-w-ross yes it's working, I've split my test cases into three files (loading, error and success) now it's passing, when they are together in a single file graphQl error is triggered in most test cases |
I had the same problem. Took the better part of a day to research the solution. Posting here to save the next guy time. The mocked response data has to match the query EXACTLY, or none of the data is added to the resolved graphql. I mean, EXACTLY. I also had to add type names the query. Setting typeName to false did not work for me. There is a npm package that can auto-add typenames to queries for you. This thread helped me out: #674 |
Note that the variables also have to be in the same order. |
If you don't want to have to worry about it complaining because of missing |
Note that the API changed; the |
I've run into issues where because I have fragments on unions and interface types, I must include the // Test error from a query that is on interface types
console.error node_modules/apollo-utilities/lib/bundle.umd.js:886
You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types.
Apollo Client will not be able to able to accurately map fragments.To make this error go away, use the IntrospectionFragmentMatcher as described in the docs: https://www.apollographql.com/docs/react/recipes/fragment-matching.html |
@kristiehowboutdat It might not be possible using MockedProvider, but you could try using MockLink directly (which MockedProvider uses under the hood), as is done here for example: You might be able to get around the typename issue by setting up a fragment matcher on your test ApolloClient in the same way you would in your real app. |
Looks like some documentation for MockedProvider was added back in June: |
@mbrowne Ah that great news perhaps next project I can actually use it now. |
FYI this is insanely frustrating and important... took two engineers a day to figure this out on one of our tests. |
We got it to work with await wait(1) which is terribly wrong but it seems we have to await something.... similar to how @andrew-w-ross awaited this await new Promise(resolve => setTimeout(resolve)) |
Another option is to use jest's mocking feature ( The mock provider I wrote is a little fancier...it can be used like this: const mocks = new Map()
// GalleryQuery is a thin wrapper around Apollo's Query component
// that includes a graphql query that fetches Gallery data (specific to our domain)
mocks.set(GalleryQuery, [
{
request: {
variables: { galleryId },
},
result: {
data: {
gallery: mockGallery,
},
},
},
])
const wrapper = mount(
<MockQueryLoaderProvider mocks={mocks}>
<Gallery />
</MockQueryLoaderProvider>
)
MockQueryLoaderProvider.subscribe(GalleryQuery, queryResult => {
// get the <Gallery> component
const galleryWrapper = queryLoaderContentsWrapper.update()
const props = galleryWrapper.props()
expect(props.gallery).toEqual(queryResult.data.gallery.data)
// more test code...
}) That way if the component you're testing (and its subcomponents) call multiple queries, you can be specific about which query result you expect for which query, and things like waiting for responses are all abstracted away in the And just to share one small bit of the implementation, here are the constructor and render methods of constructor(props: MockQueryLoaderProviderProps, context: any) {
super(props, context)
const link = new MockLink(buildMocksForMockLink(props.mocks))
this.client = new ApolloClient({
link,
cache: new Cache({ addTypename: false }),
defaultOptions: props.defaultOptions,
})
}
render() {
return (
<ApolloProvider client={this.client}>
{this.props.children}
</ApolloProvider>
)
} Disclaimer: I think sometimes when people see "Contributor" next to my name, they might think I'm on the Apollo team. I am not (I just contributed a small PR), and none of this is official advice. |
@mbrowne Yeah, that's similar to the approach I took. Using the lower level testing tools to create your own provider isn't that bad, and it's easier to work with, imo, since it's easier to see what's going on. Creating your own provider also allows you to mock out other global stuff like redux so you don't have to worry about bringing in the right mock providers for whatever your testing; you can just plop the same test provider around any smart component you want to test.
Assuming you have access to a plain text version of the schema wherever your client is, you can use it to mock out resolvers rather than specific queries. It's a less brittle approach, imo, since you can refactor the query a component uses without necessarily needing to change the mocks for that query (you end up testing that the query works given resolver results rather just copying the query into the mock every time you change it). You also get a heads up if the a query you're using is not longer valid with the current schema; if you're just mocking requests/responses, you risk false positives. (more details in that guide I linked above.) |
Spend there around 4 hours to realize it was about the order of the data... Lesson learned, but that should be fixed to not fall into this kind of tricks... My head is completely destroyed right now and my frustration is very high |
@Ruffeng Mind explaining what happened? |
Sure. I‘ve tried to work with mockedProvider for a specific component. It‘s the first time i am using it, but applied in a couple components before. My surprise was that the component didn‘t receive any error, but received as well an empty object as data. After some time trying to figure it out, i ended up in this thread saying that the response needs exactly the same order as the query, where i just had one field that wasn‘t aligned with the query. After applying it, i received my mock. From now I know if never happens again what to do, but I see some people here that happened the same and probably more people will happen it in the future. Could be nice if for the future versions the order isn‘t so important as it is now for the mocked result :+1 |
I tried this today and it still doesn't work for me. Does anyone see this with version 2.5.4? |
The approaches above didn't work for the hook version. Using |
@damiangreen our problems should be fixed in this commit . Just in case, please double-check that the mocked response it's following exactly the same order as the query (and all other deeper objects from the query). |
Great, will you update this issue when it's released? cheers |
@Ruffeng Thank you so much for this! I had the same issue and spent 4+ hours trying to figure out why my tests weren't working, when finally I came upon your comment. 👍 |
Intended outcome:
Test a graphql component with
MockedProvider
Actual outcome:
The first test with Loading works. The second where the result should be
<h1>hello world<h1>
does not.How to reproduce the issue:
Usual
create-react-app
with the following test in jestThe bigger issue is there is no documentation on how to test graphql components.
Version
The text was updated successfully, but these errors were encountered: