Giter Club home page Giter Club logo

Comments (8)

hmillison avatar hmillison commented on June 14, 2024 1

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.

jfairbank avatar jfairbank commented on June 14, 2024 1

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.

timbuckley avatar timbuckley commented on June 14, 2024

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 PUTs 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 SELECTs happen early in your saga, which will in turn send out some PUTs and CALLs 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 SELECTs 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 SELECTed 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 SELECTed

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.

timbuckley avatar timbuckley commented on June 14, 2024

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.

hmillison avatar hmillison commented on June 14, 2024

@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.

jfairbank avatar jfairbank commented on June 14, 2024

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.

timbuckley avatar timbuckley commented on June 14, 2024

@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.

jfairbank avatar jfairbank commented on June 14, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.