Skip to content

Commit

Permalink
StoreTester.dispatchAndWait() method.
Browse files Browse the repository at this point in the history
  • Loading branch information
marcglasberg committed Feb 1, 2024
1 parent 182a3df commit 79c60f2
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 36 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ Please visit the <a href="https://github.com/marcglasberg/redux_app_example">Red
repository in GitHub for a full-fledged example with a complete app showcasing the fundamentals and
best practices described in the AsyncRedux Readme.

# [21.1.0] - 2024/02/01

* `await StoreTester.dispatchAndWait(action)` dispatches an action, and then waits until it
finishes. This is the same as
doing: `storeTester.dispatch(action); await storeTester.wait(action);`.

# [21.0.2] - 2023/11/16

* Flutter 3.16.0 compatible.
Expand Down
73 changes: 42 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1256,9 +1256,15 @@ TestInfo<AppState> info = await storeTester.wait(SaveNameAction);
expect(info.state.name, "Mark");
```

or

```
TestInfo<AppState> info = storeTester.dispatchAndWait(SaveNameAction("Mark"));
expect(info.state.name, "Mark");
```

The variable `info` above will contain information about after the action reducer finishes
executing,
**no matter if the reducer is sync or async**.
executing, **no matter if the reducer is sync or async**.

The `TestInfo` instance contains the following:

Expand Down Expand Up @@ -1303,62 +1309,67 @@ Let's see all the available methods of the `StoreTester`:
Runs until the exact given action is dispatched, and then waits until it finishes. Returns the
info after the action finishes. **Ignores other** actions.

6. `Future<TestInfo> waitAllGetLast(List<Type> actionTypes, {List<Type> ignore})`
6. `Future<TestInfo> dispatchAndWait(ReduxAction action)`

Dispatches the given action, then waits until it finishes. Returns the
info after the action finishes. **Ignores other** actions.

7. `Future<TestInfo> waitAllGetLast(List<Type> actionTypes, {List<Type> ignore})`

Runs until **all** given actions types are dispatched, **in order**. Waits until all of them are
finished. Returns the info after all actions finish. Will fail with an exception if an unexpected
action is seen, or if any of the expected actions are dispatched in the wrong order. To ignore
some actions, pass them to the `ignore` list.

7. `Future<TestInfo> waitAllUnorderedGetLast(List<Type> actionTypes, {List<Type> ignore})`
8. `Future<TestInfo> waitAllUnorderedGetLast(List<Type> actionTypes, {List<Type> ignore})`

Runs until **all** given actions types are dispatched, in **any order**. Waits until all of them
are finished. Returns the info after all actions finish. Will fail with an exception if an
unexpected action is seen. To ignore some actions, pass them to the `ignore` list.

8. `Future<TestInfoList> waitAll(List<Type> actionTypes, {List<Type> ignore})`
9. `Future<TestInfoList> waitAll(List<Type> actionTypes, {List<Type> ignore})`

The same as `waitAllGetLast`, but instead of returning just the last info, it returns a list with
the end info for each action. To ignore some actions, pass them to the `ignore` list.

9. `Future<TestInfoList> waitAllUnordered(List<Type> actionTypes, {List<Type> ignore})`
10. `Future<TestInfoList> waitAllUnordered(List<Type> actionTypes, {List<Type> ignore})`

The same as `waitAllUnorderedGetLast`, but instead of returning just the last info, it returns a
list with the end info for each action. To ignore some actions, pass them to the `ignore` list.
The same as `waitAllUnorderedGetLast`, but instead of returning just the last info, it returns a
list with the end info for each action. To ignore some actions, pass them to the `ignore` list.

10. `Future<TestInfoList<St>> waitCondition(StateCondition<St> condition, {bool testImmediately = true, bool ignoreIni = true})`
11. `Future<TestInfoList<St>> waitCondition(StateCondition<St> condition, {bool testImmediately = true, bool ignoreIni = true})`

Runs until the predicate function `condition` returns true. This function will receive each
testInfo, from where it can access the state, action, errors etc. When `testImmediately` is true (
the default), it will test the condition immediately when the method is called. If the condition is
true, the method will return immediately, without waiting for any actions to be dispatched.
When `testImmediately` is false, it will only test the condition once an action is dispatched. Only
END states will be received, unless you pass `ignoreIni` as false. Returns a list with all info
until the condition is met.
Runs until the predicate function `condition` returns true. This function will receive each
testInfo, from where it can access the state, action, errors etc. When `testImmediately` is
true (the default), it will test the condition immediately when the method is called. If the
condition is true, the method will return immediately, without waiting for any actions to be
dispatched. When `testImmediately` is false, it will only test the condition once an action is
dispatched. Only END states will be received, unless you pass `ignoreIni` as false. Returns a
list with all info until the condition is met.

11. `Future<TestInfo<St>> waitConditionGetLast(StateCondition<St> condition, {bool testImmediately = true, bool ignoreIni = true})`
12. `Future<TestInfo<St>> waitConditionGetLast(StateCondition<St> condition, {bool testImmediately = true, bool ignoreIni = true})`

Runs until the predicate function `condition` returns true. This function will receive each
testInfo, from where it can access the state, action, errors etc. When `testImmediately` is true (
the default), it will test the condition immediately when the method is called. If the condition is
true, the method will return immediately, without waiting for any actions to be dispatched.
When `testImmediately` is false, it will only test the condition once an action is dispatched. Only
END states will be received, unless you pass `ignoreIni` as false. Returns the info after the
condition is met.
Runs until the predicate function `condition` returns true. This function will receive each
testInfo, from where it can access the state, action, errors etc. When `testImmediately` is
true (the default), it will test the condition immediately when the method is called. If the
condition is true, the method will return immediately, without waiting for any actions to be
dispatched. When `testImmediately` is false, it will only test the condition once an action is
dispatched. Only END states will be received, unless you pass `ignoreIni` as false. Returns the
info after the condition is met.

12. `Future<TestInfoList<St>> waitUntilError({Object error, Object processedError})`
13. `Future<TestInfoList<St>> waitUntilError({Object error, Object processedError})`

Runs until after an action throws an error of this exact type, or this exact error (using
equals). You can also, instead, define `processedError`, which is the error after wrapped by the
action's `wrapError()` method. Returns a list with all info until the error condition is met.

13. `Future<TestInfo> waitUntilErrorGetLast({Object error, Object processedError})`
14. `Future<TestInfo> waitUntilErrorGetLast({Object error, Object processedError})`

Runs until after an action throws an error of this exact type, or this exact error (using
equals). You can also, instead, define `processedError`, which is the error after wrapped by the
action's `wrapError()` method. Returns the info after the condition is met.

14. `Future<TestInfo<St>> dispatchState(St state)`
15. `Future<TestInfo<St>> dispatchState(St state)`

Dispatches an action that changes the current state to the one provided by you. Then, runs until
that action is dispatched and finished (ignoring other actions). Returns the info after the
Expand All @@ -1378,10 +1389,10 @@ expect(storeTester.state.description, isEmpty);
storeTester.dispatch(IncrementAndGetDescriptionAction());
TestInfoList<AppState> infos = await storeTester.waitAll([
IncrementAndGetDescriptionAction,
BarrierAction,
IncrementAction,
BarrierAction,
IncrementAndGetDescriptionAction,
BarrierAction,
IncrementAction,
BarrierAction,
]);
// Modal barrier is turned on (first time BarrierAction is dispatched).
Expand Down
6 changes: 4 additions & 2 deletions lib/src/store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -340,17 +340,19 @@ class Store<St> {
bool get isShutdown => _shutdown;

/// Runs the action, applying its reducer, and possibly changing the store state.
/// Note: [dispatch] is of type [Dispatch].
/// The action may be sync or async. Note: [dispatch] is of type [Dispatch].
FutureOr<ActionStatus> dispatch(ReduxAction<St> action, {bool notify = true}) =>
_dispatch(action, notify: notify);

/// Runs the action, applying its reducer, and possibly changing the store state.
/// Note: [dispatchAsync] is of type [DispatchAsync].
/// Note: [dispatchAsync] is of type [DispatchAsync]. It returns `Future<ActionStatus>`,
/// which means you can `await` it.
Future<ActionStatus> dispatchAsync(ReduxAction<St> action, {bool notify = true}) =>
Future.value(_dispatch(action, notify: notify));

/// Runs the action, applying its reducer, and possibly changing the store state.
/// Note: [dispatchSync] is of type [DispatchSync].
/// If the action is async, it will throw a [StoreException].
ActionStatus dispatchSync(ReduxAction<St> action, {bool notify = true}) {
if (!_ifActionIsSync(action)) {
throw StoreException(
Expand Down
23 changes: 21 additions & 2 deletions lib/src/store_tester.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,25 @@ class StoreTester<St> {
Future<ActionStatus> dispatchAsync(ReduxAction<St> action, {bool notify = true}) =>
store.dispatchAsync(action, notify: notify);

/// Dispatches [action], and then waits until it finishes.
/// Returns the info after the action finishes. **Ignores other** actions.
///
/// Example use:
///
/// var action = MyAction();
/// await storeTester.dispatchAndWait(action);
///
/// Note, this is the same as doing:
///
/// var action = MyAction();
/// storeTester.dispatch(action);
/// await storeTester.wait(action);
///
FutureOr<TestInfo<St>> dispatchAndWait(ReduxAction<St> action) {
store.dispatch(action);
return waitUntilAction(action);
}

void defineState(St state) => _store.defineState(state);

/// Dispatches an action that changes the current state to the one provided by you.
Expand Down Expand Up @@ -840,8 +859,8 @@ class TestInfoList<St> {

Iterable<TestInfo<St>> where(
bool test(
TestInfo<St> element,
)) =>
TestInfo<St> element,
)) =>
_info.where(test);

Iterable<T> map<T>(T f(TestInfo<St> element)) => _info.map(f);
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: async_redux
description: Redux without the boilerplate, tailored for Flutter. Easy to learn, to use and test. Allows for both sync and async reducers.
version: 21.0.2
version: 21.1.0
homepage: https://github.com/marcglasberg/async_redux
topics:
- redux
Expand Down

0 comments on commit 79c60f2

Please sign in to comment.