zth / oneblog Goto Github PK
View Code? Open in Web Editor NEWGabriel
Home Page: https://infallible-nightingale-ff3368.netlify.com
Gabriel
Home Page: https://infallible-nightingale-ff3368.netlify.com
GraphQL + Relay is one of those things that simply changed my way of thinking about UIs and data. Building components with clear boundaries and explicit data requirements just clicked for me. In this article series I’ll try and outline my approach to testing Relay Modern apps in an as realistic way as possible.
I’ll also make use of Flow. Using static typing like Flow or TypeScript handles tons of things you’d otherwise need to cover with tests, and I strongly recommend using something like it if you can.
All articles in this series will be linked here as soon as they’re published:
I’ve made a sample repository that will show all of the techniques I outline in this series of articles. It’ll be updated as each article is written, and you can check it out here:
https://github.com/zth/relay-modern-flow-jest-example
So, there’s tons of different types of tests you could write for your typical UI. Tests of single components, styling being added and removed, the right methods being called. But, chances are if your ambitions are too high and if your tests are too detailed, you’ll write less and less of them. And that’s a way bigger problem than not testing enough detail.
So, what can we do to avoid that? Well, we want to make sure that whatever testing we do is as efficient and realistic as possible. We want to cover as much ground as we can with as little effort as possible. Contrary to other testing methods, when testing UI on a high level, you’ll want to use broad strokes and test as much as you can of your app in one go. Forget the mantra of testing things in isolation, and focus writing tests in a way that a user would actually use your app.
This philosophy means a few things for us:
For this to work efficiently, we have a few requirements:
Luckily, there are solutions for both. For rendering our app and interacting with it, we’ll use react-testing-library. It’s a great lib that forces us to write tests that aren’t tied to implementation details.
For mocking our data fetching with Relay Modern we’ll use graphql-query-test-mock, which is a lib I’ve written to ease both simple and complex mocking scenarios for testing apps using GraphQL clients like Relay Modern and Apollo.
We’ll start by installing the dependencies we need. Nock is a mocking library needed by graphql-query-test-mock, so we’ll install that. We also need to make sure there’s a fetch implementation available globally as Jest don’t provide one of its own. We’ll add node-fetch to fix that.
yarn add react-testing-library graphql-query-test-mock nock node-fetch --dev
Both react-testing-library and graphql-query-test-mock requires a little bit of setup in order to be properly cleaned up and reset between tests. We’ll make use of Jests setupTestFramework and setupFiles configuration options. If you’re not familiar with those two configurations in Jest, go ahead and look them up before continuing.
First, we’ll create and export a QueryMock using graphql-query-test-mock that we’ll use in all our tests to mock our queries. Go ahead and create a file somewhere accessible, and paste the following.
// @flow
import { QueryMock } from 'graphql-query-test-mock';
export const queryMock = new QueryMock();
A quick note: graphql-query-test-mock needs a way of figuring out what query or mutation is dispatched through the network layer, so if you haven’t already for other reasons, make sure you pass the query name when making requests. See an example passing name from operation in the body in fetchQuery below:
https://github.com/zth/relay-modern-flow-jest-example/blob/master/src/config/fetchQuery.js
In the file you’re using for setupTestFramework, make sure you have the following (this will run before each test):
import { cleanup } from 'react-testing-library';
import { queryMock } from '../path/to/your/queryMock';
beforeEach(() => {
// Make sure no mocks stick around between tests
queryMock.reset();
});
// Clean up any mounted DOM by react-testing-library
afterEach(cleanup);
And finally, in a file you use as setupFile with Jest, make sure you have this:
import { queryMock } from '../path/to/your/queryMock';
/**
* Initialize our queryMock and pass in the URL you use to make requests to your GraphQL API. */
queryMock.setup(GRAPHQL_API_URL);
/**
* Jest has no fetch implementation by default. We make sure fetch exists in our tests by using node-fetch here. */
global.fetch = require('node-fetch');
There, all set up!
Ok, lots of introduction. Time for the fun part! Let’s write our first test. This test will be really simple; we’ll mount our app, let it make it’s initial query, and make sure it renders.
Here’s the sample component we’ll use. Note that we’re making use of Flow and Relay’s auto generated Flow definitions for queries. This is awesome and in my opinion one of the primary features of Relay Modern.
// @flow
import * as React from 'react';
import { QueryRenderer, graphql } from 'react-relay';
import { environment } from '../config/createRelayEnvironment';
import type { AppQueryResponse } from './__generated__/AppQuery.graphql';
const query = graphql`
query AppQuery {
viewer {
id
currentUserCount
}
}
`;
export class App extends React.Component<{}> {
render() {
return (
<div className="App">
<QueryRenderer
environment={environment}
query={query}
render={({
error,
props
}: {
error: Error,
props: AppQueryResponse
}) => {
if (error) {
console.error(error);
return <div className="ErrorScreen">Something went wrong!</div>;
}
if (props) {
return (
<div className="AppDisplayer">
<h1>User count: {props.viewer.currentUserCount}</h1>
</div>
);
}
// No error or props means we're loading still
return <div className="AppDisplayer--loading">Loading app...</div>;
}}
/>
</div>
);
}
}
So, this component makes a query called AppQuery which fetches a user count that we then show in a title. Let’s go ahead and make a very simple test:
// @flow
import * as React from 'react';
import { queryMock } from '../../__testUtils__/queryMock'; // Or wherever your queryMock is located
import { App } from '../App';
import { render, wait } from 'react-testing-library';
describe('App', () => {
it('should render the current user count', async () => {
/**
* App fetches the query AppQuery. Here, we mock all requests for that query.
*/
queryMock.mockQuery({
name: 'AppQuery',
data: {
viewer: {
id: '1',
currentUserCount: 12
}
}
});
/**
* We mount the app and wait for our element that displays the app's content
* to be visible.
*/
const r = render(<App />);
// If App works, we'll see "User count: 12" when it has made its request and rendered.
await wait(() => r.getByText('User count: 12'));
// There! That's all that's needed. If "User count: 12" does not appear within the timeout, something's up and the test will fail.
});
});
There! With this small and simple test we’ve actually tested our whole setup. This test passing actually tells us that our Relay setup is working all the way from query -> network -> render.
… And that’s it! Next article in this series is about more complex testing of queries, testing pagination and testing states in your app like errors and loading. Thanks for reading!
{"source":"medium","postId":"559b6d7fe9f8","publishedDate":1535490679736,"url":"https://medium.com/@_zth/testing-a-relay-modern-graphql-app-part-1-testing-a-simple-query-559b6d7fe9f8"}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.