modular
modular copied to clipboard
Bug: Recover injection: IGetCurrentUserUseCase<Exception>
Describe the bug I am migrating from Modular 5.0 to Modular 6.0 and I'm encountering the following problem: I need to retrieve a composite class that can be injected according to its definition. Here's a test example of my use case. The injection is not being found.
To Reproduce
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:flutter_test/flutter_test.dart';
abstract class IGetCurrentUserUseCase<T> {
T call();
}
class GetCurrentUserUseCase implements IGetCurrentUserUseCase<Exception> {
@override
Exception call() {
throw UnimplementedError();
}
}
abstract class IListenCurrentUserChangesUseCase {
Stream<String> call();
}
class ListenCurrentUserChangesUseCase
implements IListenCurrentUserChangesUseCase {
@override
Stream<String> call() {
return Stream.fromIterable(['Bwolf', 'Deivao', 'Jacob']);
}
}
class DrawerViewModel {
final IGetCurrentUserUseCase<Exception> _getCurrentUserUsecase;
final IListenCurrentUserChangesUseCase _listenCurrentUserChangesUsecase;
const DrawerViewModel(
this._getCurrentUserUsecase,
this._listenCurrentUserChangesUsecase,
);
Exception get currentUser => _getCurrentUserUsecase();
Stream<String> get currentUserStream => _listenCurrentUserChangesUsecase();
}
void main() {
testWidgets('Test Inner Inject', (tester) async {
final modularApp = ModularApp(
module: CustomModule(),
child: const AppWidget(),
);
await tester.pumpWidget(modularApp);
await tester.pump();
expect(Modular.get<IGetCurrentUserUseCase<Exception>>(), isNotNull);
expect(Modular.get<IListenCurrentUserChangesUseCase>(), isNotNull);
expect(Modular.get<DrawerViewModel>(), isNotNull);
});
}
///MOCKS
class CustomModule extends Module {
@override
void binds(Injector i) {
i.addLazySingleton<IGetCurrentUserUseCase>(GetCurrentUserUseCase.new);
i.addLazySingleton<IListenCurrentUserChangesUseCase>(
ListenCurrentUserChangesUseCase.new,
);
i.addInstance<DrawerViewModel>(DrawerViewModel(
i.get<IGetCurrentUserUseCase<Exception>>(),
i.get<IListenCurrentUserChangesUseCase>(),
));
}
@override
void routes(RouteManager r) {
r.child('/', child: (__) => Container());
}
}
class AppWidget extends StatelessWidget {
const AppWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: Modular.routeInformationParser,
routerDelegate: Modular.routerDelegate,
);
}
}
Screenshots
Generic Type diff. IGetCurrentUserUseCase<Exception> != IGetCurrentUserUseCase
In Modular 6 the Type work as Key and must be a same aways.
Hi @jacobaraujo7 even if we specify the generic type the issue still persist. The same problem occurs with exported bindings.
@jacobaraujo7 the usecase with exported bindings
import 'package:flutter_modular/flutter_modular.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
abstract class IGetCurrentUserUseCase<T> {
T call();
}
class GetCurrentUserUseCase implements IGetCurrentUserUseCase<String> {
final IAuthService _authService;
GetCurrentUserUseCase(this._authService);
@override
String call() {
return _authService.getUser();
}
}
abstract class IListenCurrentUserChangesUseCase {
Stream<String> call();
}
class ListenCurrentUserChangesUseCase
implements IListenCurrentUserChangesUseCase {
@override
Stream<String> call() {
return Stream.fromIterable(['Bwolf', 'Deivao', 'Jacob']);
}
}
abstract interface class IAuthService {
String getUser();
}
class AuthService implements IAuthService {
@override
String getUser() => 'Teste';
}
class DrawerViewModel {
final IGetCurrentUserUseCase<String> _getCurrentUserUsecase;
final IListenCurrentUserChangesUseCase _listenCurrentUserChangesUsecase;
const DrawerViewModel(
this._getCurrentUserUsecase,
this._listenCurrentUserChangesUsecase,
);
String get currentUser => _getCurrentUserUsecase();
Stream<String> get currentUserStream => _listenCurrentUserChangesUsecase();
}
void main() {
testWidgets('Test Inner Inject', (tester) async {
final modularApp = ModularApp(
module: CustomModule(),
child: const AppWidget(),
);
await tester.pumpWidget(modularApp);
await tester.pump();
expect(Modular.get<IGetCurrentUserUseCase<String>>(), isNotNull);
expect(Modular.get<IListenCurrentUserChangesUseCase>(), isNotNull);
expect(Modular.get<DrawerViewModel>(), isNotNull);
});
}
///MOCKS
class CustomModuleWithExports extends Module {
@override
void exportedBinds(Injector i) {
i.addLazySingleton<IAuthService>(AuthService.new);
}
}
///MOCKS
class CustomModule extends Module {
@override
List<Module> get imports => [
CustomModuleWithExports(),
];
@override
void binds(Injector i) {
i.addLazySingleton<IGetCurrentUserUseCase<String>>(
GetCurrentUserUseCase.new);
i.addLazySingleton<IListenCurrentUserChangesUseCase>(
ListenCurrentUserChangesUseCase.new,
);
i.addInstance<DrawerViewModel>(
DrawerViewModel(
i.get<IGetCurrentUserUseCase<String>>(),
i.get<IListenCurrentUserChangesUseCase>(),
),
);
}
@override
void routes(RouteManager r) {
r.child('/', child: (__) => Container());
}
}
class AppWidget extends StatelessWidget {
const AppWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: Modular.routeInformationParser,
routerDelegate: Modular.routerDelegate,
);
}
}
My test Works with generic
@jacobaraujo7 with generics indeed worked and now we're stuck with the exportedBindings issue.
@BenevidesLecontes https://github.com/Flutterando/modular/pull/884