Comments (8)
Redux Saga Test Plan provides integration testing functionality, but you still have to mock out all AJAX requests and your entire state tree. This requires your tests to still know a lot about the implementation details of your sagas/redux store, which would make them fairly brittle.
I think this project's ease of mocking out each external call in your saga to be a huge advantage over the code snippet in this issue.
from redux-saga-test-engine.
Chiming in since my library has been mentioned :)
The example @ms88privat provided is not a typical saga you would write by any means. That was more of an illustrative example to show that you can integrate saga tests with your real reducer. Maybe I should update my documentation with a better real-world scenario.
It's a new feature but redux-saga-test-plan does allow you to mock results from effect creators now via a .provide
method @hmillison. The benefit of that approach is that you can also mock thrown errors, and you don't have to match all the properties of the effect creator to provide a mock value (e.g. the fn
and args
for a call
). Regardless, I do like the way redux-saga-test-engine approaches mock values as well and have considered supporting that approach too.
Regardless, I would appreciate it if this repo didn't use redux-saga-test-plan as a selling point, at least not only showing the unit testing approach. I think that may paint my library as only doing unit testing which is not true. redux-saga-test-plan has grown tremendously in the realm of integration-type testing.
Maybe instead of mentioning redux-saga-test (which I believe is unmaintained anyway) and my library, just show the merits of redux-saga-test-engine over vanilla unit testing sagas. redux-saga-test-engine has a great approach to testing sagas as well, so good job by the way!
from redux-saga-test-engine.
Hey @ms88privat! Thanks for the suggestion! Did you try it out yet? Any more thoughts?
Here are my initial thoughts.
So, in the above example, the test uses a reducer to handle new version of the state so that SELECT(getSomething)
will return a different result the second time after the reducer reacts to a certain PUT
s within the saga. For completion, here is the example saga:
function* saga() {
const ageBefore = yield select(getAge);
yield put({ type: AGE_BEFORE, payload: ageBefore });
yield take(HAVE_BIRTHDAY);
const ageAfter = yield select(getAge); // Note second select, but it will receive a different value
yield put({ type: AGE_AFTER, payload: ageAfter });
}
However, I don't think that's very good saga design. I'm open to debate on this, but it would seem to make sense that your SELECT
s happen early in your saga, which will in turn send out some PUT
s and CALL
s based on that. Having the same SELECT
call yielding different values at different times in the same functions is the epitome of imperative (non-declarative) design. It also goes against the philosophy of my library: the SELECT
s are to be treated as one of the "inputs" of the saga. Multiple values for the same input wouldn't make sense.
Suppose the above saga were instead written as two separate pieces, like so:
function* saga1() {
const ageBefore = yield select(getAge);
yield put({ type: AGE_BEFORE, payload: ageBefore });
}
function* saga2() {
const ageAfter = yield select(getAge);
yield put({ type: AGE_AFTER, payload: ageAfter });
}
function* saga2Listener() {
yield takeEvery(HAVE_BIRTHDAY, saga2)
}
Written this second way, including a reducer is not helpful, since SELECT
ed state in each saga is effectively immutable as far as the saga is concerned, and no reducer is needed to present a new value. And this second way works just fine with my library; just write out some expected state to be SELECT
ed
Now, there's a broader question: Shouldn't a testing library test functions as they actually are, rather than how I might want them to be? I don't have a good response to that other than writing sagas that way is incompatible with the goals/assumptions of this test library.
Anyway, those are my thoughts right now. I'm open to other ideas!
from redux-saga-test-engine.
Btw, if you just wanted to just check that the final state of a reducer after running a saga were what you expected, you can write a trivial helper function like finalState
below to do it.
const actualPuts = sagaTestEngine(sagaToTest, envMapping)
// [
// put({ type: 'INCREMENT' }),
// put({ type: 'INCREMENT' }),
// put({ type: 'INCREMENT' }),
// put({ type: 'DECREMENT' }),
// put({ type: 'INCREMENT' }),
// ]
const initialState = 0
function reducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT': return state + 1
case 'DECREMENT': return state - 1
default: return state
}
}
// Helper.
function finalState(collectedEffects, reducer, initialState) {
return collectedEffects.reduce((state, effect) => {
if (effect.PUT) {
return reducer(state, effect.PUT.action)
} else {
return state
}
}, initialState)
}
t.assertEqual(finalState(actualPuts, reducer, initialState), 3)
from redux-saga-test-engine.
@jfairbank thanks for chiming in. I think you must have just updated the redux-saga-test-plan
docs with the information on .provide
a few hours after I was looking at them!
from redux-saga-test-engine.
No worries, @hmillison! I just released a new version yesterday, so I'm sure you hadn't seen the updated docs yet.
from redux-saga-test-engine.
@jfairbank Thanks for posting here and sharing your thoughts!
Regardless, I would appreciate it if this repo didn't use redux-saga-test-plan as a selling point, at least not only showing the unit testing approach. I think that may paint my library as only doing unit testing which is not true. redux-saga-test-plan has grown tremendously in the realm of integration-type testing.
You're right that my README
is a bit aggressive and perhaps even dismissive of yours and other libraries. That wasn't my intention, and I will make sure to tone it down. I meant it more as explaining the raison d'Γͺtre for why there needs to be yet another testing testing lib for redux-sagas. I still think, however, that a comparison of sorts is useful. Users have to compare similar libraries to figure out which suits their case, and it is a time-consuming thing to do, so IMO it's helpful for library authors/contributors give their take. At the very least I will mention your library can also handle integration testing, which mine certainly doesn't.
On the point of integration testing, I'd be very excited to see you flesh out more examples of that, it sounds like something no one else is doing, and it could be really cool!
from redux-saga-test-engine.
@timbuckley No hard feelings here. I know it wasn't mean-spirited. There's no reason why you shouldn't provide comparisons either. I just wanted to make sure others realized that you can accomplish simple, pain-free tests with redux-saga-test-plan via expectSaga
and not the admittedly verbose testSaga
. You're welcome to peruse the integration docs to draw comparisons to expectSaga
too.
Once I've finished the Redux store integration, I hope to have some more realistic integration-testing examples in place besides what's available in the docs. However, you can already integrate with reducers via expectSaga
, which is nice.
from redux-saga-test-engine.
Related Issues (20)
- Create Changelog HOT 1
- Make README nicer
- TODO: Need mechanism to throw values into the generator during tests HOT 2
- TODO: Compile ES5-version for build for lower Node version compatibility.
- TODO: Update README with instructions for new API. HOT 2
- TODO: Make a table of contents on README.md HOT 1
- TODO: Allow Map as environment mapping argument.
- Need to publish updated npm module HOT 7
- can't import library: Couldn't find preset "env" HOT 12
- TODO: Fix library to be used by properly in a bebelified environment (like React Native) HOT 1
- TODO: Handle array of PUT effects
- Change of repo ownership HOT 3
- 2.0.3 published to npm incorrectly? HOT 5
- Update redux-saga-test-plan comparison
- Improve error message if nested array is incorrect HOT 1
- Unable to pass `undefined` as mock return value HOT 1
- Update to new CircleCI config format HOT 1
- Env Mapping is missing a value for a PUT?
- TODO: Handle yield* HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from redux-saga-test-engine.