私はreact-apolloを使用して、GraphQL APIを使用するクライアントを構築していますが、テストに非常に固執しています。私が欲しいのは、サーバーをモックして、ネットワーク呼び出しを行わなくてもアプリケーションを簡単にテストできるようにすることです。
サーバーをモックする方法に関するいくつかの指針を見つけました。
しかし、サーバーにぶつからないようにするために、アプリのテストでこのモックサーバーを使用する方法の例は実際にはありません。
私の目標は、アプリが実際に機能していることを確認するための統合テストを設定することです。
describe('Profile feature', () => {
beforeAll(() => {
store = setupStore();
app = mount(
<ApolloProvider store={store} client={apolloClient}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</ApolloProvider>
);
});
});
ストアはReduxを使用しており、クライアントは次のように作成されています。
const networkInterface = createNetworkInterface({
uri: process.env.REACT_APP_API_URL
});
export const apolloClient = new ApolloClient({
networkInterface
});
実際のAPIの代わりに、ここでgraphql-toolsを使用してモックサーバーを使用するにはどうすればよいですか?
Apollo-clientクエリのモックデータを作成する2つの異なる方法を見つけました。
1つ目は、 graphql-tools を使用して、バックエンドスキーマに基づいてモックサーバーを作成することです。このモックサーバーをテストに接続するために、次のようなmockNetworkInterfaceを作成できます。
const { mockServer } = require("graphql-tools");
const { print } = require("graphql/language/printer");
class MockNetworkInterface {
constructor(schema, mocks = {}) {
if (schema === undefined) {
throw new Error('Cannot create Mock Api without specifying a schema');
}
this.mockServer = mockServer(schema, mocks);
}
query(request) {
return this.mockServer.query(print(request.query), request.variables);
}
}
このネットワークインターフェイスをApolloClientコンポーネントに渡すことができ、問題なく動作するはずです。
この設定を行うには、クライアントでAPIスキーマを最新の状態にする必要があるため、少し面倒だと思いました。
これを行う別の方法は、apollo-client/test-utils
によって提供されるmockNetworkInterface
を使用することです。
次のように使用できます。
import App from './App';
import { UserMock, PublicationMock } from '../__mocks__/data';
import { mockNetworkInterface } from 'react-apollo/test-utils';
import ApolloClient from 'apollo-client';
import { ApolloProvider } from 'react-apollo';
// We will be using here the exact same Query defined in our components
// We will provide a custom result or a custom error
const GraphQLMocks = [
{
request: {
query: UserProfileQuery,
variables: {}
},
result: {
data: {
current_user: UserMock
}
}
}
];
// To set it up we pass the mocks to the mockNetworkInterface
const setupTests = () => {
const networkInterface = mockNetworkInterface.apply(null, GraphQLMocks);
const client = new ApolloClient({ networkInterface, addTypename: false });
const wrapper = mount(
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
return {
store,
wrapper
};
};
// Then the tests look like this
describe('Profile feature', () => {
test('Profile view should render User details', async () => {
const { wrapper, store } = setupTests();
const waitFor = createWaitForElement('.profile');
await waitFor(wrapper);
const tag = wrapper.find('.profile-username');
expect(tag.text()).toEqual(`${UserMock.first_name} ${UserMock.last_name}`);
});
});
addTypename: false
をApolloClient
インスタンスに渡すことが重要です。そうしないと、すべてのクエリに__typename
を手動で追加する必要があります。
ここでmockNetworkInterfaceの実装を調べることができます: https://github.com/apollographql/apollo-test-utils/blob/master/src/mocks/mockNetworkInterface.ts
MockedProviderを使用することもできます。これにより、さらに簡単になります。
withPersons.js
_import { gql, graphql } from 'react-apollo'
export const PERSONS_QUERY = gql`
query personsQuery {
persons {
name
city
}
}
`
export const withPersons = graphql(PERSONS_QUERY)
_
withPersons.test.js
_/* eslint-disable react/prop-types */
import React, { Component } from 'react'
import { MockedProvider } from 'react-apollo/test-utils'
import { withPersons, PERSONS_QUERY } from '../withPersons'
it('withPersons', (done) => {
const mockedData = {
persons: [
{
name: 'John',
city: 'Liverpool',
},
{
name: 'Frank',
city: 'San Diego',
},
],
}
const variables = { cache: false }
class Dummy extends Component {
componentDidMount() {
const { loading, persons } = this.props.data
expect(loading).toBe(true)
expect(persons).toBe(undefined)
}
componentWillReceiveProps(nextProps) {
const { loading, persons } = nextProps.data
expect(loading).toBe(false)
expect(persons).toEqual(mockedData.persons)
done()
}
render() {
return null
}
}
const DummyWithPersons = withPersons(Dummy)
mount(
<MockedProvider
removeTypename
mocks={[
{
request: { query: PERSONS_QUERY, variables },
result: { data: mockedData } },
]}
>
<DummyWithPersons />
</MockedProvider>,
)
})
_
注:ダミーコンポーネントを使用することで、graphql()
クエリとミューテーション、およびそれらを構成した方法(オプション、小道具、スキップ、変数など)をテストするだけなので、実際のReactコンポーネント。 「接続されていない」状態でテストすることをお勧めします。
しばらくの間、役立つかもしれないブログ投稿を書きました: http://blog.dideric.is/2018/03/18/Testing-apollo-containers/
Apolloには LinkSchema と呼ばれるものがあり、Carlosが最初に言及したアプローチをはるかに簡単にします。まだセットアップは必要ですが、それだけの価値があると思います。手動で応答を作成している場合は、テストを最新の状態に保つことや、スキーマが変更されてコードでそれを考慮していないときに誤検知が発生することについて、さらに心配する必要があります。