waitAnyActionTypeFinishes method

  1. @visibleForTesting
Future<ReduxAction<St>> waitAnyActionTypeFinishes(
  1. List<Type> actionTypes, {
  2. int? timeoutMillis,
})

Returns a future which will complete when ANY action of the given types FINISHES dispatching. IMPORTANT: This method is different from the other similar methods, because it does NOT complete immediately if no action of the given types is in progress. Instead, it waits until an action of the given types finishes dispatching, even if they were not yet in progress when the method was called.

This method returns the action that completed the future, which you can use to check its status.

It's useful when the actions you are waiting for are not yet dispatched when you call this method. For example, suppose action StartAction starts a process that takes some time to run and then dispatches an action called MyFinalAction. You can then write:

dispatch(StartAction());
var action = await store.waitAnyActionTypeFinishes([MyFinalAction]);
expect(action.status.originalError, isA<UserException>());

You may also provide a timeoutMillis, which by default is 10 minutes. To disable the timeout, make it -1. If you want, you can modify defaultTimeoutMillis to change the default timeout.

Examples:

// Dispatches an actions that changes the state, then await for the state change:
expect(store.state.name, 'John')
dispatch(ChangeNameAction("Bill"));
var action = await store.waitCondition((state) => state.name == "Bill");
expect(action, isA<ChangeNameAction>());
expect(store.state.name, 'Bill');

// Dispatches actions and wait until no actions are in progress.
dispatch(BuyStock('IBM'));
dispatch(BuyStock('TSLA'));
await waitAllActions([]);
expect(state.stocks, ['IBM', 'TSLA']);

// Dispatches two actions in PARALLEL and wait for their TYPES:
expect(store.state.portfolio, ['TSLA']);
dispatch(BuyAction('IBM'));
dispatch(SellAction('TSLA'));
await store.waitAllActionTypes([BuyAction, SellAction]);
expect(store.state.portfolio, ['IBM']);

// Dispatches actions in PARALLEL and wait until no actions are in progress.
dispatch(BuyAction('IBM'));
dispatch(BuyAction('TSLA'));
await store.waitAllActions([]);
expect(store.state.portfolio.containsAll('IBM', 'TSLA'), isFalse);

// Dispatches two actions in PARALLEL and wait for them:
let action1 = BuyAction('IBM');
let action2 = SellAction('TSLA');
dispatch(action1);
dispatch(action2);
await store.waitAllActions([action1, action2]);
expect(store.state.portfolio.contains('IBM'), isTrue);
expect(store.state.portfolio.contains('TSLA'), isFalse);

// Dispatches two actions in SERIES and wait for them:
await dispatchAndWait(BuyAction('IBM'));
await dispatchAndWait(SellAction('TSLA'));
expect(store.state.portfolio.containsAll('IBM', 'TSLA'), isFalse);

// Wait until some action of a given type is dispatched.
dispatch(DoALotOfStuffAction());
var action = store.waitActionType(ChangeNameAction);
expect(action, isA<ChangeNameAction>());
expect(action.status.isCompleteOk, isTrue);
expect(store.state.name, 'Bill');

// Wait until some action of the given types is dispatched.
dispatch(ProcessStocksAction());
var action = store.waitAnyActionTypeFinishes([BuyAction, SellAction]);
expect(store.state.portfolio.contains('IBM'), isTrue);

See also: waitCondition - Waits until the state is in a given condition. waitActionCondition - Waits until the actions in progress meet a given condition. waitAllActions - Waits until the given actions are NOT in progress, or no actions are in progress. waitActionType - Waits until an action of a given type is NOT in progress. waitAllActionTypes - Waits until all actions of the given type are NOT in progress. waitAnyActionTypeFinishes - Waits until ANY action of the given types finish dispatching.

You should only use this method in tests.

Implementation

@visibleForTesting
Future<ReduxAction<St>> waitAnyActionTypeFinishes(
  List<Type> actionTypes, {
  int? timeoutMillis,
}) async {
  var (_, triggerAction) = await this.waitActionCondition(
    completedErrorMessage: "Assertion error",
    timeoutMillis: timeoutMillis,
    //
    (actionsInProgress, triggerAction) {
      //
      // If the triggerAction is one of the actionTypes,
      if ((triggerAction != null) && actionTypes.contains(triggerAction.runtimeType)) {
        // If the actions in progress do not contain the triggerAction, then the triggerAction has finished.
        // Otherwise, the triggerAction has just been dispatched, which is not what we want.
        bool isFinished = !actionsInProgress.contains(triggerAction);
        return isFinished;
      }
      return false;
    },
  );

  // Always non-null, because the condition is only met when an action finishes.
  return triggerAction!;
}