tp / tsaga

Typesafe and lightweight way to write Redux-connected functions with asynchronous side-effects that are easily testable.
Apache License 2.0
8 stars 1 forks source link

Allow asserting on the state in the middle of the saga #61

Open HenriBeck opened 5 years ago

HenriBeck commented 5 years ago

I think it would be good to allow to not only assert on the final state but also on some intermediate states. This way you would also test the reducers with it.

The question would be if we would still need toHaveFinalState then as this could also be replaced by an assertion directly at the end.

I would propose to create two new assertions: toHaveState and toHavePartialState.

Though as a saga does not trigger them, we would need to decide when we run them. Either directly after they move to the first position of the queue or directly before the next assertion in the queue.

Related: #54

tp commented 5 years ago

I would propose to create two new assertions: toHaveState and toHavePartialState.

👍

Though as a saga does not trigger them, we would need to decide when we run them. Either directly after they move to the first position of the queue or directly before the next assertion in the queue.

That sounds like a tough problem. Especially since I personally would only rarely want to use assertions (as it tests implementation details), but rather provide the least mocks necessary.

What would be a use-case though where one is interested in intermediate states? (I can image our A2B being one example, where we would want to ensure that it's in the loading state for a while.)

One suggestion to the resolve the timing ambiguity might be 2 functions: toImmediatelyHaveState and toEventuallyHaveState?

But overall I would really like to rethink combining assertions with mocks, then we could just add some assertions like this in the overall order (though as discussed before, one might want to re-use mocks multiple times, which would break the order).

One thing I like about the testing is Flutter is that we can basically "pull" blocs along, so we wouldn't have the need to put all possible combinations of assertions in one description. (The runToCompletion function, after which we can assert and continue which new method calls.)

HenriBeck commented 5 years ago

What would be a use-case though where one is interested in intermediate states? (I can image our A2B being one example, where we would want to ensure that it's in the loading state for a while.)

Yes, that would be one of the use cases. I don't we will need this often, but I think it would be nice to have.

I think you would mostly test the state directly after a dispatch assertion.

tp commented 5 years ago

I think you would mostly test the state directly after a dispatch assertion.

Right! :) There is no other point the state would be update. So now we have our trigger and the point in time where to assert on it.

Only remaining question would be API design, to we combine it somehow with toDispatch, do we make toDispatch special so it can accept a state assertion immediately afterwards, or do we introduce something new (for example because we only want to check the action type and not restate the whole payload, before then checking the state (which includes the payload again in some form)).

I am also still thinking about something like toEventuallyHaveState, especially for the case where some tests don't assert much in general. I think in the end it would be much better to use that to say "have this state at some point in time", as it would be completely decoupled from implementation details (which our current approach relies on heavily), and rather just tests the consumer perspective.

HenriBeck commented 5 years ago

toEventuallyHaveState would check after every dispatch if the state matches then, correct?

tp commented 5 years ago

toEventuallyHaveState would check after every dispatch if the state matches then, correct?

Yes, until it finds the first match.