1
- # Axios
1
+ # Network Requests
2
2
3
3
## Introduction
4
4
5
- Axios is a popular library for making HTTP requests in JavaScript. It is promise-based and has a
6
- simple API that makes it easy to use.
7
- In this guide, we will show you how to mock Axios requests and guard your test suits from unwanted
8
- and unmocked API requests.
5
+ Mocking network requests is an essential part of testing React Native applications. By mocking
6
+ network
7
+ requests, you can control the data that is returned from the server and test how your application
8
+ behaves in different scenarios, such as when the request is successful or when it fails.
9
+
10
+ In this guide, we will show you how to mock network requests and guard your test suits from unwanted
11
+ and unmocked/unhandled network requests
9
12
10
13
::: info
11
- To simulate a real-world scenario, we will use the [ Random User Generator API] ( https://randomuser.me/ ) that provides random user data.
14
+ To simulate a real-world scenario, we will use
15
+ the [ Random User Generator API] ( https://randomuser.me/ ) that provides random user data.
12
16
:::
13
17
14
18
## Phonebook Example
15
19
16
- Let's assume we have a simple phonebook application that uses Axios for fetching Data from a server.
17
- In our case, we have a list of favorite contacts that we want to display in our application.
20
+ Let's assume we have a simple phonebook application that
21
+ uses [ ` fetch ` ] ( https://reactnative.dev/docs/network#using-fetch ) for fetching Data from a server.
22
+ In our case, we have a list of contacts and favorites that we want to display in our application.
18
23
19
24
This is how the root of the application looks like:
20
25
21
26
``` tsx title=network-requests/Phonebook.tsx
22
- import React , {useEffect , useState } from ' react' ;
23
- import {User } from ' ./types' ;
27
+ import React , { useEffect , useState } from ' react' ;
28
+ import { Text } from ' react-native' ;
29
+ import { User } from ' ./types' ;
30
+ import ContactsList from ' ./components/ContactsList' ;
24
31
import FavoritesList from ' ./components/FavoritesList' ;
32
+ import getAllContacts from ' ./api/getAllContacts' ;
33
+ import getAllFavorites from ' ./api/getAllFavorites' ;
25
34
26
35
export default () => {
36
+ const [usersData, setUsersData] = useState <User []>([]);
27
37
const [favoritesData, setFavoritesData] = useState <User []>([]);
28
38
const [error, setError] = useState <string | null >(null );
29
39
30
40
useEffect (() => {
41
+ const _getAllContacts = async () => {
42
+ const _data = await getAllContacts ();
43
+ setUsersData (_data );
44
+ };
45
+ const _getAllFavorites = async () => {
46
+ const _data = await getAllFavorites ();
47
+ setFavoritesData (_data );
48
+ };
49
+
31
50
const run = async () => {
32
51
try {
33
- const _data = await getAllFavorites ();
34
- setFavoritesData (_data );
52
+ await Promise .all ([_getAllContacts (), _getAllFavorites ()]);
35
53
} catch (e ) {
36
- setError (e .message );
54
+ const message = isErrorWithMessage (e ) ? e .message : ' Something went wrong' ;
55
+ setError (message );
37
56
}
38
57
};
39
58
@@ -45,27 +64,46 @@ export default () => {
45
64
}
46
65
47
66
return (
48
- <FavoritesList users = { favoritesData } />
67
+ <>
68
+ <FavoritesList users = { favoritesData } />
69
+ <ContactsList users = { usersData } />
70
+ </>
49
71
);
50
72
};
73
+ ```
51
74
75
+ We fetch the contacts from the server using the ` getAllFavorites ` function that utilizes ` fetch ` .
76
+
77
+ ``` tsx title=network-requests/api/getAllContacts.ts
78
+ import { User } from ' ../types' ;
79
+
80
+ export default async (): Promise <User []> => {
81
+ const res = await fetch (' https://randomuser.me/api/?results=25' );
82
+ if (! res .ok ) {
83
+ throw new Error (` Error fetching contacts ` );
84
+ }
85
+ const json = await res .json ();
86
+ return json .results ;
87
+ };
52
88
```
53
89
54
- We fetch the contacts from the server using the ` getAllFavorites ` function that utilizes Axios .
90
+ We do the same for fetching the favorites, but this time limiting the results to 10 .
55
91
56
92
``` tsx title=network-requests/api/getAllFavorites.ts
57
- import axios from ' axios' ;
58
- import {User } from ' ../types' ;
93
+ import { User } from ' ../types' ;
59
94
60
95
export default async (): Promise <User []> => {
61
- const res = await axios .get (' https://randomuser.me/api/?results=10' );
62
- return res .data .results ;
96
+ const res = await fetch (' https://randomuser.me/api/?results=10' );
97
+ if (! res .ok ) {
98
+ throw new Error (` Error fetching favorites ` );
99
+ }
100
+ const json = await res .json ();
101
+ return json .results ;
63
102
};
64
-
65
103
```
66
104
67
105
Our ` FavoritesList ` component is a simple component that displays the list of favorite contacts and
68
- their avatars.
106
+ their avatars horizontally .
69
107
70
108
``` tsx title=network-requests/components/FavoritesList.tsx
71
109
import {FlatList , Image , StyleSheet , Text , View } from ' react-native' ;
@@ -107,19 +145,73 @@ export default ({users}: { users: User[] }) => {
107
145
};
108
146
109
147
// Looking for styles?
110
- // Check examples/cookbook/app/network-requests /components/FavoritesList.tsx
148
+ // Check examples/cookbook/app/advanced /components/FavoritesList.tsx
111
149
const styles =
112
150
...
113
151
```
114
152
153
+ Our ` ContactsList ` component is similar to the ` FavoritesList ` component, but it displays the list
154
+ of
155
+ all contacts vertically.
156
+
157
+ ``` tsx title=network-requests/components/ContactsList.tsx
158
+ import { FlatList , Image , StyleSheet , Text , View } from ' react-native' ;
159
+ import React , { useCallback } from ' react' ;
160
+ import type { ListRenderItem } from ' @react-native/virtualized-lists' ;
161
+ import { User } from ' ../types' ;
162
+
163
+ export default ({ users }: { users: User [] }) => {
164
+ const renderItem: ListRenderItem <User > = useCallback (
165
+ ({ item : { name , email , picture , cell }, index }) => {
166
+ const { title, first, last } = name ;
167
+ const backgroundColor = index % 2 === 0 ? ' #f9f9f9' : ' #fff' ;
168
+ return (
169
+ <View style = { [{ backgroundColor }, styles .userContainer ]} >
170
+ <Image source = { { uri: picture .thumbnail }} style = { styles .userImage } />
171
+ <View >
172
+ <Text >
173
+ Name: { title } { first } { last }
174
+ </Text >
175
+ <Text >Email: { email } </Text >
176
+ <Text >Mobile: { cell } </Text >
177
+ </View >
178
+ </View >
179
+ );
180
+ },
181
+ [],
182
+ );
183
+
184
+ if (users .length === 0 ) return <FullScreenLoader />;
185
+
186
+ return (
187
+ <View >
188
+ <FlatList <User >
189
+ data = { users }
190
+ renderItem = { renderItem }
191
+ keyExtractor = { (item , index ) => ` ${index }-${item .id .value } ` }
192
+ />
193
+ </View >
194
+ );
195
+ };
196
+
197
+ // Looking for styles or FullScreenLoader component?
198
+ // Check examples/cookbook/app/advanced/components/ContactsList.tsx
199
+ const FullScreenLoader = () => ...
200
+ const styles = ...
201
+ ```
202
+
115
203
## Start testing with a simple test
116
- In our test we will make sure we mock the ` axios.get ` function to return the data we want.
117
- In this specific case, we will return a list of 3 users.
204
+
205
+ In our test we would like to test if the ` PhoneBook ` component renders the ` FavoritesList `
206
+ and ` ContactsList ` components correctly.
207
+ We will mock the network requests and their responses to ensure that the component behaves as
208
+ expected. We will use [ MSW (Mock Service Worker)] ( https://mswjs.io/docs/getting-started ) to mock the network requests.
209
+
210
+ ``` tsx title=network-requests/Phonebook.test.tsx
118
211
119
212
:::info
120
- To prevent unexpected behavior, we ensure the following:
121
- - Prevent the mock from resolving data multiple times by using ` mockResolvedValueOnce ` .
122
- - Ensure the URL matches the base URL of the API by using a custom function ` ensureUrlMatchesBaseUrl ` .
213
+ We recommend using the Mock Service Worker (MSW ) library to declaratively mock API communication in
214
+ your tests instead of stubbing ` fetch, or relying on third-party adapters.
123
215
124
216
:::
125
217
@@ -179,20 +271,23 @@ const DATA: { results: User[] } = {
179
271
cell: ' 123-4567-890' ,
180
272
},
181
273
// For brevity, we have omitted the rest of the users, you can still find them in
182
- // examples/cookbook/app/network-requests /__tests__/PhoneBook.test.tsx
274
+ // examples/cookbook/app/advanced /__tests__/PhoneBook.test.tsx
183
275
...
184
276
],
185
277
};
186
278
187
279
```
188
280
189
281
## Testing error handling
190
- As we are dealing with network requests, we should also test how our application behaves when the API
282
+
283
+ As we are dealing with network requests, we should also test how our application behaves when the
284
+ API
191
285
request fails. We can mock the ` axios.get ` function to throw an error and test if our application is
192
286
handling the error correctly.
193
287
194
288
::: note
195
- It is good to note that Axios throws auto. an error when the response status code is not in the range of 2xx.
289
+ It is good to note that Axios throws auto. an error when the response status code is not in the
290
+ range of 2xx.
196
291
:::
197
292
198
293
``` tsx title=network-requests/Phonebook.test.tsx
@@ -242,6 +337,7 @@ export default {
242
337
` ` `
243
338
244
339
## Conclusion
340
+
245
341
Testing a component that makes network requests with Axios is straightforward . By mocking the Axios
246
342
requests , we can control the data that is returned and test how our application behaves in different
247
343
scenarios , such as when the request is successful or when it fails .
@@ -252,5 +348,8 @@ and how to guard against unwanted API requests throughout your test suite.
252
348
## Further Reading and Alternatives
253
349
254
350
Explore more powerful tools for mocking network requests in your React Native application :
255
- - [Axios Mock Adapter ](https :// github.com/ctimmerm/axios-mock-adapter): A popular library for mocking Axios calls with an extensive API, making it easy to simulate various scenarios.
256
- - [MSW (Mock Service Worker )](https :// mswjs.io/): Great for spinning up a local test server that intercepts network requests at the network level, providing end-to-end testing capabilities.
351
+
352
+ - [Axios Mock Adapter ](https :// github.com/ctimmerm/axios-mock-adapter): A popular library for
353
+ mocking Axios calls with an extensive API , making it easy to simulate various scenarios .
354
+ - [MSW (Mock Service Worker )](https :// mswjs.io/): Great for spinning up a local test server that
355
+ intercepts network requests at the network level , providing end - to - end testing capabilities .
0 commit comments