Line data Source code
1 : import 'dart:async';
2 :
3 : import 'package:redfire/types.dart';
4 : import 'package:redux/redux.dart';
5 :
6 : import 'empty_reducer.dart';
7 :
8 : /// An extension of [Store] with no reducers that takes a [state] of type
9 : /// "T extends RedFireState".
10 : ///
11 : /// [state] can be externally updated so that the store emits the updated state.
12 : ///
13 : /// [FakeStore] also keeps a record of dispatched actions that can be queried.
14 : class FakeStore<T extends RedFireState> implements Store<T> {
15 1 : FakeStore(T state)
16 : : _state = state,
17 1 : _changeController = StreamController<T>.broadcast(),
18 2 : reducer = EmptyReducer<T>();
19 :
20 : /// TODO: figure out how to create a T and update with auth info
21 : // // Named constructor for creating an authenticated fake store that will
22 : // // allow tests to bypass the auth UI
23 : // FakeStore.authenticated()
24 : // : _state = ExampleAppState.init().copyWith.auth(
25 : // userData: AuthUserDataExamples.minimal,
26 : // step: AuthenticationEnum.waitingForInput),
27 : // _changeController = StreamController<T>.broadcast(),
28 : // reducer = EmptyReducer();
29 :
30 : // The list of dispatched actions that can be queried by a test.
31 : final _dispatched = <ReduxAction>[];
32 3 : List<ReduxAction> get dispatched => List.unmodifiable(_dispatched);
33 :
34 : // A controller & stream for emiting each disptached action so tests can listen in.
35 : final _dispatchesStreamController = StreamController<ReduxAction>();
36 0 : Stream<ReduxAction> get dispatches => _dispatchesStreamController.stream;
37 :
38 : // A list of actions that make the dispatch function throw. When encountered
39 : // the action is removed from the list, meaning only the first attempted
40 : // dispatch will throw, unless the action is re-added after the dispatch.
41 : final _throwList = <ReduxAction>[];
42 0 : void throwOn(ReduxAction action) => _throwList.add(action);
43 :
44 : //
45 0 : void updateState(T state) {
46 0 : _state = state;
47 0 : _changeController.add(_state);
48 : }
49 :
50 : // We must override the reducer as a var in order to extend Store.
51 : @override
52 : T Function(T, dynamic) reducer;
53 :
54 : // We keep our own state so we can have a default value.
55 : T _state;
56 :
57 : // We need a StreamController to provide the onChange method.
58 : final StreamController<T> _changeController;
59 :
60 : // Override dispatch to just add the action to the list.
61 0 : @override
62 : dynamic dispatch(dynamic action) {
63 0 : if (action is! ReduxAction) throw Exception('action != ReduxAction');
64 0 : if (_throwList.contains(action)) {
65 0 : _throwList.remove(action); // don't leave FakeStore in a 'broken' state
66 0 : throw Exception('Encountered $action');
67 : }
68 0 : _dispatched.add(action);
69 0 : _dispatchesStreamController.add(action);
70 : }
71 :
72 0 : @override
73 0 : Stream<T> get onChange => _changeController.stream;
74 :
75 0 : @override
76 0 : T get state => _state;
77 :
78 0 : @override
79 0 : Future teardown() => _changeController.close();
80 : }
|