How to display facets with count with Algolia - flutter

I'm trying to get the list of facet that I've configured as describe here. I use the new official Algolia package along with the unofficial for settings. I thought that use the official package would change the response. Despite in the console browser, every thing is display as attended the searchResponse.facets is always empty.
Check the code below.
import 'dart:async';
import 'dart:io';
import 'package:algolia/algolia.dart';
import 'package:algolia_helper_flutter/algolia_helper_flutter.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:masterecommerce/src/constants/app_sizes.dart';
import 'package:masterecommerce/src/exceptions/app_exception.dart';
import 'package:masterecommerce/src/features/menu/presentation/search_header.dart';
import 'package:masterecommerce/src/features/products/domain/algolia_output.dart';
import 'package:masterecommerce/src/features/products/domain/algolia_params.dart';
import '../constants/credentials.dart';
import '../features/products/domain/product.dart';
import 'firestore_service.dart';
final searchResponseProvider = StateProvider.autoDispose<SearchResponse>((ref) {
return SearchResponse({});
});
final searchStateProvider = StateProvider.autoDispose<SearchState>((ref) {
return const SearchState(indexName: kIndexName);
});
final algoliaInputProvider = StateProvider.autoDispose<AlgoliaInput>((ref) {
return const AlgoliaInput();
});
final algoliaControllerProvider = StateNotifierProvider.autoDispose<
AlgoliaController, AsyncValue<List<Product>>>((ref) {
return AlgoliaController(
ref: ref, algoliaInput: ref.watch(algoliaInputProvider));
});
final algoliaControllerSearchProvider = StateNotifierProvider.autoDispose<
AlgoliaController, AsyncValue<List<Product>>>((ref) {
return AlgoliaController(
ref: ref,
algoliaInput: AlgoliaInput(
query: ref.watch(currentQuerySearchProvider), hitsPerPage: 3));
});
class AlgoliaController extends StateNotifier<AsyncValue<List<Product>>> {
StreamSubscription? subResponses;
StreamSubscription? subSearchState;
late HitsSearcher searcher;
late Algolia algoliaForSettings;
final Ref ref;
final AlgoliaInput algoliaInput;
AlgoliaController({required this.ref, required this.algoliaInput})
: super(const AsyncLoading()) {
algoliaForSettings = const Algolia.init(
applicationId: algoliaKeyAppId, apiKey: algoliaKeyCustom);
searcher = HitsSearcher(
applicationID: algoliaKeyAppId,
apiKey: algoliaKeyCustom,
indexName: kIndexName,
);
subResponses = searcher.responses.handleError((onError) {
print(onError);
state = AsyncError(onError);
}).listen((searchResponse) {
print(searchResponse.facets);
print(searchResponse.raw["facets"]);
ref.read(searchResponseProvider.state).update((state) => searchResponse);
final products = searchResponse.hits
.map((e) => Product.fromMapAlgolia(e.cast()))
.toList();
if (mounted) {
state = AsyncValue<List<Product>>.data(products);
}
});
subSearchState = searcher.state.handleError((onError) {
print(onError);
state = AsyncError(onError);
}).listen((searchState) {
ref.read(searchStateProvider.state).update((state) => searchState);
});
_newAlgoliaState(algoliaInput: algoliaInput);
}
#override
void dispose() {
searcher.dispose();
subResponses?.cancel();
subSearchState?.cancel();
super.dispose();
}
Future<void> _newAlgoliaState({required AlgoliaInput algoliaInput}) async {
state = const AsyncLoading();
final algoliaOutput = algoliaInput.toAlgoliaOutput();
await _setAlgoliaRanking(algoliaOutput: algoliaOutput);
if (!mounted) {
return;
}
searcher.connectFilterState(algoliaOutput.filterState);
searcher.applyState((state) => algoliaOutput.toSearchState());
}
Future<void> _setAlgoliaRanking(
{required AlgoliaOutput algoliaOutput}) async {
AlgoliaIndexReference algoliaIndexReference =
algoliaForSettings.instance.index("products");
final ranking = algoliaOutput.ranking;
if (ranking != null && ranking.isNotEmpty) {
AlgoliaTask algoliaTask =
await algoliaIndexReference.settings.setRanking([
...ranking,
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom",
]).setSettings();
await algoliaTask
.waitTask()
.timeout(const Duration(seconds: timeOutSecond))
.catchError((onError) {
if (onError is SocketException) {
throw const AppException.noInternet();
} else if (onError is TimeoutException) {
throw const AppException.timeOut();
} else {
throw const AppException.unknown();
}
});
}
final customRanking = algoliaOutput.customRanking;
if (customRanking != null && customRanking.isNotEmpty) {
final AlgoliaTask algoliaTask = await algoliaIndexReference.settings
.setCustomRanking(customRanking)
.setSettings();
await algoliaTask
.waitTask()
.timeout(const Duration(seconds: timeOutSecond))
.catchError((onError) {
if (onError is SocketException) {
throw const AppException.noInternet();
} else if (onError is TimeoutException) {
throw const AppException.timeOut();
} else {
throw const AppException.unknown();
}
});
}
}
}

As said here the searchState.facet need to be set.

Related

"The named parameter 'channelId' is required, but there's no corresponding argument." Flutter error how to solve?

I tried to built video call using agora 5. But "RtcRemoteView.SurfaceView" show some error.I couldn't understand what's the reason for this.
error
imports
import 'package:agora_rtc_engine/rtc_local_view.dart' as RtcLocalView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView;
code
class VideoCall extends StatefulWidget {
final String channelName;
final ClientRole role;
const VideoCall({Key? key, required this.channelName, required this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}
class _VideoCallState extends State<VideoCall> {
final _users = <int>[];
final _infoStrings = <String>[];
bool muted = false;
RtcEngine? _engine;
#override
void dispose() {
// clear users
_users.clear();
// destroy sdk
_engine?.leaveChannel();
_engine?.destroy();
super.dispose();
}
#override
void initState() {
super.initState();
// initialize agora sdk
initialize();
}
Future<void> initialize() async {
if (APP_ID.isEmpty) {
setState(() {
_infoStrings.add(
'APP_ID missing, please provide your APP_ID in settings.dart',
);
_infoStrings.add('Agora Engine is not starting');
});
return;
}
await _initAgoraRtcEngine();
_addAgoraEventHandlers();
await _engine?.enableWebSdkInteroperability(true);
VideoEncoderConfiguration configuration = VideoEncoderConfiguration();
configuration.dimensions = const VideoDimensions(); //(1920,1080)
await _engine?.setVideoEncoderConfiguration(configuration);
await _engine?.joinChannel(Token, widget.channelName, null!, 0);
}
Future<void> _initAgoraRtcEngine() async {
_engine = await RtcEngine.create(APP_ID);
await _engine?.enableVideo();
await _engine?.setChannelProfile(ChannelProfile.LiveBroadcasting);
await _engine?.setClientRole(widget.role);
}
void _addAgoraEventHandlers() {
_engine?.setEventHandler(RtcEngineEventHandler(error: (code) {
setState(() {
final info = 'onError: $code';
_infoStrings.add(info);
});
}, joinChannelSuccess: (channel, uid, elapsed) {
setState(() {
final info = 'onJoinChannel: $channel, uid: $uid';
_infoStrings.add(info);
});
}, leaveChannel: (stats) {
setState(() {
_infoStrings.add('onLeaveChannel');
_users.clear();
});
}, userJoined: (uid, elapsed) {
setState(() {
final info = 'userJoined: $uid';
_infoStrings.add(info);
_users.add(uid);
});
}, userOffline: (uid, elapsed) {
setState(() {
final info = 'userOffline: $uid';
_infoStrings.add(info);
_users.remove(uid);
});
}, firstRemoteVideoFrame: (uid, width, height, elapsed) {
setState(() {
final info = 'firstRemoteVideo: $uid ${width}x $height';
_infoStrings.add(info);
});
}));
}
List<Widget> _getRenderViews() {
final List<StatefulWidget> list = [];
if (widget.role == ClientRole.Broadcaster) {
list.add(RtcLocalView.SurfaceView());
}
_users.forEach((int uid) => list.add(RtcRemoteView.SurfaceView(uid: uid)));
return list;
}
add(RtcLocalView.SurfaceView());
}
_users.forEach((int uid) => list.add(RtcRemoteView.SurfaceView(uid: uid)));
return list;
}
pubspec.yaml file packages
How to solve this "The named parameter 'channelId' is required, but there's no corresponding argument. (Documentation) Try adding the required argument" error?
You just need to provide channelid to SurfaceView see the example in the official package site

Hive not updating field values

I have a user box where I store some data about the user.
In the main.dart file, I am registering and opening the UserDBAdapter
void main() async {
await Hive.initFlutter();
Hive.registerAdapter(UserDBAdapter());
await Hive.openBox<UserDB>('users');
return runApp(
MyApp(),
);
}
In my Bloc, I have a function which logins the user and then saves true in the isLoggedIn field of the user
class UserBloc extends Bloc<UserEvent, UserState> {
UserDB user = UserDB();
final usersBox = Hive.box<UserDB>('users');
UserRepository userRepository;
UserBloc(this.userRepository) : super(UserInitial()) {
createUser();
verifyUser();
loginUser();
logoutUser();
usersBox.put('user', user);
}
Future<void> loginUser() async {
return on<LoginUser>((event, emit) async {
emit(UserLoading());
await Future.delayed(const Duration(milliseconds: 500));
try {
final result = await userRepository.login(
event.email,
event.password,
);
if (result['success'] == false) {
emit(UserError(result['message']));
} else {
emit(
UserLoggedIn(),
);
user.isLoggedIn = true; // I set it to true here
user.token = result['token'];
user.save(); // Then I save it here. which means the new changes is persisted in the local storage
}
} catch (error) {
emit(
UserError(
error.toString(),
),
);
}
});
}
But my point is that, when I try hot reloading the app, it sends me to the login screen instead of the HomeScreen()
#override
void initState() {
if (Hive.box<UserDB>('users').get('user') == null) {
print('empty'); // This does not print, that means I have a user in the local storage
Hive.box<UserDB>('users').put(
'user',
UserDB(isVerified: false, isLoggedIn: false),
);
}
super.initState();
}
#override
Widget build(BuildContext context) {
final userDB = Hive.box<UserDB>('users').get('user')!;
print(userDB.isLoggedIn); // Here prints false instead of true
if (userDB.isLoggedIn) {
return const NavigationScreen();
} else if (userDB.isVerified && !userDB.isLoggedIn) {
return AnimatedSplashScreen(
splash: const SplashScreen(),
duration: 4000,
nextScreen: const LoginSignUpSwitch(),
);
} else {
return AnimatedSplashScreen(
splash: const SplashScreen(),
duration: 4000,
nextScreen: const WelcomeScreen(),
);
}
}
Below is the UserDB class
import 'package:hive/hive.dart';
part 'user.g.dart';
#HiveType(typeId: 1)
class UserDB extends HiveObject {
UserDB({
this.name,
this.email,
this.isVerified = false,
this.isLoggedIn = false,
this.token,
});
// NAME (0)
#HiveField(0)
String? name;
//EMAIL(1)
#HiveField(1)
String? email;
//IS-VERIFIED(2)
#HiveField(2, defaultValue: false)
bool isVerified;
//IS-LOGGEDIN(3)
#HiveField(3, defaultValue: false)
bool isLoggedIn;
//TOKEN(4)
#HiveField(4)
String? token;
}
NB: I am printing the value of the isLoggedIn in the HomeScreen and it prints true
final userDB = Hive.box<UserDB>('users').get('user');
print(userDB!.isLoggedIn); // Prints true here

How to compose async action and StateNotifierProvider?

I have some stream source (from FlutterReactiveBle library) and reflect it to state managed by StateNotifier.
But I can't sure whether it is right way from the following source. I'm especially afraid of _setState invalidates connectionProvider. And it looks like a bit complicated.
How can I improve this?
It may not work because I wrote it just for illustration.
#freezed
class DeviceConnections with _$DeviceConnections {
const DeviceConnections._();
const factory DeviceConnections({
Map<String, StreamSubscription<void>> connectings,
MapEntry<String, StreamSubscription<void>>? connected,
}) = _DeviceConnections;
}
class SimpleStateNotifier<T> extends StateNotifier<T> {
SimpleStateNotifier(super.state);
void update(T newState) {
state = newState;
}
}
StateNotifierProvider<SimpleStateNotifier<T>, T> simpleStateNotifierProvider<T>(
T initialState,
) {
return StateNotifierProvider<SimpleStateNotifier<T>, T>((ref) {
return SimpleStateNotifier(initialState);
});
}
class DeviceConnector {
DeviceConnector({
required FlutterReactiveBle ble,
required DeviceConnections state,
required Function(DeviceConnections) setState,
required Iterable<String> deviceIds,
}) : _ble = ble,
_state = state,
_setState = setState,
_deviceIds = deviceIds;
final FlutterReactiveBle _ble;
final DeviceConnections _state;
final Function(DeviceConnections) _setState;
final Iterable<String> _deviceIds;
void connect() {
final subscriptions = <String, StreamSubscription<void>>{};
for (final id in _deviceIds) {
subscriptions[id] = _connectInterval(id).listen((event) {});
}
_setState(_state.copyWith(connectings: subscriptions));
}
void disconnect() {
for (final subscription in _state.connectings.values) {
subscription.cancel();
}
_state.connected?.value.cancel();
_setState(DeviceConnections());
}
Stream<void> _connectInterval(String id) async* {
while (true) {
final connection = _ble.connectToDevice(
id: id,
connectionTimeout: Duration(seconds: 10),
);
await for (final update in connection) {
switch (update.connectionState) {
case DeviceConnectionState.connected:
final subscription = _state.connectings[id];
if (subscription != null) {
final others =
_state.connectings.entries.where((x) => x.key != id).toList();
for (final connection in others) {
connection.value.cancel();
}
_setState(
DeviceConnections(connected: MapEntry(id, subscription)),
);
}
break;
default:
break;
}
}
}
}
}
final connectionStateProvider = simpleStateNotifierProvider(
DeviceConnections(),
);
final bleProvider = Provider((_) => FlutterReactiveBle());
class AnotherState extends StateNotifier<List<String>> {
AnotherState(super.state);
}
final anotherStateNotifierProvider = StateNotifierProvider<AnotherState, List<String>>((ref) {
return AnotherState([]);
});
final connectionProvider = Provider((ref) {
final ble = ref.watch(bleProvider);
final connectorState = ref.watch(connectionStateProvider);
final connectorNotifier = ref.watch(connectionStateProvider.notifier);
final deviceIds = ref.watch(anotherStateNotifierProvider);
final connector = DeviceConnector(
ble: ble,
deviceIds: deviceIds,
state: connectorState,
setState: connectorNotifier.update,
);
ref.onDispose(connector.disconnect);
return connector;
});

How to implement authentication in flutter using riverpod

I am trying to do a login using riverpod, the login must call an api but at the moment I am using a fake api I want that while the api is called I can show a loader to the user and if everything is correct navigate to home.
I have the following:
authentication_service.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:watch_movie_app/src/data/data_source/local/fake_data.dart';
import 'package:watch_movie_app/src/data/models/models.dart';
import 'package:watch_movie_app/src/domain/models/models.dart';
class AuthenticationService {
Future<Auth> login(User user) async {
await Future.delayed(const Duration(seconds: 2));
User isName = fakeUsers.firstWhere(
(element) => element.name == user.name,
orElse: () => emptyUser(),
);
User isPassword = fakeUsers.firstWhere(
(element) => element.password == user.password,
orElse: () => emptyUser(),
);
if (isName.name != '' && isPassword.password != '') {
return Auth(
message: 'Succes welcome user',
status: true,
aditionalData: getRandomString(15));
}
return Auth(message: 'Credenciales incorrectas', status: false);
}
}
auth_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:watch_movie_app/src/data/enums/enum_login_status.dart';
import 'package:watch_movie_app/src/domain/constants/constants.dart';
import 'package:watch_movie_app/src/domain/providers/app_providers.dart';
final userAuthProvider = StateProvider<Map<String, dynamic>>((_) => {
'signedIn': false,
'loaded': false,
'status': LoginStatus.initialize,
});
final saveUserTokenProvider = StateProvider.family<bool, String>((ref, token) {
final localStore = ref.read(localStoreProvider);
localStore.write(tokenKey, token);
return true;
});
final userTokenProvider = StateProvider<String>((ref) {
final localStore = ref.read(localStoreProvider);
return localStore.read(tokenKey);
});
login_controller.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:watch_movie_app/src/data/enums/enum_login_status.dart';
import 'package:watch_movie_app/src/data/models/models.dart';
import 'package:watch_movie_app/src/domain/models/models.dart';
import 'package:watch_movie_app/src/domain/providers/auth_provider.dart';
import 'package:watch_movie_app/src/domain/services/authentication_service.dart';
final authProvider = StateNotifierProvider((ref) => AuthNotifier(ref));
class AuthNotifier extends StateNotifier<Auth> {
final WidgetRef ref;
dynamic _authRepository;
AuthNotifier(this.ref) : super(Auth()) {
_authRepository = ref.read(authRepository);
}
Future<void> login(User user) async {
Map<String, dynamic> userAuthStatus = ref.read(userAuthProvider.state).state;
userAuthStatus = {...userAuthStatus, 'loaded': true};
final Auth loginResult = await _authRepository.login(user);
state = loginResult;
if (loginResult.status) {
userAuthStatus = {'loaded': false, 'signedIn': true, 'status': LoginStatus.success};
} else {
userAuthStatus = {...userAuthStatus, 'loaded': false, 'status': LoginStatus.failed};
}
}
void clearUser() {
state = Auth();
}
}
auth.dart
class Auth {
final String message, aditionalData;
bool status;
Auth({this.message = '', this.status = false, this.aditionalData = ''});
}
versions packages:
flutter_riverpod: ^2.0.0-dev.0
Flutter 2.10.2
Dart 2.15.1 DevTools 2.9.2

how to mock firebase_messaging in flutter?

Hello im trying to mock firebase messaging to get token but when i try to test i get some error,can someone help me to solve this error. This error occur only in testing and not in my emulator or mobile phone. Here is my setupFirebaseAuthMocks. Thank you
my test
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
}
void main() {
setupFirebaseAuthMocks();
late ProviderContainer container;
group('AuthenticationControllerTest -', () {
setUpAll(() async {
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
registerThirdPartyServices();
});
tearDown(() {
unregisterThirdPartyServices();
//container.dispose();
});
});
Error
MissingPluginException(No implementation found for method Messaging#getToken on channel plugins.flutter.io/firebase_messaging)
here is the method im trying to call
Future<Result<Failure, bool>> registerUserFirebaseToken() async {
try {
log.i('Registering Firebase');
final fireBaseMessaging = FirebaseMessaging.instance;
final token = await fireBaseMessaging.getToken();
log.v('Firebase token: $token');
await api.post(
link: '${env.getValue(kAuthUrl)}users/auth/firebase',
body: {'token': token},
hasHeader: true,
);
return const Success(true);
} catch (e) {
return Error(Failure(message: 'Firebase registration went wrong, Please try again!', content: e.toString()));
}
}
For those having the same issue, there is an example of a Mock on the official firebase messaging Github
Depending on your Mockito's version, you may have to update this code a little bit.
Here is the Mock file I'm using with Mockito v5.3.2
// ignore_for_file: require_trailing_commas
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart';
import 'package:firebase_messaging_platform_interface/firebase_messaging_platform_interface.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
typedef Callback = Function(MethodCall call);
final MockFirebaseMessaging kMockMessagingPlatform = MockFirebaseMessaging();
Future<T> neverEndingFuture<T>() async {
// ignore: literal_only_boolean_expressions
while (true) {
await Future.delayed(const Duration(minutes: 5));
}
}
void setupFirebaseMessagingMocks() {
TestWidgetsFlutterBinding.ensureInitialized();
setupFirebaseCoreMocks();
// Mock Platform Interface Methods
// ignore: invalid_use_of_protected_member
when(kMockMessagingPlatform.delegateFor(app: anyNamed('app')))
.thenReturn(kMockMessagingPlatform);
// ignore: invalid_use_of_protected_member
when(kMockMessagingPlatform.setInitialValues(
isAutoInitEnabled: anyNamed('isAutoInitEnabled'),
)).thenReturn(kMockMessagingPlatform);
}
// Platform Interface Mock Classes
// FirebaseMessagingPlatform Mock
class MockFirebaseMessaging extends Mock
with MockPlatformInterfaceMixin
implements FirebaseMessagingPlatform {
MockFirebaseMessaging() {
TestFirebaseMessagingPlatform();
}
#override
bool get isAutoInitEnabled {
return super.noSuchMethod(Invocation.getter(#isAutoInitEnabled),
returnValue: true, returnValueForMissingStub: true) as bool;
}
#override
FirebaseMessagingPlatform delegateFor({FirebaseApp? app}) {
return super.noSuchMethod(
Invocation.method(#delegateFor, [], {#app: app}),
returnValue: TestFirebaseMessagingPlatform(),
returnValueForMissingStub: TestFirebaseMessagingPlatform(),
) as FirebaseMessagingPlatform;
}
#override
FirebaseMessagingPlatform setInitialValues({bool? isAutoInitEnabled}) {
return super.noSuchMethod(
Invocation.method(
#setInitialValues, [], {#isAutoInitEnabled: isAutoInitEnabled}),
returnValue: TestFirebaseMessagingPlatform(),
returnValueForMissingStub: TestFirebaseMessagingPlatform(),
) as FirebaseMessagingPlatform;
}
#override
Future<RemoteMessage?> getInitialMessage() {
return super.noSuchMethod(Invocation.method(#getInitialMessage, []),
returnValue: neverEndingFuture<RemoteMessage>(),
returnValueForMissingStub: neverEndingFuture<RemoteMessage>())
as Future<RemoteMessage?>;
}
#override
Future<void> deleteToken() {
return super.noSuchMethod(Invocation.method(#deleteToken, []),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as Future<void>;
}
#override
Future<String?> getAPNSToken() {
return super.noSuchMethod(Invocation.method(#getAPNSToken, []),
returnValue: Future<String>.value(''),
returnValueForMissingStub: Future<String>.value('')) as Future<String?>;
}
#override
Future<String> getToken({String? vapidKey}) {
return super.noSuchMethod(
Invocation.method(#getToken, [], {#vapidKey: vapidKey}),
returnValue: Future<String>.value(''),
returnValueForMissingStub: Future<String>.value('')) as Future<String>;
}
#override
Future<void> setAutoInitEnabled(bool? enabled) {
return super.noSuchMethod(Invocation.method(#setAutoInitEnabled, [enabled]),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as Future<void>;
}
#override
Stream<String> get onTokenRefresh {
return super.noSuchMethod(
Invocation.getter(#onTokenRefresh),
returnValue: const Stream<String>.empty(),
returnValueForMissingStub: const Stream<String>.empty(),
) as Stream<String>;
}
#override
Future<NotificationSettings> requestPermission(
{bool? alert = true,
bool? announcement = false,
bool? badge = true,
bool? carPlay = false,
bool? criticalAlert = false,
bool? provisional = false,
bool? sound = true}) {
return super.noSuchMethod(
Invocation.method(#requestPermission, [], {
#alert: alert,
#announcement: announcement,
#badge: badge,
#carPlay: carPlay,
#criticalAlert: criticalAlert,
#provisional: provisional,
#sound: sound
}),
returnValue: neverEndingFuture<NotificationSettings>(),
returnValueForMissingStub:
neverEndingFuture<NotificationSettings>())
as Future<NotificationSettings>;
}
#override
Future<void> subscribeToTopic(String? topic) {
return super.noSuchMethod(Invocation.method(#subscribeToTopic, [topic]),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as Future<void>;
}
#override
Future<void> unsubscribeFromTopic(String? topic) {
return super.noSuchMethod(Invocation.method(#unsubscribeFromTopic, [topic]),
returnValue: Future<void>.value(),
returnValueForMissingStub: Future<void>.value()) as Future<void>;
}
}
class TestFirebaseMessagingPlatform extends FirebaseMessagingPlatform {
TestFirebaseMessagingPlatform() : super();
}
and here is the unit test itself
void main() {
setupFirebaseMessagingMocks();
setUpAll(() async {
await Firebase.initializeApp();
FirebaseMessagingPlatform.instance = kMockMessagingPlatform;
});
test('An example of test', () {
//...
when(kMockMessagingPlatform.getToken(vapidKey: anyNamed('vapidKey')))
.thenAnswer(
(_) => Future.value('DEVICE_ID'),
);
//...
});
}