Redux saga yield put unit test not working - reactjs

I looking to doc and some samples online, but still not working. I use Sinon for unit test, and I keep getting this error, stuck on this one so long, can't figure it out.
expected { Object (##redux-saga/IO, combinator, ...) } to deeply equal { Object (##redux-saga/IO, combinator, ...) }
My action
export const loadingStatus = (response) => {
return { type: "LOADING_STATUS", response };
};
My saga
export function* mySampleSaga() {
try {
yield put(loadingStatus('loading'));
yield delay(1000);
const config = yield select(getConfig);
const requestCall = new SendingRequest(config);
const linkRequests = yield select(getLinks);
const response = yield call(
[requestService, requestCall.sample],
"2020-01-01",
"2020-12-21"
);
const result = get(response, 'entities.requests', {});
yield put(success(result));
yield put(loadingStatus('done'));
} catch (error) {
yield put(sendError(error));
yield put(loadingStatus('done'));
}
}
My test
describe('sample saga', () => {
const config = {
sample: "123"
};
const linkRequests = ['12345', '5678910'];
it('should update request status - happy path', () => {
const gen = mySampleSaga();
expect(gen.next().value).to.deep.equal(put(loadingStatus('loading'))); // This keep getting error below
});
it('If saga has error', () => {
const gen = mySampleSaga();
const error = new Error('error');
gen.next();
expect(gen.next().value).to.deep.equal(put(sendError(error)));
expect(gen.next().value).to.deep.equal(put(loadingStatus('done')));
expect(gen.next().done).to.equal(true);
});
});

Related

How To Know If Dispatch Is Success or No In Redux Saga

So i already create the createMonsterStart and it will hit my API, my API is returning response code, and I want to alert success when the response code is 00 otherwise it will alert failed, how can i achieve that? here is my code:
const onSubmitHandler = () => {
dispatch(createMonsterStart(monster))
if(dispatch success){
alert("success")
}else{
alert("error")
}
}
And here is the redux saga code:
export function* createMonsterAsync({ payload: { monster } }) {
try {
const user = yield select(getUser)
const a = yield call(createMonster, user.user.token, monster)
if (a.error) {
yield put(createMonsterFailure(a.error))
return false
}
const monsters = yield call(fetchMonsterAsync)
yield put(createMonsterSuccess(monsters))
} catch (error) {
yield put(createMonsterFailure(error))
}
}

Use eventChannel to get real time data from Firestore

I would like to sync my data in React with Firestore, each time some data is changed I would like to have an update/refresh of my data.
For fetching the data I have:
function* syncCustomers() {
try {
const response = yield call(fireBaseBackend.getCustomersAPI);
yield put(loadCustomers(response));
} catch (error) {
yield put(customerError(error));
}
}
Where my getCustomersAPI is:
getCustomersAPI = () => {
return new Promise((resolve, reject) => {
firebase.firestore().collection("customers").onSnapshot((snap) => {
let documents = [];
snap.docs.forEach(doc => {
let result = doc.data();
result.uid = doc.id;
documents.push(result);
});
resolve(documents);
});
});
};
This works to get my data, for the real time I implemented:
function* usersChannelSaga () {
try {
while (true) {
const response = yield call(fireBaseBackend.getCustomersAPI);
yield put(loadCustomers(response));
}
}
catch (error) {
yield put(customerError(error));
}
}
But I would like to use the eventChannel for this. How does this need to be implemented?
I tried:
function* usersChannelSaga () {
const channel = eventChannel(emit => fireBaseBackend.syncCustomers(emit));
try {
while (true) {
const data = yield take(channel);
yield put(loadCustomers(response));
}
}
catch (error) {
yield put(customerError(error));
}
}
Where syncCustomers is :
syncCustomers(emit){
return firebase.firestore().collection("customers").onSnapshot(emit);
}
Anyone an idea how to solve this?

How to mock variables inside redux saga generator functions?

how can I test the saga below?
export function* getSnapShotFromUserAuth(userAuth, additionalData) {
try {
const userRef = yield call(
createUserProfileDocument,
userAuth,
additionalData
);
const userSnapshot = yield userRef.get();
yield put(signInSuccess({ id: userSnapshot.id, ...userSnapshot.data() }));
} catch (error) {
yield put(signInFailure(error));
}
}
I was only able to get it working up until the first line:
describe("getSnapShotFromUserAuth", () => {
const mockUserAuth = {};
const mockAdditionalData = {};
const generator = getSnapShotFromUserAuth(mockUserAuth, mockAdditionalData);
it("should get snapshot from user auth", () => {
expect(generator.next().value).toEqual(
call(createUserProfileDocument, mockUserAuth, mockAdditionalData)
);
});
});
How can I verify the next line? const userSnapshot = yield userRef.get();
I keep getting error TypeError: Cannot read property 'get' of undefined when calling trying to test the next line as it cannot find userRef. Is there a way to be able to mock the next line?
You can dictate what the result of the yield is by what you pass in when you call next(). So for example, after doing the first generator.next, you can do:
const mockUserRef = {
get: jest.fn();
}
expect(generator.next(mockUserRef).value).toEqual(/* whatever */);
Answer -
it("should check for signInSuccess", () => {
const myMock = jest.fn();
let userRef = {
get: myMock.mockReturnValue({
id: 1,
data: () => {},
}),
};
let userSnapshot = {
id: 1,
data: () => {},
};
generator.next(userRef);
expect(generator.next(userSnapshot).value).toEqual(
put(signInSuccess({ id: userSnapshot.id, ...userSnapshot.data() }))
);
});

Put expectaion unmet in redux-saga-test plan

So I have a saga which shows fetches some data to show in a table.
Action Creators are as follows
export const fetchInstanceDataSetAssocSuccess = (records) => {
return {
type: actionTypes.FETCH_INSTANCE_DATASETS_ASSOC_SUCCESS,
records: records
}
}
export const fetchInstanceDataSetAssocFailed = (error) => {
return {
type: actionTypes.FETCH_INSTANCE_DATASETS_ASSOC_FAILED,
error: error
}
}
export const fetchInstanceDataSetAssocStart = () => {
return {
type: actionTypes.FETCH_INSTANCE_DATASETS_ASSOC_START
}
}
export const fetchInstanceDataSetAssoc = () => {
return {
type: actionTypes.FETCH_INSTANCE_DATASETS_ASSOC_INITIATE
}
}
My saga is as follows
function * fetchInstanceDataSetAssocSaga (action) {
yield put(instanceDataSetAssocActions.fetchInstanceDataSetAssocStart())
const useMockData = yield constants.USE_MOCK_DATA
if (useMockData) {
yield delay(constants.MOCK_DELAY_SECONDS * 1000)
}
try {
const res = (useMockData)
? (yield constants.INSTANCE_DATASET_ASSOC)
: (yield call(request, {url:
API_URLS.INSTANCE_DATASET_ASSOC_API_ENDPOINT, method: 'GET'}))
yield put(instanceDataSetAssocActions.fetchInstanceDataSetAssocSuccess(res.data))
} catch (error) {
yield
put(instanceDataSetAssocActions.fetchInstanceDataSetAssocFailed(error))
}
}
Action to watch over the Saga is as follows
export function * watchInstanceDataSetAssocSaga () {
yield takeEvery(actionTypes.FETCH_INSTANCE_DATASETS_ASSOC_INITIATE,
fetchInstanceDataSetAssocSaga)
}
Test Cases are as follows
describe('load instance dataset assoc table', () => {
test('update state with instance-dataset records for landing page',() => {
const finalState = {
records: constants.INSTANCE_DATASET_ASSOC.data,
loading: false,
error: false
}
const requestParam = {url: API_URLS.INSTANCE_DATASET_ASSOC_API_ENDPOINT, method: 'GET'}
return expectSaga(watchInstanceDataSetAssocSaga)
.provide([[call(request,requestParam),constants.INSTANCE_DATASET_ASSOC]])
.withReducer(instanceDataSetAssoc)
.put(instanceDataSetAssocActions.fetchInstanceDataSetAssocStart())
.put(instanceDataSetAssocActions.fetchInstanceDataSetAssocSuccess(constants.INSTANCE_DATASET_ASSOC.data))
.dispatch(instanceDataSetAssocActions.fetchInstanceDataSetAssoc())
.hasFinalState(finalState)
.silentRun()
})
})
I get the following error for this.
SagaTestError:
put expectation unmet:
at new SagaTestError (node_modules/redux-saga-test-plan/lib/shared/SagaTestError.js:17:57)
at node_modules/redux-saga-test-plan/lib/expectSaga/expectations.js:63:13
at node_modules/redux-saga-test-plan/lib/expectSaga/index.js:572:7
at Array.forEach (<anonymous>)
at checkExpectations (node_modules/redux-saga-test-plan/lib/expectSaga/index.js:571:18)
I am following the docs correctly but still getting the above error.
Maybe its late, but i found an answer, maybe it will help you
This mistake may occure because of library timeout try to turn off the timeout with .run(false)
original link https://github.com/jfairbank/redux-saga-test-plan/issues/54

How to chain firebase observables using redux-saga?

I've recently made the move from ionic/angular2/Rxjs to React/React Native/Redux-sagas. I'm porting over my app from ionic to react native and have really enjoyed the process. One thing, however, I have really struggled with is using firebase in react native via redux sagas. I can do simple requests however I would like to chain three requests and get the return value as an JSON object. Currently I have this :
export const getTuteeUID = state => state.login.username;
function* getMemberProfiles(UID) {
try {
const memberObject = yield call(get, 'userProfile', UID);
return memberObject;
} catch (err) {
console.log(err);
}
}
function* getLatestConversation(grpID) {
try {
const opts = newOpts();
const refLatestConvo = firebase
.database()
.ref('conversations')
.child(`${grpID}`)
.orderByChild('createdAt')
.limitToLast(1);
yield call([refLatestConvo, refLatestConvo.on], 'value', opts.handler);
while (true) {
const { data } = yield take(opts);
if (data.val()) {
return data.val()[data._childKeys[0]];
}
return null;
}
} catch (err) {
console.log(err);
}
}
export function* getChatGroupObject(grpID, tuteeUID) {
try {
const groupObject = yield call(get, 'groups', grpID);
const memberProfiles = yield Object.keys(groupObject.members)
.filter(mem => mem !== tuteeUID)
.map(memUID => call(getMemberProfiles, memUID));
const latestConversation = yield call(getLatestConversation, grpID);
return { ...groupObject, memberProfiles, key: grpID, latestConversation };
} catch (err) {
console.log(err);
}
}
/**
*
* #return {Generator} []
*/
export function* fetchChatGroups() {
try {
const opts = newOpts();
const tuteeUID = yield select(getTuteeUID);
const refGrpIDs = firebase.database().ref('userProfile').child(`${tuteeUID}/groups`);
const snapGrpIDs = yield call([refGrpIDs, refGrpIDs.once], 'value', opts.handler);
if (snapGrpIDs.val()) {
const groupObject = yield Object.keys(snapGrpIDs.val()).map(grpID =>
call(getChatGroupObject, grpID, tuteeUID),
);
yield put(ChatAction.chatGroupsReceived(groupObject));
} else {
ChatAction.chatGroupsReceived([]);
}
} catch (error) {
console.log(error);
}
}
Now this works and returns the correct object, however if the latest conversation in the array changes the object won't update. How can I get this to continue updating? Another thing is if I were to put this in a while(true) loop, is there a way to unsubscribe from the observable? In rxjs this used to be super easy to do.

Resources