Testing with Dart Redux Thunks
aprofromindia opened this issue · 1 comments
I have written the following code and am trying to test a redux thunk action in flutter. Unfortunately when I debug the code, I can see the thunkMiddleware doesn't intercept the action as expected (as the returned Function(store)
never gets triggered).
state.dart
@JsonSerialize()
class Pokemon {
final String name;
final String url;
Pokemon(this.name, this.url);
factory Pokemon.fromJson(Map<String, dynamic> json) =>
_$PokemonFromJson(json);
}
// state
@immutable
class PokemonsState {
final List<Pokemon> pokemons;
final bool isLoading;
final Exception ex;
const PokemonsState(
{this.pokemons = const [], this.isLoading = false, this.ex});
PokemonsState copyWith(
{List<Pokemon> pokemons, bool isLoading, Exception ex}) {
return PokemonsState(
pokemons: pokemons ?? this.pokemons,
isLoading: isLoading ?? this.isLoading,
ex: ex ?? this.ex);
}
}
// reducer
PokemonsState pokemonsState(PokemonsState state, action) {
switch (action.runtimeType) {
case FetchPokemons:
return state.copyWith(isLoading: true);
case AddPokemons:
if (action.error == null)
return state.copyWith(
pokemons: action.payload, isLoading: false, ex: null);
return state.copyWith(ex: action.error, isLoading: false);
}
return state;
}
// actions
class FetchPokemons {}
class AddPokemons {
final List<Pokemon> payload;
final Exception error;
AddPokemons({this.payload, this.error});
}
// thunks
loadPokemons(Client client) {
return (Store<AppState> store) async {
store.dispatch(FetchPokemons());
try {
var res = await client.get(pokemonUrl);
if (res.statusCode == HttpStatus.ok) {
final pokemons = jsonDecode(res.body)['results'];
store.dispatch(AddPokemons(
payload:
List<Pokemon>.from(pokemons.map((i) => Pokemon.fromJson(i)))));
} else {
throw HttpException(res.reasonPhrase);
}
} on Exception catch (e) {
store.dispatch(AddPokemons(error: e));
}
};
}
state_test.dart
class MockClient extends Mock implements Client{}
void main(){
Store<PokemonsState> store;
setUp(() {
store = Store(pokemonsState,
initialState: PokemonsState(), middleware: [thunkMiddleware]);
});
test('add Pokemons success should add a list of pokemons to the store',
() {
final client = MockClient();
when(client.get(argThat(isInstanceOf<String>()))).thenAnswer((_) async =>
Response(
'{"results": [{"name": "p1", "url": "u1"}, {"name": "p2", "url": "u2"}]}',
200));
store.dispatch(loadPokemons(client));
expect(store.state.pokemons.length, 2);
});
});
}
Any help in fixing the test would be most appreciated!
Thunk actions are asynchronous and therefore you won't immediately see the expected result in the state, but with a small delay. You might try a CallableThunkAction and then await MyCallableThunkAction().call(store)
instead of store.dispatch(...)
, but I haven't tried that. In case the thunk action dispatches more asynchronous actions, and you need to wait for them to be finished, that suggestion will surely not work.