the error
this is the error I'm getting when I run npx react-native run-android
I was writing the code and everything was fine till I decided to take a break then I came back and wanted to continue but this error came up so I'm not even sure where the error is from, so any help would be appreciated
I tried these fixes
react-native link (i usually do this after install a dependency or package then restart)
./gradlew clean
npm install
I'm using an older version following this video youtube
These are the only places error is used in my code
I'm trying to fetch market data from coingecko
marketReducer.js
import { ActionSheetIOS } from 'react-native';
import * as marketActions from './marketActions';
const initialState = {
myHoldings: [],
coins: [],
error: null,
loading: false
}
const marketReducer = (state = initialState, action) => {
switch (action.type) {
case marketActions.GET_HOLDINGS_BEGIN:
return {
...state,
loading: true
}
case marketActions.GET_HOLDINGS_SUCCESS:
return {
...state,
myHoldings: action.payload.myHoldings
}
case marketActions.GET_HOLDINGS_FAILURE:
return {
...state,
error: action.payload.error
}
case marketActions.GET_COIN_MARKET_BEGIN:
return {
...state,
loading: true
}
case marketActions.GET_COIN_MARKET_SUCCESS:
return {
...state,
coins: action.payload.coins
}
case marketActions.GET_COIN_MARKET_FAILURE:
return {
...state,
error: action.payload.error
}
default:
return state
}
}
marketActions.js
import axios from "axios";
export const GET_HOLDINGS_BEGIN = "GET_HOLDINGS_BEGIN"
export const GET_HOLDINGS_SUCCESS = "GET_HOLDINGS_SUCCESS"
export const GET_HOLDINGS_FAILURE = "GET_HOLDINGS_FAILURE"
export const GET_COIN_MARKET_BEGIN = "GET_COIN_MARKET_BEGIN"
export const GET_COIN_MARKET_SUCCESS = "GET_COIN_MARKET_SUCCESS"
export const GET_COIN_MARKET_FAILURE = "GET_COIN_MARKET_FAILURE"
//Holding / My Holdings
export const getHoldingsBegin = () => ({
type: GET_HOLDINGS_BEGIN
})
export const getHoldingsSuccess = (myHoldings) => ({
type: GET_HOLDINGS_SUCCESS,
payload: { myHoldings }
});
export const getHoldingsFailure = (error) = ({
type: GET_HOLDINGS_FAILURE,
payload: { error }
})
export function getHoldings(holdings = [], currency = "usd", orderBy = "market_cap_desc", sparkline = true, priceChangePerc = "7d", perPage = 10, page = 1) {
return dispatch => {
dispatch(getHoldingsBegin())
let ids = holdings.map((item) => { return item.id }).join(",");
let apiUrl = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=${currency}&order=${orderBy}&per_page=${perPage}&page=${page}&sparkline=${sparkline}&price_change_percentage=${priceChangePerc}&ids=${ids}`
return axios({
url: apiUrl,
method: 'GET',
header: {
Accept: "application/json"
}
}).then((response) => {
console.log("GetHoldings")
console.log(response)
if (response.state == 200) {
//Massage data
let myHoldings = response.data.map((item) => {
//Retrieve our current holdings -> current quantity
let coin = holdings.find(a => a.id == item.id)
//Price from 7 days ago
let price7d = item.current_price / (1 + item.price_change_percentage_7d_in_currency * 0.01)
return {
id: item.id,
symbol: item.symbol,
name: item.name,
img: item.image,
current_price: item.current_price,
price_change_percentage_7d_in_currency: item.price_change_percentage_7d_in_currency,
holding_value_change_7d: (item.current_price - price7d) * coin.qty,
sparkline_in_7d: {
value: item.sparkline_in_7d.price.map((price) => {
return price * coin.qty
})
}
}
})
dispatch(getHoldingsSuccess(myHoldings))
} else {
dispatch(getHoldingsFailure(response.data));
}
}).catch((error) => { dispatch(getHoldingsFailure(error)); });
}
}
// Coin Market
export const getCoinMarketBegin = () => ({
type: GET_COIN_MARKET_BEGIN
})
export const getCoinMarketSuccess = (coins) => ({
type: GET_COIN_MARKET_SUCCESS,
payload: { coins }
})
export const getCoinMarketFailure = (error) => ({
type: GET_COIN_MARKET_FAILURE,
payload: { error }
})
export function getCoinMarket(currency = "usd", orderBy = "market_cap_desc", sparkline = true, priceChangePerc = "7d", perPage = 10, page = 1) {
return dispatch => {
dispatch(getCoinMarketBegin())
let apiUrl = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=${currency}&order=${orderBy}&per_page=${perPage}&page=${page}&sparkline=${sparkline}&price_change_percentage=${priceChangePerc}
`
return axios({
url: apiUrl,
method: 'GET',
header: {
Accept: 'application/json'
}
}).then((response) => {
if (response.state == 200) {
dispatch(getCoinMarketSuccess(response.data))
}else{
dispatch(getCoinMarketFailure(response.data))
}
}).catch((error) => {
dispatch(getCoinMarketFailure(error))
})
}
}
Related
I need help with the async nature of Async storage and axios api. Here's the functionality that I am trying to achieve ->
send request to two separate api to get some data.
display that data on the screen with some additional text
api request are authenticated so a token is passed as Authentication Header
I have attached the current implementation, I am having the a number of errors in this
Errors:
Login_token not set in state after fetching from Async Storage.
Data not set in state after api call
both resulting in either failed api calls or undefined state errors on render
This is my code.
import React, { FunctionComponent, useEffect, useCallback, useState} from 'react';
import { StyleSheet, View} from 'react-native';
// chat
import { GiftedChat } from 'react-native-gifted-chat';
// navigation
import { RootStackParamList } from '../../navigators/RootStack';
import { StackScreenProps } from '#react-navigation/stack';
export type Props = StackScreenProps<RootStackParamList, "Chat">;
// api
import { Convo_details, Send_Msg, List_Msg, Expert_Public_Profile } from '../../api/UserApi';
import Spinner from 'react-native-loading-spinner-overlay';
import AsyncStorage from '#react-native-async-storage/async-storage';
import uuid from 'react-native-uuid';
const Chat: FunctionComponent<Props> = ({ navigation, route, ...props }) => {
// console.log(props.route.params);
const [login_token, setlogin_token] = useState('')
const [conversation_id, setconversation_id] = useState('')
const [conversation_details, setconversation_details] = useState({})
const [currentuser, setcurrentuser] = useState({})
const [loading, setLoading] = useState(false);
const [expertuid, setexpertuid] = useState('')
const [ExpertProfile, setExpertProfile] = useState({})
const [messages, setMessages] = useState([]);
useEffect(() => {
getlogintoken()
console.log("####################################","getlogintoken");
}, [])
/* conversationid */
useEffect(() => {
if (route.params != null) {
setconversation_id(route.params[0])
}
console.log("####################################","conversation id");
}, [])
/* expert uid */
useEffect(() => {
if (route.params != null) {
setexpertuid(route.params[1])
}
console.log("####################################","expert uid");
}, [])
/* expert public profile */
useEffect(() => {
getexpertpublicprofile()
getConvo_details()
console.log("####################################","convo_details");
}, [])
useEffect(() => {
// get current user
AsyncStorage.getItem("currentuser").then(res => {
if (res != null) setcurrentuser(res)
else alert("Current user not found")
})
console.log("####################################","current user");
}, [])
// set welcome msg
useEffect(() => {
if (Object.keys(conversation_details).length != 0 && Object.keys(ExpertProfile).length != 0)
setwelcomemsg()
}, [])
const onSend = useCallback(async (messages = []) => {
// console.log(messages[0].text);
setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
const data = {
conversation_id: "f98d6851-a713-4f58-9118-77a779ff175f",//conversation_id,
message_type: "TEXT",
body: messages[0].text
}
const res: any = await Send_Msg(data, login_token)
.catch(error => {
alert(`Send_Msg -> ${error}`)
console.log(error);
return
})
if (res.status == 200) {
console.log(res.data);
} else console.log(res);
}, [])
const getexpertpublicprofile = async () => {
setLoading(true)
const res: any = await Expert_Public_Profile(expertuid, login_token)
.catch(error => {
setLoading(false)
console.log("Expert public profile ->");
alert(`Expert public profile ->${error.message}`)
console.log(error);
return
})
setLoading(false)
if (res.status === 200) setExpertProfile(res.data)
else {
alert(`get expert public profile${res.data.message}`)
console.log("getexpertpublicprofile -->");
console.log(res.data);
}
}
const getlogintoken = () => {
AsyncStorage.getItem("login_token").then(res => {
if (res != null) {
setLoading(false)
setlogin_token(res)
}
else alert("No login token found")
})
}
const getConvo_details = async () => {
setLoading(true)
const res: any = await Convo_details(conversation_id, login_token)
.catch(error => {
setLoading(false)
alert(`Convo_details-->${error.message}`)
console.log("Convo_details -->");
console.log(error);
return
})
setLoading(false)
if (res.status === 200) setconversation_details(res.data)
else {
alert(`get convo details-> ${res.data.message}`)
console.log("getConvo_details -->");
console.log(res.data);
}
}
const setwelcomemsg = () => {
try {
let user = JSON.parse(currentuser)
let messages = [
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `About Me - ${ExpertProfile.bio}`,
user: {
_id: conversation_details.recipient.user_uid,
}
},
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `My name is ${conversation_details.recipient.name}`,
user: {
_id: conversation_details.recipient.user_uid,
}
},
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `Hi ${user.full_name}`,
user: {
_id: conversation_details.recipient.user_uid,
}
}]
setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
} catch (error) {
console.log("try -> set welcome msg");
console.log(error);
return
}
}
return (
<View style={styles.maincontainer}>
<Spinner
visible={loading}
textContent={'Loading...'}
textStyle={{ color: '#FFF' }}
/>
<GiftedChat
messages={messages}
onSend={messages => onSend(messages)}
user={{
_id: currentuser.user_uid,
}}
isTyping={false}
scrollToBottom={true}
showAvatarForEveryMessage={true}
renderAvatar={() => null}
/>
</View>
);
}
export default Chat;
const styles = StyleSheet.create({
maincontainer: {
flex: 1,
},
});
When axios returns, it usually give the response as res.data, so in your case, try either res.data or res.data.yourToken (I'm not sure how it's your object).
Gurav,
As far as your code above, The api call's will trigger even before you get currentuser or loginToken. You have to handle the api call after getting the currentuser and loginToken. This can be gracefully handled with async, await.
example code:
useEffect(() => {
getData()
}, [])
useEffect(() => {
if(login_token && currentuser) {
//The api call goes here after you get the logintoken andcurrentuser.
// The above condition is just an example but will vary based on your requirements
}
}, [login_token, currentuser])
const getData = async () => {
await getlogintoken()
await getcurrentuser()
}
const getlogintoken = async () => {
await AsyncStorage.getItem("login_token").then(res => {
if (res != null) {
setLoading(false)
setlogin_token(res)
}
else alert("No login token found")
})
}
const getcurrentuser = async () => {
await AsyncStorage.getItem("currentuser").then(res => {
if (res != null) setcurrentuser(res)
else alert("Current user not found")
})
}
I have a simple question. I am implementing the useSelector Hook React Native together with ReduxToolKit.
But now the problem when the useSelector have data or not empty and everytime I change my screen the useSelector data remain the same data.
I want when change screen my useSelector data to be empty array again.
How do I solve this problem ?
Thank You
EDIT :
ApiChartingSlice.js
export const ApiChartingDataThunk = createAsyncThunk(
'ApiChartingData',
async (data) => {
try {
const {chart, ticker} = data;
const response = await ApiChartingData(chart, ticker);
return response;
} catch (error) {
return console.log({ error: error.message });
}
}
)
// status: 'idle' | 'loading' | 'succeeded' | 'failed',
export const ApiChartingDataSlice = createSlice({
name: 'ApiChartingData',
initialState: {
apiData: [],
status: 'idle',
error: null
},
reducers: {},
extraReducers: {
[ApiChartingDataThunk.pending.type]: (state, action) => {
state.playerList = {
status: state.status = 'loading',
apiData: [],
error: {},
};
},
[ApiChartingDataThunk.fulfilled.type]: (state, action) => {
state.playerList = {
status: state.status = 'idle',
apiData: state.apiData = action.payload,
error: {},
};
},
[ApiChartingDataThunk.rejected.type]: (state, action) => {
state.playerList = {
status: state.status = 'failed',
apiData: [],
error: action.payload,
};
},
}
});
ChartUserCard.js
const tickerData = useSelector(state => state.ApiTicker.apiData);
const checkTicker = useCallback(() => {
dispatch(ApiTickerThunk(inputValue))
.unwrap()
.then((originalPromiseResult) => {
// console.log(originalPromiseResult);
})
.catch((rejectedValueOrSerializedError) => {
console.log(rejectedValueOrSerializedError);
});
setStart(true);
}, [dispatch, inputValue, tickerData]);
in Here : const tickerData = useSelector(state => state.ApiTicker.apiData);
I want to reset tickerData.
Thank To #this.arjun.
const dataThunk = {chart: "", ticker: ""};
const tickerThunk = "";
const resetDataThunk = useCallback(() => {
dispatch(ApiTickerThunk(tickerThunk));
dispatch(ApiChartingDataThunk(dataThunk));
}, [dispatch]);
Just use dispatch empty data.
I try to test this action:
const getGameList = function(context) {
if(context.state.user.id){
let request_body = {
user_id : context.state.user.id
}
axios.post(`api/game_list_of_user`,request_body).then(response => {
context.commit('UpdateGameList',response.data);
}).catch(error => console.log(error));
}
};
My action is to get the list of game for a specific user.
This action has:
as input my user id .
as output my game of list.
My test:
import actions from '#/store/actions'
import state from '#/store/state'
import store from '#/store'
import axios from 'axios'
jest.mock('axios');
describe('getGameList', () => {
test('Success: should return the game list of the user and update gameList in the store', () => {
const state = { user: {id: 1} };
const mockFunction = jest.fn();
const response = {
data: [
{ id:1, name:"game_name1" },
{ id:2, name:"game_name2" }
]
};
axios.post.mockResolvedValue(response);
actions.getGameList({ mockFunction },{ state });
//expect(mockFunction).toHaveBeenCalledTimes(1);
//expect(mockFunction).toHaveBeenCalledWith('UpdateGameList',response.data);
});
test('Error: an error occurred', () => {
const errorMessage = 'Error';
axios.get.mockImplementationOnce(() =>
Promise.reject(new Error(errorMessage))
);
});
});
I declare my state (with my user id).
I declare my expected response
from my request (the game list = response.data).
I use jest.fn() to mock the function. (Should I do that ?)
I got this error:
I want to check:
My request has been called
The response of my request matches with my expected response
My mutation is then called
How can I solve that error?
Edit1: my test
jest.mock('axios');
describe('getGameList', () => {
test('Success: should return the game list of the user and update gameList in the store', () => {
const context = {
state : {
user: {
id: 1
}
}
};
const mockFunction = jest.fn();
const response = {
data: [
{ id:1, name:"game_name1" },
{ id:2, name:"game_name2" }
]
};
axios.post.mockResolvedValue(response);
actions.getGameList({ mockFunction, context });
expect({ mockFunction, context }).toHaveBeenCalledTimes(1);
expect(mockFunction).toHaveBeenCalledWith('UpdateGameList',response.data);
});
test('Error: an error occurred', () => {
const errorMessage = 'Error';
axios.get.mockImplementationOnce(() =>
Promise.reject(new Error(errorMessage))
);
});
});
this is my solution:
import actions from '#/store/actions'
import mutations from '#/store/mutations'
import state from '#/store/state'
import store from '#/store'
import axios from 'axios'
let url = ''
let body = {}
jest.mock("axios", () => ({
post: jest.fn((_url, _body) => {
return new Promise((resolve) => {
url = _url
body = _body
resolve(true)
})
})
}))
//https://medium.com/techfides/a-beginner-friendly-guide-to-unit-testing-the-vue-js-application-28fc049d0c78
//https://www.robinwieruch.de/axios-jest
//https://lmiller1990.github.io/vue-testing-handbook/vuex-actions.html#testing-actions
describe('getGameList', () => {
test('Success: should return the game list of the user and update gameList in the store', async () => {
const context= {
state: {
user: {
id:1
}
},
commit: jest.fn()
}
const response = {
data: [
{ id:1, name:"game_name1" },
{ id:2, name:"game_name2" }
]
};
axios.post.mockResolvedValue(response) //OR axios.post.mockImplementationOnce(() => Promise.resolve(response));
await actions.getGameList(context)
expect(axios.post).toHaveBeenCalledWith("api/game_list_of_user",{"user_id":1});
expect(axios.post).toHaveBeenCalledTimes(1)
expect(context.commit).toHaveBeenCalledWith("UpdateGameList", response.data)
});
test('Error: an error occurred', () => {
const errorMessage = 'Error';
axios.post.mockImplementationOnce(() =>
Promise.reject(new Error(errorMessage))
);
});
});
in a react-native project,I keep hitting in this error:
state is undefined, evaluating store.getstate()
//store.js
const composeEnhancers =
typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
const enhancer = composeEnhancers(applyMiddleware(thunk));
const Store = createStore(
combineReducers(
{
form: formReducer,
appointmentsReducer
},
enhancer
)
);
console.log(Store.getState());
export default Store;`
//reducer.js
import {
FETCH_APPOINTMENTS_BEGIN,
FETCH_APPOINTMENTS_SUCCESS,
FETCH_APPOINTMENTS_FAILURE
} from '../actions/appointmentsAction';
const initialState = {
data: [],
loading: false,
error: null
};
export default function appointmentsReducer(state = initialState, action) {
switch(action.type) {
case FETCH_APPOINTMENTS_BEGIN:
return {
...state,
loading: true,
error: null
};
case FETCH_APPOINTMENTS_SUCCESS:
return {
...state,
loading: false,
data: action.payload.appointments
};
case FETCH_APPOINTMENTS_FAILURE:
return {
...state,
loading: false,
error: action.payload.error,
data: []
};
default:
return state;
}
}
//actions.js
import { listUrl } from "../cst";
export const FETCH_APPOINTMENTS_BEGIN = "FETCH_APPOINTMENTS_BEGIN";
export const FETCH_APPOINTMENTS_SUCCESS = "FETCH_APPOINTMENTS_SUCCESS";
export const FETCH_APPOINTMENTS_FAILURE = "FETCH_PRODUCTS_FAILURE";
export const fetchAppointmentsBegin = () => ({
type: FETCH_APPOINTMENTS_BEGIN
});
export const fetchAppointmentsSuccess = appointments => ({
type: FETCH_APPOINTMENTS_SUCCESS,
payload: { appointments }
});
export const fetchAppointmentsFailure = error => ({
type: FETCH_APPOINTMENTS_FAILURE,
payload: { error }
});
export function fetchAppointments() {
return dispatch => {
dispatch(fetchAppointmentsBegin());
return fetch(listUrl)
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(fetchApointmentsSuccess(json.appointment));
return json.appointment;
})
.catch(error => dispatch(fetchAppointmentsFailure(error)));
};
}
// Handle HTTP errors since fetch won't.
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
// app.js
export default function App() {
return (
<Provider store={Store}>
<Navigation />
</Provider>
);
}
//list rendrer component :
const mapStateToProps = state => ({
data: state.appointments.data,
loading: state.loading,
error: state.error
});
the console.log of store.getstate() gives :
Object {
"appointmentsReducer": Object {
"data": Array [],
"error": null,
"loading": false,
},
"form": Object {},
I'm not sure where the problem is.
Is it due to the asynchronous call not being handled properly?
If I use saga to handle the fetch, will it resolve the problem?
Any help would be appreciated .
I'm new to Jest testing and moxios. Just trying to write my first async action test. Test dies with this error:
Expected value to equal:
[{"payload": {"checked": true, "followingInfoId": "1"}, "type": "HANDLE_FAVORITE_SUCCESS"}]
Received:
[{"payload": [TypeError: Cannot read property 'getItem' of undefined], "type": "ERROR"}]
Does anyone can tell me where is the problem. I suppose that the moxios response doesn't go to "then"?
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import moxios from 'moxios';
import * as actions from './index';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
const store = mockStore();
describe('followings actions', () => {
beforeEach(() => {
moxios.install();
store.clearActions();
});
afterEach(() => {
moxios.uninstall();
});
it('dispatches the HANDLE_FAVORITE_SUCCESS action', () => {
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
payload: {
followingInfoId: '1',
checked: true
}
});
});
const expectedActions = [
{
'type': 'HANDLE_FAVORITE_SUCCESS',
payload: {
followingInfoId: '1',
checked: true
}
}
];
return store.dispatch(actions.handleFavorite()).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
});
Here is the action creator:
export const handleFavorite = data => {
return dispatch => {
return followApi.handleFavorite(data).then(payload => {
dispatch({ type: 'HANDLE_FAVORITE_SUCCESS', payload });
}, err => {
dispatch({ type: 'ERROR', payload: err })
});
}
};
Here is the followApi.handleFavorite:
handleFavorite: (data) => {
return new Promise ((resolve, reject) => {
httpServise.patch(`${host}:${port}/followings/handle-favorite`, data).then(
res => {
if (res.data.payload) {
resolve(res.data.payload);
} else reject({status: 401});
}, err => reject(err)
);
});
},
And and a part of the http-servise if needed:
patch: (url, params) => {
return new Promise((resolve, reject) => {
axios(url, {
method: 'PATCH',
headers: getHeaders(),
data: params
}).then(res => {
resolve(res);
}, err => {
reject(err);
});
});
}
If you want to test action creators, you should mock followApi.handleFavorite method rather than axios.
Here is the solution for testing action creators only use jestjs and typescript, You can mock the module manually by yourself.
Folder structure:
.
├── actionCreators.spec.ts
├── actionCreators.ts
├── followApi.ts
└── httpServise.ts
actionCreators.ts:
import followApi from './followApi';
export const handleFavorite = data => {
return dispatch => {
return followApi.handleFavorite(data).then(
payload => {
dispatch({ type: 'HANDLE_FAVORITE_SUCCESS', payload });
},
err => {
dispatch({ type: 'ERROR', payload: err });
}
);
};
};
followApi.ts:
import { httpServise } from './httpServise';
const host = 'http://github.com/mrdulin';
const port = 3000;
const followApi = {
handleFavorite: data => {
return new Promise((resolve, reject) => {
httpServise.patch(`${host}:${port}/followings/handle-favorite`, data).then(
(res: any) => {
if (res.data.payload) {
resolve(res.data.payload);
} else {
reject({ status: 401 });
}
},
err => reject(err)
);
});
}
};
export default followApi;
httpService.ts:
import axios from 'axios';
function getHeaders() {
return {};
}
export const httpServise = {
patch: (url, params) => {
return new Promise((resolve, reject) => {
axios(url, {
method: 'PATCH',
headers: getHeaders(),
data: params
}).then(
res => {
resolve(res);
},
err => {
reject(err);
}
);
});
}
};
actionCreators.spec.ts:
import configureMockStore from 'redux-mock-store';
import thunk, { ThunkDispatch } from 'redux-thunk';
import { AnyAction } from 'redux';
import * as actions from './actionCreators';
import followApi from './followApi';
jest.mock('./followApi.ts', () => {
return {
handleFavorite: jest.fn()
};
});
type State = any;
const middlewares = [thunk];
const mockStore = configureMockStore<State, ThunkDispatch<State, undefined, AnyAction>>(middlewares);
const store = mockStore();
describe('followings actions', () => {
beforeEach(() => {
store.clearActions();
jest.resetAllMocks();
});
it('dispatches the HANDLE_FAVORITE_SUCCESS action', () => {
expect.assertions(2);
const mockedHandleFavoritePayload = {
followingInfoId: '1',
checked: true
};
(followApi.handleFavorite as jest.MockedFunction<typeof followApi.handleFavorite>).mockResolvedValueOnce(
mockedHandleFavoritePayload
);
const data = 'jest';
const expectedActions = [
{
type: 'HANDLE_FAVORITE_SUCCESS',
payload: {
followingInfoId: '1',
checked: true
}
}
];
return store.dispatch(actions.handleFavorite(data)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
expect(followApi.handleFavorite).toBeCalledWith(data);
});
});
it('dispatches the ERROR action', () => {
const mockedhHndleFavoriteError = new Error('network error');
(followApi.handleFavorite as jest.MockedFunction<typeof followApi.handleFavorite>).mockRejectedValueOnce(
mockedhHndleFavoriteError
);
const data = 'jest';
const expectedActions = [
{
type: 'ERROR',
payload: mockedhHndleFavoriteError
}
];
return store.dispatch(actions.handleFavorite(data)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
expect(followApi.handleFavorite).toBeCalledWith(data);
});
});
});
Unit test result with 100% coverage report:
PASS src/stackoverflow/52025257/actionCreators.spec.ts (5.95s)
followings actions
✓ dispatches the HANDLE_FAVORITE_SUCCESS action (5ms)
✓ dispatches the ERROR action (2ms)
-------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
actionCreators.ts | 100 | 100 | 100 | 100 | |
-------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 6.87s, estimated 7s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/52025257