Why one of my state is not triggered during my test - flutter

I followed Reso code youtube to create a small weather app, but I used the latest bloc library and flutter_bloc 4.0 also.
Base App: https://www.youtube.com/watch?v=hTExlt1nJZI&list=PLB6lc7nQ1n4jCBkrirvVGr5b8rC95VAQ5&index=7
BLoc Test: https://www.youtube.com/watch?v=S6jFBiiP0Mc&list=PLB6lc7nQ1n4jCBkrirvVGr5b8rC95VAQ5&index=8
The first 2 tests are working. For example, the below one does not give me any error:
test(
'NEWER WAY BUT lONG-WINDED emits [WeatherLoading, WeatherLoaded] when successful',
() {
when(mockWeatherRepository.fetchWeather(any))
.thenAnswer((_) async => weather);
final bloc = WeatherBloc(mockWeatherRepository);
bloc.add(GetWeather('London'));
emitsExactly(bloc, [
WeatherInitial(),
WeatherLoading(),
WeatherLoaded(weather),
]);
});
For some reason, that test below does not trigger the WeatherInitial.
blocTest(
'emits [WeatherLoading, WeatherLoaded] when successful',
build: () async {
when(mockWeatherRepository.fetchWeather(any))
.thenAnswer((_) async => weather);
return WeatherBloc(mockWeatherRepository);
},
act: (bloc) => bloc.add(GetWeather('London')),
expect: [
WeatherInitial(),
WeatherLoading(),
WeatherLoaded(weather),
],
);
The error is:
ERROR: Expected: [
WeatherInitial:WeatherInitial,
WeatherLoading:WeatherLoading,
WeatherLoaded:WeatherLoaded
]
Actual: [WeatherLoading:WeatherLoading, WeatherLoaded:WeatherLoaded]
Which: was WeatherLoading:<WeatherLoading> instead of WeatherInitial:<WeatherInitial> at location [0]
Do you have any clue why?

This behaviour is correct according to the official bloc_test library:
skip is an optional int which can be used to skip any number of states.
The default value is 1 which skips the initialState of the bloc.
skip can be overridden to include the initialState by setting skip to 0.
So if you want to include your "InitialState" just ,set the "skip" value to 0 :
.
.
.
skip: 0,
expect: [
WeatherInitial(),
WeatherLoading(),
WeatherLoaded(weather),
],

Related

Flutter Bloc Test verify/running a function after get result

I try to test bloc (AuthBloc) which running "logout" when getLocalToken is failed and I get this error.
How can I verify/running logout after I get result ServerException on my bloctest.
Please Help.
Thanks before.
My Bloc :
on<AppStarted>((event, emit) async {
final token = await getLocalToken(const Params(needValidation: true));
token.fold(
(failure) {
logout(NoParams());
emit(AuthNotAuthenticated());
},
(auth) => emit(AuthAuthenticated()),
);
});
Here My Test Code :
blocTest<AuthBloc, AuthState>(
'should emit [AuthNotAuthenticated] when token / input is invalid',
build: () {
when(mockGetLocalToken(any))
.thenAnswer((_) async => Left(ServerFailure()));
return bloc;
},
act: (blc) => blc.add(AppStarted()),
expect: () { return <AuthState>[AuthNotAuthenticated()];},
);
Error :
00:03 +2 -1: AppStarted should emit [AuthNotAuthenticated] when token / input is invalid [E]
MissingStubError: 'call'
No stub was found which matches the arguments of this method call:
call(NoParams())
Add a stub for this method using Mockito's 'when' API, or generate the MockLogout mock with a MockSpec with 'returnNullOnMissingStub: true'
Expected: [AuthNotAuthenticated:AuthNotAuthenticated()]
Actual: []
Which: at location [0] is [] which shorter than expected
==== diff ========================================
[[-AuthNotAuthenticated()-]]
==== end diff ====================================

Flutter Cubit Testing States

Trying to write tests for a cubit in flutter. When I run my code, everything works fine, but the tests are causing me issues.
When I run this, I get an error:
> type 'Null' is not a subtype of type 'Future<Fact>'
> MockFactRepository.fetchFact
/test/fact_cubit_test.dart
group(
'Get Fact',
() {
const fact = Fact(text: 'This is a fact');
blocTest(
'emits [FactCubit.initial, .loading, .loaded] when successful',
build: () {
when(mockFactRepository.fetchFact()).thenAnswer((_) async => fact);
return FactCubit(mockFactRepository);
},
act: (FactCubit cubit) => cubit.getFact(),
expect: () => [
FactState.initial().runtimeType,
FactState.loading().runtimeType,
FactState.loaded(fact).runtimeType,
],
);
},
);

Flutter blocTest Missing type arguments for generic function 'blocTest<B extends BlocBase<State>, State>'

When following the bloc test documentation, I created the following blocTest;
blocTest('should do something',
build: () => SignInBloc(signIn: mockSignIn),
act: (bloc) => bloc.add(const OnEmailChanged(email: 'test')));
However I get the intellisense error;
Missing type arguments for generic function 'blocTest<B extends BlocBase<State>, State>'.
And the (bloc) provided in the add is of type Object?.
To fix the issue you have to tell the blocTest what types to expect.
blocTest<SignInBloc, SignInState>('should do something',
build: () => SignInBloc(signIn: mockSignIn),
act: (bloc) => bloc.add(const OnEmailChanged(email: 'test')));
});

Update a widget in mobile app on a new database record

I am developing an app using flutter.
The backend is in flask and the database is a nosql (mongodb).
I have a widget which shows users who have liked an article.
What I want to achieve is:
A) if user X likes an article that I am currently viewing I want to instantly see that (ie his avatar, name, doesn’t matter).
B) let’s say I am on another screen (ie settings), I want the same to happen in the background so when I go back to the article screen, to see the user that has liked the article (if that’s possible).
What I know so far is that I have to use a stream builder (flutter). This is fine, I understand how that works.
My question is how am I going to push the new server event/database record(user X likes article Y) to the app.
Should I use server sent events, websockets or there is another solution?
If sse and ws are the only solutions which one is preferable given that I’m using flask as my backend?
Almost all of the examples I have seen online are unfortunately using firebase (not all of us want to use firebase!) and none of the websocket examples mention anything about data we want to retrieve from a db.
Any reference to a helpful tutorial (no firebase!) would be very helpful.
I'm doing something similar for a chat app, i had to use flask-socketio to emit events from flask and socket_io_client: ^2.0.0-beta.4-nullsafety.0 on flutter along with flutter_bloc to handle my state. I'm using the beta flutter socket_io_client because my server is using socketio 4 which is not supported by the current stable version.
Flutter
#injectable
class SocketBloc extends Bloc<SocketEvent, SocketState> {
final Socket _socket;
SocketBloc(this._socket)
: super(SocketState.initial()) {
on<SocketEvent>((event, emit) async {
await event.map(
connecting: (value) async => await _mapConnectingToState(emit, value),
connected: (value) async => await _mapConnectToState(emit, value),
disconnected: (value) async => await _mapDisconnectToState(emit, value),
error: (value) async => await _mapErrorToState(emit, value),
connect: (value) async => await _mapSocketConnectToState(emit, value),
inquiries: (value) async => await _mapAddInquiriesToState(emit, value),
setActiveInquiry: (value) async =>
await _mapSetActiveInquiryToState(emit, value),
newChatMessage: (value) async =>
await _mapNewChatMessageToState(emit, value),
newMessage: (value) async => await _mapNewMessageToState(emit, value),
sendChat: (value) async => await _mapSendChatToState(emit, value),
uploadFiles: (value) async => await _mapUploadFilesToState(emit, value),
);
});
_setUpListeners();
}
void _setUpListeners() {
_socket.onConnecting((data) => add(const SocketEvent.connecting()));
_socket.onConnect((data) => add(const SocketEvent.connected()));
_socket.onConnectError((data) => add(const SocketEvent.error()));
_socket.onDisconnect((data) => add(const SocketEvent.disconnected()));
_socket.on(
Events.INQUIRIES.name,
(data) => add(SocketEvent.inquiries(data)),
);
_socket.on(
Events.NEW_CHAT.name,
(data) => add(SocketEvent.newChatMessage(data)),
);
_socket.on(
Events.NEW_MESSAGE.name,
(data) => add(SocketEvent.newMessage(data)),
);
}
Flask
#socketio.on(prefix)
def handle_new_message(data):
admin = get_admin()
if not admin:
raise Exception("Admin not configured")
# Get user by sid
db_user = User.objects.get(session=request.sid)
if not db_user:
raise Exception("No such client")
message = data.get('message')
if not message:
raise Exception("No message content")
message_id = data.get('message_id')
if not message_id:
raise Exception("No message ID")
db_message = Message.objects.get(pk=message_id)
if not db_message:
raise Exception("No such message")
# TODO - Affirm that sender is owner of message
chat = Chat(message=message,
message_id=message_id,
recipient=admin.uid,
sender=db_user.uid)
chat.save()
emit(SocketEvents.NEW_CHAT.name, JSONEncoder().encode(clear_cls(chat.to_mongo().to_dict())))
db_message.last_message = chat.message
db_message.save()
emit(SocketEvents.NEW_MESSAGE.name, JSONEncoder().encode(clear_cls(db_message.to_mongo().to_dict())))

Test bloc test with parameter failed

So, I have using this bloc_test library version bloc_test: ^5.0.0.
Previously I test bloc with this code and work fine
test(
'should emit [RegisterLoadingState,RegisterLoadedState] when RegisterWithPassword is successful',
() async {
setUpSuccessfulValidateRegister();
setUpSuccessfulRegister();
final expected = [
RegisterInitialState(),
RegisterLoadingState(),
RegisterLoadedState(account: customer),
];
expectLater(bloc, emitsInOrder(expected));
bloc.add(RegisterWithPasswordEvent(
name: nameTest,
email: emailTest,
password: passwordTest,
retypedPassword: retypedPasswordTest,
));
});
Currently I change it with using bloc_test package and the test failed
blocTest(
'should emit [RegisterLoadingState,RegisterLoadedState] when RegisterWithPassword is successful',
build: () async {
setUpSuccessfulValidateRegister();
setUpSuccessfulRegister();
return bloc;
},
act: (bloc) => bloc.add(RegisterWithPasswordEvent(
name: nameTest,
email: emailTest,
password: passwordTest,
retypedPassword: retypedPasswordTest,
)),
expect: [
RegisterLoadingState(),
RegisterLoadedState(account: customer),
],
);
Here is the error in test
Expected: [
RegisterLoadingState:RegisterLoadingState,
RegisterLoadedState:RegisterLoadedState
]
Actual: [
RegisterLoadingState:RegisterLoadingState,
RegisterLoadedState:RegisterLoadedState
]
Which: was RegisterLoadedState:<RegisterLoadedState> instead of RegisterLoadedState:<RegisterLoadedState> at location [1]
package:test_api expect
package:bloc_test/src/bloc_test.dart 124:25 blocTest.<fn>
the error gone if I removed the equatable in state with account parameter. Anyone know why this test works on the first code and failed with bloc_test packages?