Testing strategy on Relay + React

Testing strategy on Relay + React

I am experimenting with React + Relay + Graphql these days. Unfortunately, I cannot find any easy and convenient way to test React component wrapped by Relay Container.
Basically, I would like to achieve these goals along TDD,

Render a container and test its content,
Change variables and test its changes on content.

Compared with React + Flux, React + Relay is more like black box, or, declarative.
I can see people mock Relay.createContainer to bypass Relay and merely test React Component. It leaves the Relay part uncovered and there is no way to drive this part by testing.
https://github.com/facebook/relay/issues/161
Also, I read through test cases of Relay and its really tedious to render a mock container.
https://github.com/facebook/relay/blob/master/src/tools/mocks/RelayTestUtils.js
I will be really grateful if you can share you solution.
Thanks!

Solutions/Answers:

Solution 1:

I’ve been trying to test Relay containers like I would components in a Flux application. Specifically, I want to make sure that they render the correct content for a given state and props and that they call methods to change data in appropriate places; in Flux this is a call to an action creator, in Relay this is a call to Relay.Store.update or this.props.relay.setVariables.

My first attempt was to build a RelayTestUtil object with a renderContainerIntoDocument method. I based it heavily on https://github.com/facebook/relay/blob/master/src/tools/mocks/RelayTestUtils.js, https://github.com/facebook/relay/blob/master/src/legacy/store/mocks/GraphQLStoreQueryResolver.js, and the Relay Container tests. This used very minimal mocking and was great for testing container rendering but was completely useless for testing data changes. Trying to spy on calls to Relay.Store.update and this.props.relay.setVariables, or to mock data changes, became more trouble than it was worth.

Related:  Fetch API cannot load webpack://… error

I settled on adding __mocks__\react-relay.js to completely mock Relay and using simpler version of RelayTestUtils.renderContainerIntoDocument to inject Relay properties into a container. I’m not entirely satisfied with this solution, but it seems to work for now.

__mocks__\react-relay.js:

var Relay = require.requireActual('react-relay');
var React = require('react');

module.exports = {
  QL: Relay.QL,
  Mutation: Relay.Mutation,
  Route: Relay.Route,
  Store: {
    update: jest.genMockFn()
  },
  createContainer: (component, containerSpec) => {
    const fragments = containerSpec.fragments || {};

    // mock the static container methods
    Object.assign(component, { getFragment: (fragmentName) => fragments[fragmentName] });

    return component;
  }
};

RelayTestUtils.js:

const React = require('react');
const ReactDOM = require('react-dom');


const RelayTestUtils = {
  renderContainerIntoDocument(containerElement, relayOptions) {
    relayOptions = relayOptions || {};

    const relaySpec = {
      forceFetch: jest.genMockFn(),
      getPendingTransactions: jest.genMockFn().mockImplementation(() => relayOptions.pendingTransactions),
      hasOptimisticUpdate: jest.genMockFn().mockImplementation(() => relayOptions.hasOptimisticUpdate),
      route: relayOptions.route || { name: 'MockRoute', path: '/mock' },
      setVariables: jest.genMockFn(),
      variables: relayOptions.variables || {}
    };

    return ReactDOM.render(
      React.cloneElement(containerElement, { relay: relaySpec }),
      document.createElement('div')
    );
  }
};

export default RelayTestUtils;

Tests look something like this, where fragmentData matches the shape of the GraphQL response:

it('changes items', () => {
  const myContainer = RelayTestUtils.renderContainerIntoDocument(
    <MyContainer { ...fragmentData }/>, 
    { variables: { itemId: 'asdf' } }
  );
  myContainer.changeItem();
  expect(myContainer.props.relay.setVariables).toBeCalled();
});

Solution 2:

I’ve wrote a blog post of how to test Relay using Jest against a working GraphQL backend: https://medium.com/entria/relay-integration-test-with-jest-71236fb36d44#.an74bdopy

This repo https://github.com/sibelius/relay-integration-test contains examples of testing react web and react native using Relay

References