···
9
+
When testing your components, you're likely going to want to check arguments and force different states for your components using Urql.
11
+
> **Note:** Examples demonstrate the _React hooks_ version of Urql being used but underlying patterns apply to all implementations.
13
+
## Mocking the client
15
+
For the most part, Urql's hooks are just adapters for talking to the Urql client.
17
+
The way in which they do this is by making calls to the client via context.
19
+
- `useQuery` calls `executeQuery`
20
+
- `useMutation` calls `executeMutation`
21
+
- `useSubscription` calls `executeSubscription`
23
+
Here's an example client mock being used while testing a component.
26
+
import { mount } from 'enzyme';
27
+
import { Provider } from 'urql';
28
+
import { MyComponent } from './MyComponent';
30
+
const mockClient = {
31
+
executeQuery: jest.fn(),
32
+
executeMutation: jest.fn(),
33
+
executeSubscription: jest.fn(),
36
+
it('renders', () => {
37
+
const wrapper = mount(
38
+
<Provider value={mockClient}>
45
+
## Testing calls to the client
47
+
Once you have your mock setup, calls to the client can be tested.
50
+
it('skips the query', () => {
52
+
<Provider value={mockClient}>
53
+
<MyComponent skip={true} />
56
+
expect(mockClient.executeQuery).toBeCalledTimes(0);
60
+
Testing mutations and subscriptions also work in a similar fashion.
63
+
it('triggers a mutation', () => {
64
+
const wrapper = mount(
65
+
<Provider value={mockClient}>
75
+
.simulate('change', { currentTarget: { value: variables.name } });
76
+
wrapper.find('button').simulate('click');
78
+
expect(mockClient.executeMutation).toBeCalledTimes(1);
79
+
expect(mockClient.executeMutation).toBeCalledWith(
80
+
expect.objectContaining({ variables })
87
+
For testing render output, or creating fixtures, you may want to force the state of your components.
91
+
Fetching states can be simulated by returning a stream which never returns. Wonka provides a utility for this, aptly called `never`.
93
+
Here's a fixture which stays in the _fetching_ state.
96
+
import { Provider } from 'urql';
97
+
import { never } from 'wonka';
98
+
import { MyComponent } from './MyComponent';
100
+
const fetchingState = {
101
+
executeQuery: () => never,
105
+
<Provider value={fetchingState}>
111
+
### Response (success)
113
+
Response states are simulated by providing a stream which contains a network response. For single responses, Wonka's `fromValue` function can do this for us.
115
+
**Example snapshot test of response state**
118
+
const responseState = {
119
+
executeQuery: () =>
123
+
{ id: 1, title: 'Post title', content: 'This is a post' },
124
+
{ id: 3, title: 'Final post', content: 'Final post here' },
130
+
it('matches snapshot', () => {
131
+
const wrapper = mount(
132
+
<Provider value={responseState}>
136
+
expect(wrapper).toMatchSnapshot();
140
+
### Response (error)
142
+
Error responses are similar to success responses, only the value in the stream is changed.
145
+
import { Provider, CombinedError } from 'urql';
147
+
const errorState = {
148
+
executeQuery: () =>
150
+
error: new CombinedError({
151
+
networkError: Error('something went wrong!'),
157
+
### Handling multiple hooks
159
+
Returning different values for many `useQuery` calls can be done by introducing conditionals into the mocked client functions.
162
+
const mockClient = () => {
163
+
executeQuery: ({ query }) => {
164
+
if (query === GET_USERS) {
165
+
return fromValue(usersResponse);
168
+
if (query === GET_POSTS) {
169
+
return fromValue(postsResponse);
175
+
## Simulating changes
177
+
Simulating multiple responses can be useful, particularly testing `useEffect` calls dependent on changing query responses.
179
+
For this, a _subject_ is the way to go. In short, it's a stream which you can push responses to. The `makeSubject` function from Wonka is what you'll want to use for this purpose.
181
+
Below is an example of simulating subsequent responses (such as a cache update/refetch) in a test.
184
+
import { mount } from 'enzyme';
185
+
import { act } from 'react-dom/test-utils';
186
+
import { Provider } from 'urql';
187
+
import { makeSubject } from 'wonka';
188
+
import { MyComponent } from './MyComponent';
190
+
const [stream, pushResponse] = makeSubject();
192
+
const mockedClient = {
193
+
executeQuery: () => stream,
196
+
it('shows notification on updated data', () => {
197
+
const wrapper = mount(
198
+
<Provider value={mockedClient}>
207
+
posts: [{ id: 1, title: 'Post title', content: 'This is a post' }],
211
+
expect(wrapper.find('dialog').exists()).toBe(false);
218
+
{ id: 1, title: 'Post title', content: 'This is a post' },
219
+
{ id: 1, title: 'Post title', content: 'This is a post' },
224
+
expect(wrapper.find('dialog').exists()).toBe(true);