question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

State of testing Relay powered components

See original GitHub issue

We’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:closed
  • Created 5 years ago
  • Reactions:7
  • Comments:9 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
alloycommented, Nov 28, 2018

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.

1reaction
alloycommented, Nov 30, 2018

Do you mean a flow type describing the shape of the full query response? I’m curious how having a flow type to describe that would be helpful

@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.

for a lot of products that could also be a gigantic flow type.

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:

// ArtworkMetadata.tsx

import { createFragmentContainer, graphql } from "react-relay"
import { ArtworkMetadata_artwork } from "__generated__/ArtworkMetadata.graphql"

export const ArtworkMetadata: React.SFC<{ artwork: ArtworkMetadata_artwork }> = createFragmentContainer(
  ({ artwork }) => <span>{artwork.title} – {artwork.artist.name}</span>,
  graphql`
    fragment ArtworkMetadata_artwork on Artwork {
      title
      artist {
        name
      }
    }
  `
)
// ArtworkBrick.tsx

import { createFragmentContainer, graphql } from "react-relay"
import { ArtworkBrick_artwork } from "__generated__/ArtworkBrick.graphql"

export const ArtworkBrick: React.SFC<{ artwork: ArtworkBrick_artwork }> = createFragmentContainer(
  ({ artwork }) => <div><img src={artwork.image.url} /><ArtworkMetadata artwork={artwork} /></div>,
  graphql`
    fragment ArtworkBrick_artwork on Artwork {
      image {
        url
      }
      ...ArtworkMetadata_artwork
    }
  `
)
// ArtworkBrick.test.tsx

import { graphql, mockEnvironmentWithStore , QueryRenderer } from "react-relay"
import { mount } from "enzyme"
import { ArtworkBrickTestQuery, ArtworkBrickTestQueryUnmaskedResponse } from "__generated__/ArtworkBrick.test.graphql"

const query = graphql`
  query ArtworkBrickTestQuery($artworkID: ID!) {
    artwork(id: $artworkID) {
      ...ArtworkBrick_artwork
    }
  }
`

const artworkFixture: ArtworkBrickTestQueryUnmaskedResponse = {
  artwork: {
    title: "Monkey Sign",
    image: {
      url: "https://d32dm0rphc51dk.cloudfront.net/L52FHh7v_f9mZ3QkC_2YJA/thumbnail.jpg"
    }
    artist: {
      name: "Banksy"
    }
  }
}

describe("ArtworkBrick", () => {
  it("renders synchronously", () => {
    const tree = mount(
      <QueryRenderer<ArtworkBrickTestQuery>
        dataFrom={STORE_THEN_NETWORK}
        environment={mockEnvironmentWithStore(artworkFixture)}
        query={query}
        variables={{ artworkID: "banksy-monkey-sign" }}
        render={props => <ArtworkBrick artwork={props.artwork}}
      />
    )

    expect(tree.find("span").text).toEqual("Monkey Sign - Banksy")
    // etc
  })
})
Read more comments on GitHub >

github_iconTop Results From Across the Web

Testing Relay Components
The purpose of this document is to cover the Relay APIs for testing Relay components. The content is focused mostly on jest unit-tests...
Read more >
3 Ways to Test a Relay - wikiHow
1. Do a basic visual inspection of the relay. Many relays have a clear plastic shell containing the coil and contacts. Visible damage...
Read more >
How To Test A Relay | The Drive
Your vehicle has a variety of electrical components that power everything ... Thankfully, testing a relay is a task that even amateur mechanics...
Read more >
How to Test a Relay? Checking SSR & Coil Relays
Testing Solid State Relay in Diode Test Mode (DMM) · Rotate the multimeter knob to the “Diode Test Mode” as shown in fig...
Read more >
How to Test a Relay with a Multimeter? - Electronics Hub
Another test we can do with the multimeter is the continuity between the three high-power contacts of the relay. When the relay is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found