I'm currently trying to write Jest tests for my React Native application, testing my fetch commands as such:
const token = await AsyncStorage.getItem("id");
let response = await fetch('http://192.168.0.12:3000/auth/login', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
}
});
let res = await response.json();
...rest of code
But I can't seem to find any mocking solutions for Async Storage one version before (ie. WITHIN React Native, NOT the current #react-native-community/async-storage. Currently, I've tried fully mocking the module like so, and checking whether the getItem() method is ever called:
test('tests Login', () => {
jest.mock('react-native', () => {
AsyncStorage: {
getItem: jest.fn(() => {
return new Promise((resolve, reject)=>{
resolve("cool");
});
})
}
});
expect(AsyncStorage.getItem).toBeCalled();
});
But this currently returns the following error:
expect(jest.fn()).toBeCalled()
Expected number of calls: >= 1
Received number of calls: 0
And when I change it to this (which I don't think is the right way):
expect(AsyncStorage.getItem()).toBeCalled()
it returns a Promise that doesn't resolve:
expect(received).toBeCalled()
Received has type: object
Received has value: {"_40": 0, "_55":undefined, "_65": 1, "_72": null}
My question is, how can I mock the older version of AsyncStorage to check whether the function has been called, or have the mock return a constant value so the test can execute the rest of the method? Any help with this would be greatly appreciated. I have tried the various solutions suggested on SO, but all have returned the same errors. The current software I am using is:
React Native (Expo SDK 37.0.0),
Jest,
React-test-renderer
Related
I am modifying a state variable (setTokens(tokens - 1)) in React native and then using the modified variable in an axios PUT request (library_tokens: tokens).
The problem is, the put request is successful, but it puts the old value of the variable instead of the modified one in the database after the PUT request.
The following is the code:
const [tokens,setTokens] = useState(0)
const lendBook = book => {
// Add book to the IssueReturn collection in the database
issuesApi
.post('/bookissue', {
booksIssued: book._id,
image: book.image,
user: context.stateUser.user.userId,
})
.then(response => {
if (response.status === 200) {
// Decrement user's library token
setTokens(tokens - 1);
// Modify the user's library tokens
userProfileApi
.put(
`/${context.stateUser.user.userId}`,
{
library_tokens: tokens,
},
{
headers: {Authorization: `Bearer ${jwtToken}`},
},
)
.then(response => {
console.log('tokens', tokens);
});
}
})
.catch(err => {
console.log(err);
});
};
You can use useEffect like this.
useEffect(() => {
console.log(tokens) // do something after state has updated
}, [tokens])
After state updation the useEffect will be called, so you can call userProfileApi inside useEffect.
setTokens it not a synchron function. code executed afterwards will not have the updated state. either use a local variable to store the result of token - 1 or make use of the useEffect hook.
I am using expo and used hooks as I need the response to be saved in an array to access it later and I am not using classes so I found the hooks method, first it was giving me an infinite loop so when I searched I found that if I added an empty array as the second parameter in the useEffect() method this would make it run only 1 time but this is not happening as the code runs 3 times now, Is there any solution? If not is there another way to save the response in an array without classes rather than using hooks ?
The code below is what makes the problem.
Thank you in advance.
const [wallets, setWallets] = useState({});
async function fetchData() {
const res = await fetch('https://api.streetcred.id/custodian/v1/api/wallets', {
method: 'GET',
headers: {
Authorization: 'Bearer ',
XStreetcredSubscriptionKey: '',
Accept: 'application/json',
'Content-Type': 'application/json',
}
});
res
.json()
.then(res => setWallets(res))
.catch(err => setErrors(err));
}
useEffect(() => {
fetchData();
}, []);
Write the function fetchData inside the useeffect method.
Need some help in solving a reload problem.
I fetch data via service:
import axios from 'axios'
const apiClient = axios.create({
baseURL: 'www.domain/api/v1',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
and
export default {
getCompanies() {
return apiClient.get('/companies')
},
in store:
export const actions = {
fetchCompanies({ commit }) {
return CompanyService.getCompanies().then(response => {
commit('SET_COMPANIES', response.data)
})
},
in pages/companies:
async fetch({ store, error }) {
try {
await store.dispatch('company/fetchCompanies')
} catch (e) {
error({
statusCode: 503,
message: 'Unable to fetch Companies at this time'
})
}
},
works fine, but no data on page reload.
Some help would be great.
If you are using it on a pagination component the reason it is not reloading is that fetch it will be called server-side once and in the client-side just when navigating to further routes.
The fetch method is not called on query string changes by default. If you want to change this behavior, for example when building a pagination component, you can setup parameters that should be listened to through the watchQuery property of your page component. Learn more on the API watchQuery page.
Looks Nuxt documentation: https://nuxtjs.org/api/pages-fetch/
You can use watchQuery to fix this.
https://nuxtjs.org/api/pages-watchquery
I am trying to access a prestashop API with vuejs2
<script>
import axios from 'axios'
export default {
data () {
return {
get: [],
errors: []
}
},
created () {
axios({
method: 'get',
url: 'https://myprestashopsite.com/api/categories/?ws_key=J***************Z&filter[id_parent]=5&output_format=JSON'
}).then(response => {
this.get = response.data
})
.catch(e => {
this.errors.push(e)
})
}
}
In the web developer console of mozilla I see that my request return a 200 with the data in the response. But I get "Error: Network Error app.js%20line%201266%20%3E%20eval:15:15" catch as an error.
I tried with another API and it worked, so I guess it comes from the prestashop api. (prestashop version 1.7.3.0)
Is there a way to fix this ?
The problem seems to come from axios. I had to add a rule to the server.
I found the solution to this on this thread :
https://github.com/axios/axios/issues/853
There are other solutions I didn't try in this thread if mine doesn't work.
how to add the rule : https://enable-cors.org/server.html
I am trying to use react-native-fetch-polyfill becouse of timeout feature for fetch requests but can't implement onProgress event:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(function(data) {
console.log(data);
})
.catch(function(error) {
console.log('Fetch Error :-S', error);
});
I don't know where to add:
onUploadProgress: function (progressEvent)
That library does not support progress handler. If you need this feature and want to use that library, the simplest thing for you to do would be to fork the library and add the feature yourself:
1) Fork the repository on GitHub.
2) Edit js file in your repository. For example, add callback you need as a third argument to the function:
export default function fetchPolyfill (input, init) {
// becomes
export default function fetchPolyfill (input, init, onUploadProgress) {
// add this somewhere inside
if (onUploadProgress)
xhr.upload.onprogress = onUploadProgress
3) Edit your package json to include
"react-native-fetch-polyfill": "git://github.com/youraccount/react-native-fetch-polyfill"
and run npm install.
1a) Of course you may actually just copy the script and edit it locally on your computer without dealing with GitHub, if you are fine with it not being in node modules. Or download the whole folder and use it as a package.
You can use axios
that already have thus function (onUploadProgress)
Under the hood, fetch uses the React-Native XMLHttpRequest object; this is also true for react-native-fetch-polyfill. This is not the regular xhr object which is used in browsers since the actual requests are sent from the native side.
As far as I know, both RN fetch and react-native-fetch-polyfill do not support upload progress, but you can use XMLHttpRequest directly to do that:
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (progressEvent) => {
//handle progress here, you can use progressEvent.loaded, progressEvent.total to calculate the progress
};
const body = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
});
xhr.setRequestHeader("Content-type", "application/json; charset=UTF-8");
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts');
xhr.send(body);
you can also add the timeout handling yourself:
xhr.timeout = 30 * 1000;
xhr.ontimeout = () => {
//handle timeout here
}