State of testing Relay powered components
See original GitHub issueWe’ve been trying a few different things and haven’t settled on a solution yet that satisfies all the, in my mind, requirements. So I figured it might be time to write up those requirements, the things we’ve experimented with, and what the final solution could be.
Requirements
- Exercise fragments: to verify that fragments select the correct fields.
- Exercise containers: to verify that container configuration is correct (really only refetch/pagination containers).
- Easy to use: i.e. easy to provide required mock data (typed data highly preferable).
- Fast tests: because slow tests scale badly.
Tried options
RelayStubProvider
This approach mocks all of the Relay API and inserts data directly into the components. An example can be found here
- Exercise fragments: Some coverage could be provided by using the types emitted for the fragment, but those also only go 1 level deep and thus don’t cover children of the container.
- Exercise containers: None
- Easy to use:
- Fast tests:
relay-mock-network-layer / renderRelayTree
This approach mocks our schema, uses a Relay network layer that directly queries the mocked schema, and uses renderRelayTree
to keep rendering the React tree until the Relay containers have all rendered.
- Exercise fragments: Actual queries are performed.
- Exercise containers: No Relay APIs are mocked.
- Easy to use: Figuring out what data to provide and how to provide it has been a constant pain. The graphql-tools
addMockFunctionsToSchema
functionality provides little guidance in what data is missing and how it should be mocked. - Fast tests: Everything related to the network layer is async, so we need to update, poll, and scan the tree continuously to know if the containers have been rendered, which is turning out to be too slow.
I could see us extending Relay to emit types for all containers in the entire tree, which would make stubbing the schema exactly according to those types trivial. The only additional change needed would be for addMockFunctionsToSchema
to infer what aliased fields to stub based on the passed in data. (Currently if in our fragments we select e.g. foo: bar
, where foo
is an alias of the bar
field, addMockFunctionsToSchema
expects us to mock the bar
field.)
Next options
Entire mocked copy of our GraphQL service
We haven’t done this yet, but an option I discussed with @ds300 was to add a ‘VCR’ library to our GraphQL service that would be able to record all the possible upstream requests and replay those when importing the service into our component libraries.
- Exercise fragments: Same as relay-mock-network-layer / renderRelayTree
- Exercise containers: relay-mock-network-layer / renderRelayTree
- Easy to use: Unlike relay-mock-network-layer / renderRelayTree, there wouldn’t be a need to do any data mocking, because the real data that our service provides has already been captured. (Albeit limited in permutations of the data.)
- Fast tests: Same as relay-mock-network-layer / renderRelayTree
Use Relay store API
Relay has an imperative store API, which we thus far have interacted with only when updating the store after mutations, but this is what the Relay library tests use.
- Exercise fragments: Need to verify this, but as Relay uses the fragments to select data from the normalised store, I think this could be enough to ensure the fragments select the right data.
- Exercise containers: No mocking of container APIs.
- Easy to use: We could easily add the ability to Relay to emit types for an entire tree and then create an API that would insert that data into the store.
- Fast tests: Once data is in the store, we can tell a
QueryRenderer
to synchronously render data that’s already available in the store.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:7
- Comments:9 (7 by maintainers)
Top GitHub Comments
For now I’m thinking of starting work on making Relay emit types for the entire tree and update
addMockFunctionsToSchema
to automatically handle aliased fields, because that should ease the current pain points of “relay-mock-network-layer / renderRelayTree”, but also be a stepping stone to the “Use Relay store API” option.@josephsavona Yeah that’s what I meant. It would be helpful in knowing all the fixture data that the dev needs to provide without reading all of the fragments of the containers involved and looking up the types of the fields selected in those fragments.
True, I should clarify that we currently have query renderers in our tests for subsets of an entire product view, so the data tree would be significantly smaller.
An example of what I’d imagine a test would look like: