Stub a closure function using sinon for redux actions - reactjs

I have an redux action which has an async call to an API.
import { ForbiddenRequest, APIError } from "../errors"
import { fetchActionCreator } from "redux-fetch-helpers"
export const ADD_CART_ITEMS = "ADD_CART_ITEMS"
export default function addCartItems(items, authToken){
return fetchActionCreator({
url: `${API_BASE}/ajax_cart`, //eslint-disable-line no-undef
fetchOptions: {
method: "POST",
headers: new Headers({
"Authorization": `jwt ${authToken}`,
"Accept": "application/json",
"Content-Type": "application/json",
}),
body: JSON.stringify(items),
credentials: "same-origin",
},
actionType: ADD_CART_ITEMS,
responseConfig: {
200: (resp => resp),
403: (payload => new ForbiddenRequest(payload)),
other: (payload => new APIError(payload)),
}
})
}
I am trying to mock the fetchActionCreator method by using sinon stubs.
This is my spec file
import addCartItems from "../../actions/addCartItems"
import sinon from "sinon"
describe("The addCartItems action", () => {
let fetchActionCreator
it("should create an action to add an item into the cart", () => {
const addedCartItem = {
items: [{product_variant: 10, quantity: 1}]
}
const expectedAction = { type: "ADD_CART_ITEMS", meta: {sequence: "BEGIN"}}
fetchActionCreator = sinon.stub()
// fetchActionCreator()
fetchActionCreator.returns(expectedAction)
expect(addCartItems(addedCartItem, "someToken")).to.equal(expectedAction)
})
})
But somehow the function is not getting mocked. Can you suggest me the right way.

You need to stub the actual function from the library that is being called, not just create a stub that has the same name.
Add the following to your imports in your tests:
import * as reduxFetchHelpers from 'redux-fetch-helpers';
Then to the body of your test, replace your current stub code with:
const fetchActionCreator = sinon.stub(reduxFetchHelpers, 'fetchActionCreator');
fetchActionCreator.returns(expectedAction);
I have not tested this code but it looks like it should work.

Related

converting custom react function to async

I made this custom hook.
import axios from "axios";
import Cookies from "js-cookie";
import React from "react";
const useGetConferList= () => {
let token = JSON.parse(localStorage.getItem("AuthToken"));
const Idperson = JSON.parse(Cookies.get("user")).IdPerson;
const [response, setResponse] = React.useState();
const fetchConfer= (datePrensence, idInsurance, timePrensence) => {
axios({
method: "post",
url: `${process.env.REACT_APP_API_URL_API_GET_ERJASERVICE_LIST}`,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
data: JSON.stringify({
datePrensence,
idInsurance,
Idperson,
searchfield: "",
timePrensence: parseInt(timePrensence) * 60,
}),
})
.then((r) => {
setResponse(r.data.Data);
})
.catch(() => alert("NetworkError"));
};
return { fetchConfer, response };
};
export default useGetConferList;
as you can see I export the fetchConfer function. but I want to make it async. for example, calling the function and then doing something else like this:
fetchConfer(Date, Time, Id).then((r) => {
if (search !== "") {
window.sessionStorage.setItem(
"searchList",
JSON.stringify(
r.data
)
);
}
});
as you can see in non async situation, I can't use then.
You can try this
const fetchConfer = async (datePrensence, idInsurance, timePrensence) => {
try {
const response = await axios({
method: "post",
url: `${process.env.REACT_APP_API_URL_API_GET_ERJASERVICE_LIST}`,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
data: JSON.stringify({
datePrensence,
idInsurance,
Idperson,
searchfield: "",
timePrensence: parseInt(timePrensence) * 60,
}),
})
setResponse(response.data.Data);
// need to return data
return response.data.Data
} catch(error) {
alert("NetworkError")
}
};
use the function in another async function
const someAsyncFunc = async () => {
// try catch
const r = fetchConfer(Date, Time, Id)
if (search !== "") {
window.sessionStorage.setItem(
"searchList",
JSON.stringify(
r.data
)
);
}
...
or use it how you are currently using it
Hope it helps

GraphQL dynamic page API call

So I am building a dynamic lesson page with GraphQl and React.
I built a custom hook, and I do not know how to pass the ID up to the config data.
This is my hook that I made.
This is my first time working with GraphQL
import axios from 'axios'
import { useState, useEffect } from 'react'
const { REACT_APP_SPACE_ID, REACT_APP_CDA_TOKEN } = process.env
var data = JSON.stringify({
query: `{
lesson(id: ${id}){
shortTitle
shortDescription
}
}`,
variables: {},
})
var config = {
method: 'post',
url: `https://graphql.contentful.com/content/v1/spaces/${REACT_APP_SPACE_ID}`,
headers: {
Authorization: `Bearer ${REACT_APP_CDA_TOKEN}`,
'Content-Type': 'application/json',
},
data: data,
}
export default function GetLesson(id) {
let [data, setData] = useState()
useEffect(() => {
getContent()
}, [])
const getContent = async () => {
await axios(config)
.then(function (response) {
setData(response.data.data.lesson)
})
.catch(function (error) {
console.log(error)
})
}
return { data }
}

Make multiple axios calls using jest

I am working with rest js using typescript and I am trying to mock multiple API calls using jest for unit testing.
My api calls are in the following format:
await axios.request({
method: 'POST',
url: //api url,
data: {},
headers: {}
})
.then()
.catch()
I am mocking the axios as follows:
jest.mock('axios', () => {
return {
request: jest.fn().mockResolvedValue({
data: ['responseData', 'responseData1']
headers: //response header
})
}
});
The test case for api call is created as follows:
expect(axios.request).toHaveBeenCalled(); expect(axios.request).toHaveBeenCalledWith({
method: 'POST',
url: //api url,
data: {},
headers: {}
});
For multiple API calls, I am mocking it multiple times with different response data but it is taking the last mocked value as the response of all the API calls in the test cases.
for example: for multiple data mocks like:
jest.mock('axios', () => {
return {
request: jest.fn().mockResolvedValue({
data: ['responseData', 'responseData1']
headers: //response header
})
}
});
jest.mock('axios', () => {
return {
request: jest.fn().mockResolvedValue({
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
})
}
});
when I am running the test cases I am getting the response for all my apis as:
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
instead of:
data: ['responseData', 'responseData1']
headers: //response header
data: ['secondResponseData', 'secondResponseData1']
headers: //response header
I don't know how to mock the correct response with the correct api call in the test cases. Is there any way that I can mock the correct response with the API calls?
Basic usage.
import * as axios from "axios";
// Mock out all top level functions, such as get, put, delete and post:
jest.mock("axios");
// ...
test("good response", () => {
axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));
// ...
});
test("bad response", () => {
axios.get.mockImplementation(() => Promise.reject({ ... }));
// ...
});
With response code.
axios.get.mockImplementation(() => Promise.resolve({ status: 200, data: {...} }));
Based on parameters.
axios.get.mockImplementation((url) => {
if (url === 'www.example.com') {
return Promise.resolve({ data: {...} });
} else {
//...
}
});
Try something like this:
axiosPostSpy = jest.spyOn(axios, 'post').mockImplementation((url) => {
if( url === 'www.test.com?key=serverKey') {
return {
data: {
success: false,
},
};
} else {
return {
data: {
success: true,
},
};
}
});

(RN) Possible Unhandled Promise Rejection (id: 0): #Redux + axios

function requestService() {
return axios.create({
baseURL: userEndpoint,
headers: {
common: {
Accept: 'application/json',
}
}
}).then(response => {
return response.json();
}).catch(error => {
console.log('requestService', error);
});
}
module.exports = {
requestService
};
RequestService.js
import type { PromiseAction } from "./Types";
async function loadHopses(userId: number): PromiseAction {
const url = `hopses/user/${userId}`
const list = requestService().get(url);
await InteractionManager.runAfterInteractions();
return {
type: "LOADED_HOPSES",
list
};
}
module.exports = {
loadHopses
};
Action.js
this.props.dispatch(loadHopses(1));
App.js
export type PromiseAction = Promise<Action>;
Types.js
error is
Possible Unhandled Promise Rejection (id: 0):
TypeError: _axios2.default.create(...).then is not a function
TypeError: _axios2.default.create(...).then is not a function
I based on f8 facebook app and be converting parse to rest
What's wrong in this code?
please help..
axios.create returns an instance like this:
var instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
These are the only valid methods for that.
axios#request(config)
axios#get(url[, config])
axios#delete(url[, config])
axios#head(url[, config])
axios#options(url[, config])
axios#post(url[, data[, config]])
axios#put(url[, data[, config]])
axios#patch(url[, data[, config]])
You can instead use it like this:
return axios.({
method: 'post',
baseURL: userEndpoint,
headers: {
common: {
Accept: 'application/json',
}
}
}).then(...).catch(...);
Using axios() instead of axios.create()

How to make a rest post call from ReactJS code?

I am new to ReactJS and UI and I wanted to know how to make a simple REST based POST call from ReactJS code.
If there is any example present it would be really helpful.
Straight from the React Native docs:
fetch('https://mywebsite.example/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
(This is posting JSON, but you could also do, for example, multipart-form.)
Also see docs for ReactJS AJAX FAQs if not using React Native.
React doesn't really have an opinion about how you make REST calls. Basically you can choose whatever kind of AJAX library you like for this task.
The easiest way with plain old JavaScript is probably something like this:
var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.send(data);
In modern browsers you can also use fetch.
If you have more components that make REST calls it might make sense to put this kind of logic in a class that can be used across the components. E.g. RESTClient.post(…)
Another recently popular packages is : axios
Install : npm install axios --save
Simple Promise based requests
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
you can install superagent
npm install superagent --save
then for make post call to server
import request from "../../node_modules/superagent/superagent";
request
.post('http://localhost/userLogin')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ username: "username", password: "password" })
.end(function(err, res){
console.log(res.text);
});
As of 2018 and beyond, you have a more modern option which is to incorporate async/await in your ReactJS application. A promise-based HTTP client library such as axios can be used. The sample code is given below:
import axios from 'axios';
...
class Login extends Component {
constructor(props, context) {
super(props, context);
this.onLogin = this.onLogin.bind(this);
...
}
async onLogin() {
const { email, password } = this.state;
try {
const response = await axios.post('/login', { email, password });
console.log(response);
} catch (err) {
...
}
}
...
}
I think this way also a normal way. But sorry, I can't describe in English ((
submitHandler = e => {
e.preventDefault()
console.log(this.state)
fetch('http://localhost:5000/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
}
https://googlechrome.github.io/samples/fetch-api/fetch-post.html
fetch('url/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
Here is a the list of ajax libraries comparison based on the features and support.
I prefer to use fetch for only client side development or isomorphic-fetch for using in both client side and server side development.
For more information on isomorphic-fetch vs fetch
Here is a util function modified (another post on stack) for get and post both. Make Util.js file.
let cachedData = null;
let cachedPostData = null;
const postServiceData = (url, params) => {
console.log('cache status' + cachedPostData );
if (cachedPostData === null) {
console.log('post-data: requesting data');
return fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then(response => {
cachedPostData = response.json();
return cachedPostData;
});
} else {
console.log('post-data: returning cachedPostData data');
return Promise.resolve(cachedPostData);
}
}
const getServiceData = (url) => {
console.log('cache status' + cachedData );
if (cachedData === null) {
console.log('get-data: requesting data');
return fetch(url, {})
.then(response => {
cachedData = response.json();
return cachedData;
});
} else {
console.log('get-data: returning cached data');
return Promise.resolve(cachedData);
}
};
export { getServiceData, postServiceData };
Usage like below in another component
import { getServiceData, postServiceData } from './../Utils/Util';
constructor(props) {
super(props)
this.state = {
datastore : []
}
}
componentDidMount = () => {
let posturl = 'yoururl';
let getdataString = { name: "xys", date:"today"};
postServiceData(posturl, getdataString)
.then(items => {
this.setState({ datastore: items })
console.log(items);
});
}
Here is the simple method to define and call post APIs in reactjs. Install axios using command npm install axios and call post req method wherever you want, it will return array that contains 100 elements.
// Define post_req() Method in authAction.js
import axios from 'axios';
const post_req = (data) => {
return new Promise((resolve, reject) => {
const url = 'https://jsonplaceholder.typicode.com/posts'
const header = {
"Access-Control-Allow-Origin": "*",
"Content-Type: application/json"
}
axios({
method: 'post',
url: url,
data: data,
headers: header
});
.then((res)=>{resolve(res);})
.catch((err)=>{reject(err);})
})
}
// Calling post_req() Method in react component
import React, { Component } from 'react';
import { post_req } from 'path of file authAction.js'
class MyReactComponent extends Component {
constructor(props) {
super(props);
this.state = {
myList:[]
};
}
componentDidMount() {
let data = {
.......
}
this.props.post_req(data)
.then((resp)=>{this.setState({myList:resp.data})})
.catch((err)=>{console.log('here is my err',err)})
}
render() {
return (
<div>
....
</div)
}
}
export default MyReactComponent;
import React ,{useState}from 'react';
import Axios from 'axios';
export default function Formlp()
{
const url ="";
const [state, setstate] = useState({
name:"",
iduser:""
})
function handel(e){
const newdata={...state}
newdata[e.target.id]=e.target.value
setstate(newdata);
}
function submit(e)
{
e.preventDefault();
// Axios.post(url,{name:state.name,iduser:state.iduser}).then( res=>{console.log(res)});
console.log(state)
}
return (
<div onSubmit={ (e)=> submit(e)}>
<input onChange={ (e)=>handel(e) } id="name" value={state.name} placeholder="name" type="text" >
<input onChange={ (e)=>handel(e) } id="iduser" value={state.iduser} placeholder="iduser" type="text" >
<button>submit</button>
</form>
</div>
);
}
Here is a quick example for v18+ while handling form data and creating a POST request with the data.
async function handleOrderSubmit(event){
event.preventDefault()
try{
const formData= {name: event.target.name.value, email: event.target.email.value, message: event.target.name.message}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
};
const response = await fetch('https://www.example.com/form', requestOptions);
const data = await response.json();
navigate("/form-response", { state: {data: data, status: true} })
}
catch(error){
navigate("/form-response", { state: {status: false} })
}
}
Note 1: Using status on '/form-response' page, you can customise what to show user. For true, you can show a different section and for false a different one.
Note 2: If the status is successful, you can access data on the next page also and customise it according to user information.
Note 3: event.preventDefault() is important to avoid page reloading.
Here is an example: https://jsfiddle.net/69z2wepo/9888/
$.ajax({
type: 'POST',
url: '/some/url',
data: data
})
.done(function(result) {
this.clearForm();
this.setState({result:result});
}.bind(this)
.fail(function(jqXhr) {
console.log('failed to register');
});
It used jquery.ajax method but you can easily replace it with AJAX based libs like axios, superagent or fetch.

Resources