Cannot read property of undefined data() Firebase - javascript

I'm trying to implement redux saga in my old project and i get strange error.
I'm getting back the userData with all user details but my middleware logger tells me that sign_in_failed fires instead of sign_in_success with this error:
Cannot read property of undefined data() Firebase.
So i tried to do optional chaining and i also tried the old way of deep property check (with &&) but this didnt help. Also, i cant anymore perform a stripe payments due to this error because stripe cant see the user.
UserSaga.jsx
import { takeLatest, all, call, put } from 'redux-saga/effects'
import { USER_ACTIONS_TYPES } from '../../actions/user/userActionsTypes'
import {
signInSuccess,
signInFailed,
signUpSuccess,
signUpFailed,
signOutSuccess,
signOutFailed
} from '../../actions/user/userActionCreator'
import {
getCurrentUser,
createUserDocumentFromAuth,
createAuthUserWithEmailAndPassword,
signInWithGooglePopup,
signInAuthUserWithEmailAndPassword,
signOutAuthUser
} from '../../../database/firebase.config'
export function* getUserSnapshot(userAuth, additionalInformation) {
try {
const userSnapshot = yield call(
createUserDocumentFromAuth,
userAuth,
additionalInformation
);
//yield put(signInSuccess({ id: userSnapshot?.id, ...userSnapshot.data()}));
// console.log('userSnapshot2>>>>>>>>>', ...userSnapshot.data())
const id = userSnapshot?.id;
const userData = userSnapshot.data()
const {createdAt, email, password}= userData
yield put(signInSuccess({ id, createdAt, email, password }));
console.log('userSnapshot2>>>>>>>>>', userSnapshot)
} catch (error) {
yield put(signInFailed(error.message))
}
}
export function* signInWithGoogle() {
try {
const { user } = yield call(signInWithGooglePopup)
yield call(getUserSnapshot, user)
} catch (error) {
yield put(signInFailed(error))
}
}
export function* signInWIthEmail({ payload: { email, password } }) {
try {
const { user } = yield call(signInAuthUserWithEmailAndPassword, email, password)
yield call(getUserSnapshot, user)
} catch (error) {
yield put(signInFailed(error))
}
}
export function* isUserAuth() {
try {
const userAuth = yield call(getCurrentUser)
if (!userAuth) return;
yield call(getUserSnapshot, userAuth)
} catch (error) {
yield put(signInFailed(error))
}
}
export function* signUpWIthEmail({ payload: { email, password, displayName } }) {
try {
const { user } = yield call(createAuthUserWithEmailAndPassword, email, password)
yield put(signUpSuccess(user, { displayName }))
} catch (error) {
yield put(signUpFailed(error))
}
}
export function* signOut() {
try {
yield call(signOutAuthUser)
yield put(signOutSuccess())
} catch (error) {
yield put(signOutFailed(error))
}
}
export function* signInAfterSignUp({ payload: { user, additionalDetails } }) {
yield call(getUserSnapshot, user, additionalDetails)
}
export function* onGoogleSignInStart() {
yield takeLatest(USER_ACTIONS_TYPES.GOOGLE_SIGN_IN_START, signInWithGoogle)
}
export function* onCheckUserSession() {
yield takeLatest(USER_ACTIONS_TYPES.CHECK_USER_SESSION, isUserAuth)
}
export function* onEmailSignInStart() {
yield takeLatest(USER_ACTIONS_TYPES.EMAIL_SIGN_IN_START, signInWIthEmail)
}
export function* onSignUpStart() {
yield takeLatest(USER_ACTIONS_TYPES.SIGN_UP_START, signUpWIthEmail)
}
export function* onSignUpSuccess() {
yield takeLatest(USER_ACTIONS_TYPES.SIGN_IN_SUCCESS, signInAfterSignUp)
}
export function* onSignOutStart() {
yield takeLatest(USER_ACTIONS_TYPES.SIGN_OUT_START, signOut)
}
export function* userSagas() {
yield all([
call(onCheckUserSession),
call(onGoogleSignInStart),
call(onEmailSignInStart),
call(onSignUpStart),
call(onSignUpSuccess),
call(onSignOutStart),
call(onSignUpSuccess)
])
}
firebase.config.js
// Initialize Firebase and Oauth
initializeApp(firebaseConfig);
const googleProvider = new GoogleAuthProvider();
googleProvider.setCustomParameters({
prompt: "select_account"
})
//Initialize GAuth with popup signin method
export const auth = getAuth()
export const signInWithGooglePopup = () => signInWithPopup(auth, googleProvider)
// export const signInWithGoogleRedirect = () => signInWithRedirect(auth, googleProvider)
// Initialize Firestore
export const db = getFirestore()
// get the conllection created with all docs
export const getCollectionWithDocuments = async() => {
const collectionRef = collection(db, 'categories')
const q = query(collectionRef)
const querySnapShot = await getDocs(q)
return querySnapShot.docs.map(docSnapshot => docSnapshot.data())
}
//Create a user document
export const createUserDocumentFromAuth = async(userAuth, additionalInformation = {}) => {
if (!userAuth) return;
const userDocRef = doc(db, 'users', userAuth.uid)
// console.log('userRef>>', userDocRef)
const userSnapshot = await getDoc(userDocRef)
// console.log('just snapshot>>>', snapShot)
// console.log('if shot exist>>', snapShot.exists())
if (!userSnapshot.exists()) {
const { displayName, email } = userAuth
const createdAt = new Date();
try {
await setDoc(userDocRef, {
displayName,
email,
createdAt,
...additionalInformation
})
} catch (error) {
console.log("error creating user", error.message)
}
}
return userSnapshot;
}
export const createAuthUserWithEmailAndPassword = async(email, password) => {
if (!email || !password) return;
return await createUserWithEmailAndPassword(auth, email, password)
}
export const signInAuthUserWithEmailAndPassword = async(email, password) => {
if (!email || !password) return;
return await signInWithEmailAndPassword(auth, email, password)
}
export const signOutAuthUser = async() => await signOut(auth)
export const onAuthObserver = (callback) => onAuthStateChanged(auth, callback)
//Create a collection of document in firestore (call it ones inside useeffect to avoid mutations)
export const createCollectionWithDocuments = async(collectionName, objectsToAdd) => {
const collectionRef = collection(db, collectionName)
const batch = writeBatch(db)
objectsToAdd.forEach(object => {
const docRef = doc(collectionRef, object.title.toLowerCase())
batch.set(docRef, object)
})
await batch.commit()
console.log('collection created')
}
export const getCurrentUser = () => {
return new Promise((resolve, reject) => {
const unsubscribe = onAuthStateChanged(
auth,
(userAuth) => {
unsubscribe();
resolve(userAuth);
// console.log(userAuth)
},
reject)
})
}
userReducer.jsx
export const INITIAL_STATE = {
currentUser: null,
isLoading: false,
error: null
}
export const userReducer = (state = INITIAL_STATE, action) => {
const { type, payload } = action;
switch (type) {
case USER_ACTIONS_TYPES.SIGN_IN_SUCCESS:
return {
...state,
currentUser: payload,
error: null
}
case USER_ACTIONS_TYPES.SIGN_OUT_SUCCESS:
return {
...state,
currentUser: null
}
case USER_ACTIONS_TYPES.SIGN_OUT_FAILED:
case USER_ACTIONS_TYPES.SIGN_UP_FAILED:
case USER_ACTIONS_TYPES.SIGN_IN_FAILED:
return {
...state,
error: payload
}
default:
return state
}
}
userActions.js
export const emailSignInStart = (email, password) => createActions(USER_ACTIONS_TYPES.EMAIL_SIGN_IN_START, { email, password })
export const signInSuccess = user => createActions(USER_ACTIONS_TYPES.SIGN_IN_SUCCESS, user)
export const signInFailed = error => createActions(USER_ACTIONS_TYPES.SIGN_IN_FAILED, error)

Related

Redux actions always in pending state

I am trying to create a scraping application using redux toolkit for learning purposes.Whenever I dispatch the action the data gets scraped and console logged but the action state is never fullfilled and is always pending
MY ASYNC THUNK
export const loadData = createAsyncThunk(
"alldata/getdata",
async ({ pageNo, language }, thunkAPI) => {
const data = await fetch(
`http://localhost:5000/scrape?pageNo=${encodeURIComponent(
pageNo
)}&language=${encodeURIComponent(language)}`
);
const res=await data.json()
return {
payload: res,
};
}
);
MY SLICE
const projectSlice = createSlice({
name: "allprojects",
initialState: {
projectState: [],
workingState: [],
isLoading: false,
hasError: false,
},
reducers: {
addProject: (state, action) => {
return state.workingState.push(action.payload);
},
removeProject: (state, action) => {
return state.workingState.filter(
(project) => project.link !== action.payload.link
);
},
},
extraReducers: {
[loadData.pending]: (state, action) => {
state.isLoading = true;
state.hasError = false;
},
[loadData.fulfilled]: (state, { payload }) => {
state.projectState = payload;
state.isLoading = false;
state.hasError = false;
},
[loadData.rejected]: (state, action) => {
state.isLoading = false;
state.hasError = true;
},
},
});
export const { addProject, removeProject } = projectSlice.actions;
const Projectreducer = projectSlice.reducer;
export default Projectreducer;
export const projectSelector = (state) => state.allprojects;
REACT COMPONENT
const { workingState, projectState, isLoading, hasError } =
useSelector(projectSelector);
const dispatch = useDispatch();
const [selectData, setSelectData] = React.useState({ languages: "" });
const [pageData, setPageData] = React.useState({ pageNo: 1 });
const handleClick = (event) => {
event.preventDefault();
dispatch(
loadData({ pageNo: pageData.pageNo, language: selectData.languages })
);
};
So how do I get the action to be fullfilled and push the data in the ProjectState array after the async request
EDIT:
API
app.get("/scrape", async (req, res) => {
const { pageNo, language } = req.query;
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto(
`https://github.com/search?p=${pageNo}&q=language%3A${language}`,
{
waitUntil: "domcontentloaded",
}
); // URL is given by the "user" (your client-side application)
const data = await page.evaluate(() => {
const list = [];
const items = document.querySelectorAll(".repo-list-item");
for (const item of items) {
list.push({
projectName: item.querySelector(".f4 > a").innerText,
about: item.querySelector("p").innerText,
link: item.querySelector("a").getAttribute("href"),
});
}
return list;
});
console.log(data);
await browser.close();
});
Store
import { configureStore } from "#reduxjs/toolkit";
import Projectreducer from "./Slices/slice";
export const store = configureStore({
reducer: {
allprojects: Projectreducer,
},
});
Its possible that the api that you are fetching is throwing an error so in this case it always recommended to have a catch block and throw an error to that its falls into loadData.rejected state.
So, do the check network tab in the dev tools of the browser that you are using, so that you can confirm if the api is responding or not.
Also can you share the projectSelector selector ? could be the something wrong in the selector.
action:
export const loadData = createAsyncThunk(
'alldata/getdata',
async ({ pageNo, language }, { rejectWithValue }) => {
try {
const data = await fetch(
`http://localhost:5000/scrape?pageNo=${encodeURIComponent(
pageNo
)}&language=${encodeURIComponent(language)}`
);
const res = await data.json();
return {
payload: res,
};
} catch (error) {
return rejectWithValue({ payload: error?.message || error });
}
}
);
reducer:
extraReducers: {
...,
[loadData.rejected]: (state, { payload }) => {
state.isLoading = false;
state.hasError = true;
state.message = payload;
},
},
One more thing to mention here is that redux toolkit recommends to use builder callback, for more details check here:
https://redux-toolkit.js.org/api/createslice#extrareducers
in your example it would be like
extraReducers: (builder) => {
builder
.addCase(loadData.pending, (state) => {
...
})
.addCase(loadData.fulfilled, (state, action) => {
...
})
.addCase(loadData.rejected, (state, action) => {
...
});

The 'refreshToken' function makes the dependencies of useEffect Hook (at line 142) change on every render

I've been trying to deploy my first React App and i cannot seem to be able to get rid of the following warning which on production stops me from doing a deployment:
Line 60:11: The 'refreshToken' function makes the dependencies of useEffect Hook (at line 142) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of 'refreshToken' in its own useCallback() Hook react-hooks/exhaustive-deps
Is there an easy way to fix this without breaking the JWT token authentification?
AuthContext.js
import React, { useEffect, useState, useCallback } from 'react'
import { API } from "../api"
import axios from "axios"
import { isAfter, isEqual, parseISO, sub } from 'date-fns'
export const AuthContext = React.createContext(null)
export function AuthContextProvider({ children }) {
const [accessTokenExpiration, setAccessTokenExpiraton] = useState(undefined);
const getUser = () => {
return JSON.parse(localStorage.getItem('user'))
}
const isLoggedIn = () => {
return localStorage.getItem('user') !== null
}
const [user, setUser] = useState(() => {
return isLoggedIn() ? getUser() : null;
})
const [shouldGoToLogin, setShouldGoToLogin] = useState(() => {
if (!user || !user.access_token || !user.refresh_token) {
return true;
}
return false;
})
const logout = async () => {
if (!user) {
return;
}
const { access_token } = user;
localStorage.removeItem('user')
setUser(null);
return axios.post(API.auth.logout, {
headers: {
"Authorization": `Bearer ${access_token}`,
"Content-Type": "application/json"
},
withCredentials: true
});
}
const login = async (values) => {
console.log(values);
const correctedValues = { ...values, username: values.email };
return axios.post(API.auth.login, correctedValues)
.then(res => {
const data = res.data;
processApiData(data);
})
}
const processApiData = useCallback((resp) => {
let newUser = { ...user, ...resp };
delete(newUser.user); // Delete the user sub-object since we merged that directly into the top-level object
saveUser(newUser); // Save the user
const { access_token_expiration } = newUser;
if (access_token_expiration) {
console.log("have expiration", access_token_expiration);
const nextExpiration = parseISO(access_token_expiration); // Convert from ISO 8601 to a Date Object
const earlyRefreshTime = sub(nextExpiration, { minutes: 55 }); // Do an hourish early
setAccessTokenExpiraton(earlyRefreshTime); // Set the upcoming expiraton
}
}, [user])
const refreshToken = useCallback(async () => {
const user = getUser();
const redirectToLogout = () => {
localStorage.clear(); // Clear our localStorage
setShouldGoToLogin(true);
};
if (!user) { // No user
redirectToLogout();
}
console.log(API.auth.refreshToken);
const resp = await fetch(API.auth.refreshToken, {
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({'refresh': user?.refresh_token}),
method: "POST",
withCredentials: true
})
console.log("status", resp.status);
if (resp.status === 200) {
const data = await resp.json(); // Convert to JSON
console.log("refresh token data", data);
processApiData(data);
} else {
redirectToLogout();
}
}, [processApiData])
const resetPassword = async (values) => {
return axios.post(API.auth.passwordReset, values);
}
const saveUser = async (newUser) => {
localStorage.setItem('user', JSON.stringify(newUser))
setUser(newUser)
}
const signup = async (values) => {
return axios.post(API.auth.signup, values);
}
useEffect(() => {
if (!user) {
return;
}
const interval = setInterval(()=> {
if(!user){
return false;
}
if (accessTokenExpiration) {
const now = new Date(); // Get the current time
console.log(now);
console.log(accessTokenExpiration);
if (isAfter(now, accessTokenExpiration) || isEqual(now, accessTokenExpiration)) { // If we are late to the party or the stars have aligned
refreshToken(); // Refresh the token
}
} else { // We do not have an access token expiration yet
refreshToken(); // Refresh the token immediately so we get a time
}
}, 1000 * 15)
return ()=> clearInterval(interval)
}, [accessTokenExpiration, refreshToken, user])
return (
<AuthContext.Provider value={{
getUser,
isLoggedIn,
logout,
login,
resetPassword,
signup,
user,
shouldGoToLogin
}}>
{children}
</AuthContext.Provider>
)
}
Put refreshToken function directly in your useEffect hook or wrap in useCallback.

Uncaught ReferenceError: keyword is not defined at UseFetch.jsx and at Transactions.jsx

I am trying to load a website to my localhost but keep running into an error that says Uncaught ReferenceError: keyword is not defined at useFetch (:3000/src/hooks/useFetch.jsx:21:7) at TransactionsCard (:3000/src/components/Transactions.jsx:33:18). The issue hapens in my code where I'm fetching gifs from my API at giphy developer.
Here is the source code:
Transactions.jsx:
import React, { useEffect, useState } from "react";
import { ethers } from "ethers";
import { contractABI, contractAddress } from "../utils/constants";
export const TransactionContext = React.createContext();
const { ethereum } = window;
const createEthereumContract = () => {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const transactionsContract = new ethers.Contract(contractAddress, contractABI, signer);
return transactionsContract;
};
export const TransactionsProvider = ({ children }) => {
const [formData, setformData] = useState({ addressTo: "", amount: "", keyword: "", message: "" });
const [currentAccount, setCurrentAccount] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [transactionCount, setTransactionCount] = useState(localStorage.getItem("transactionCount"));
const [transactions, setTransactions] = useState([]);
const handleChange = (e, name) => {
setformData((prevState) => ({ ...prevState, [name]: e.target.value }));
};
const getAllTransactions = async () => {
try {
if (ethereum) {
const transactionsContract = createEthereumContract();
const availableTransactions = await transactionsContract.getAllTransactions();
const structuredTransactions = availableTransactions.map((transaction) => ({
addressTo: transaction.receiver,
addressFrom: transaction.sender,
timestamp: new Date(transaction.timestamp.toNumber() * 1000).toLocaleString(),
message: transaction.message,
keyword: transaction.keyword,
amount: parseInt(transaction.amount._hex) / (10 ** 18)
}));
console.log(structuredTransactions);
setTransactions(structuredTransactions);
} else {
console.log("Ethereum is not present");
}
} catch (error) {
console.log(error);
}
};
const checkIfWalletIsConnect = async () => {
try {
if (!ethereum) return alert("Please install MetaMask.");
const accounts = await ethereum.request({ method: "eth_accounts" });
if (accounts.length) {
setCurrentAccount(accounts[0]);
getAllTransactions();
} else {
console.log("No accounts found");
}
} catch (error) {
console.log(error);
}
};
const checkIfTransactionsExists = async () => {
try {
if (ethereum) {
const transactionsContract = createEthereumContract();
const currentTransactionCount = await transactionsContract.getTransactionCount();
window.localStorage.setItem("transactionCount", currentTransactionCount);
}
} catch (error) {
console.log(error);
throw new Error("No ethereum object");
}
};
const connectWallet = async () => {
try {
if (!ethereum) return alert("Please install MetaMask.");
const accounts = await ethereum.request({ method: "eth_requestAccounts", });
setCurrentAccount(accounts[0]);
window.location.reload();
} catch (error) {
console.log(error);
throw new Error("No ethereum object");
}
};
const sendTransaction = async () => {
try {
if (ethereum) {
const { addressTo, amount, keyword, message } = formData;
const transactionsContract = createEthereumContract();
const parsedAmount = ethers.utils.parseEther(amount);
await ethereum.request({
method: "eth_sendTransaction",
params: [{
from: currentAccount,
to: addressTo,
gas: "0x5208", //21,000 gwei in hexadecimal form
value: parsedAmount._hex,
}],
});
const transactionHash = await transactionsContract.addToBlockchain(addressTo, parsedAmount, message, keyword);
setIsLoading(true);
console.log(`Loading - ${transactionHash.hash}`);
await transactionHash.wait();
console.log(`Success - ${transactionHash.hash}`);
setIsLoading(false);
const transactionsCount = await transactionsContract.getTransactionCount();
setTransactionCount(transactionsCount.toNumber());
window.location.reload();
} else {
console.log("No ethereum object");
}
} catch (error) {
console.log(error);
throw new Error("No ethereum object");
}
};
useEffect(() => {
checkIfWalletIsConnect();
checkIfTransactionsExists();
}, [transactionCount]);
return (
<TransactionContext.Provider
value={{
transactionCount,
connectWallet,
transactions,
currentAccount,
isLoading,
sendTransaction,
handleChange,
formData,
}}
>
{children}
</TransactionContext.Provider>
);
};
useFetch.jsx:
import { useEffect, useState } from 'react';
const API_KEY = import.meta.env.VITE_GIPHY_API;
const useFetch = () => {
const [gifUrl, setGifUrl] = useState("");
const fetchGifs = async () => {
try {
const response = await fetch(`https://api.giphy.com/v1/gifs/search?api_key=${API_KEY}&q=${keyword.split(" ").join("")}&limit=1`)
const { data } = await response.json();
setGifUrl(data[0]?.images?.downsized_medium?.url)
} catch (error) {
setGifUrl('https://metro.co.uk/wp-content/uploads/2015/05/pokemon_crying.gif?quality=90&strip=all&zoom=1&resize=500%2C284')
}
}
useEffect(() => {
if (keyword) fetchGifs();
}, [keyword]);
return gifUrl;
}
export default useFetch;
When I comment out the lines that use 'keyword' it launches with no errors. This is at lines 14, 18, and 58-62 of Transactions.jsx.
Any help would be greatly appreciated, thank you!
The problem here is that you have not define keyword inside your useFetch function.
If you are trying to pass the keyword from the place where you use useFetch then do something like below and use the useFetch like const gifUrl = useFetch(<keyword>)
import { useEffect, useState } from 'react';
const API_KEY = import.meta.env.VITE_GIPHY_API;
const useFetch = (keyword) => {
const [gifUrl, setGifUrl] = useState("");
const fetchGifs = async () => {
try {
const response = await fetch(`https://api.giphy.com/v1/gifs/search?api_key=${API_KEY}&q=${keyword.split(" ").join("")}&limit=1`)
const { data } = await response.json();
setGifUrl(data[0]?.images?.downsized_medium?.url)
} catch (error) {
setGifUrl('https://metro.co.uk/wp-content/uploads/2015/05/pokemon_crying.gif?quality=90&strip=all&zoom=1&resize=500%2C284')
}
}
useEffect(() => {
if (keyword) fetchGifs();
}, [keyword]);
return gifUrl;
}
export default useFetch;
or even try adding default value for key work like below.
const useFetch = (keyword = "some keyword") => {

Cannot read property OnSnapshot of undefined

componentDidMount() {
this.authListener = auth.onAuthStateChanged( async userAuth => {
if(userAuth){
const userRef = await handleUserProfile(userAuth); userRef.onSnapshot(snapshot=>{
this.setState({ currentUser:{ id:snapshot.id, ...snapshot.data() } }) }) } this.setState({ ...initialState })
});
}
Your function handleUserProfile is not returning the userRef so you get that error. It would be great to provide more that to help you more with this. Maybe the code of that function handleUserProfile.
Can you try to updated your handleUserProfile function to:
export const handleUserProfile = async ({ userAuth, additionalData = {} }) => {
if (!userAuth) {
console.warn("No userAuth provided!");
return;
}
const { uid } = userAuth;
const userRef = firestore.doc(`users/${uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { displayName, email } = userAuth;
const timestamp = new Date();
try {
await userRef.set({
displayName,
email,
createdDate: timestamp,
...additionalData,
});
} catch (err) {
console.warn(err);
}
}
return userRef;
};
If you are getting the log No userAuth provided! you are not sending a userAuth to it.

Redux Saga not started?

I've written these actions and the saga to listen for them.
export async function addToWishlistApi(id: number) {
console.log("addToWishlistApi HELLO CAN ANYBODY HEAR ME");
const res = await axios.get(WishlistUrls.add(id));
console.log(res);
}
export function* addToWishlistSaga({ id }: { id: number }): Saga<void> {
console.log("addToWishlistSaga HELLO CAN ANYBODY HEAR ME");
try {
const res = yield call(addToWishlistApi, id);
console.log(res);
const wishlist = yield call(getCurrentWishlist);
console.log("WISHLIST", wishlist);
if (wishlist.contains(id))
yield put({ type: DealActionTypes.wishlistSuccess });
} catch (error) {
console.log("ERROR", error);
}
}
export async function getCurrentWishlist(): Promise<number[]> {
const res = await axios.get(WishlistUrls.getWishlist);
console.log(res.data.includes("WISHLIST-2.HTML"));
const $ = cheerio.load(res.data);
const tags = $(".button.yith-wcqv-button");
const idStrings: string[] = [];
tags.each((i, tag) => {
idStrings.push(tag.attribs["data-product_id"]);
});
const wishlist = idStrings.map(n => Number(n));
return wishlist;
}
export default function* wishlistSaga(): Saga<void> {
yield all([
yield takeEvery(DealActionTypes.addToWishlistStart, addToWishlistSaga),
yield takeEvery(
DealActionTypes.removeFromWishlistStart,
removeFromWishlistSaga
)
]);
}
I'm trying to test with recordSaga
import { runSaga } from "redux-saga";
export default async function recordSaga(saga, initialAction) {
const dispatched = [];
await runSaga(
{ dispatch: action => dispatched.push(action) },
saga,
initialAction
).done;
return dispatched;
}
And here are my tests:
describe("addToWishlistSaga", () => {
const startAction: Type.AddToWishlistStartAction = {
type: Types.addToWishlistStart,
id: deal.id
};
const successAction: Type.WishlistSuccessAction = {
type: Types.wishlistSuccess
};
const failureAction: Type.AddToWishlistFailureAction = {
type: Types.addToWishlistFailure,
id: deal.id
};
fit("dispatches a success action on success", async () => {
const dispatched = await recordSaga(wishlistSaga, startAction);
expect(dispatched).toContainEqual(successAction);
});
xit("dispatches a failure action on failure", async () => {
mock.onGet(WishlistUrls.add(deal.id)).networkErrorOnce();
const dispatched = await recordSaga(wishlistSaga, startAction);
expect(dispatched).toContainEqual(failureAction);
});
});
});
The saga setup and test setup are identical to what I've used successfully in other projects, but for some reason addToWishlistSaga is never being run. None of the desperate log statements are being printed, and dispatched comes back empty.
What am I doing wrong here? My head is about to explode.

Categories

Resources