Flutter no longer shows any error message, I'm using android studio, but even if I start the program in console messages still won't appear. For example if mapping an object goes wrong, there will be no error shown in console, I'll have to find it my self
This is my main file:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
ErrorWidget.builder = (FlutterErrorDetails details) => Container(
color: Colors.white,
child: const Center(
child: Text('Error'),
),
);
await SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp],
);
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
} catch (e) {}
setupLocator();
await SentryFlutter.init((SentryFlutterOptions options) {
options.reportPackages = false;
options.enableOutOfMemoryTracking = true;
options.enableAppLifecycleBreadcrumbs = false;
options.anrEnabled = true;
options.debug = true;
options.dsn ='';
options.tracesSampleRate = 1.0;
}, appRunner: () => runApp(MyApp(route: route,)));
}
class MyApp extends StatelessWidget {
final String route;
final bool isLoggedIn;
MyApp({
required this.route,
required this.isLoggedIn,
});
#override
Widget build(BuildContext context) {
return GlobalBlocProviders(
isLoggedIn: isLoggedIn,
child: BlocListener<NotificationsBloc, NotificationsState>(
listener: (context, state) {
final route = state.route;
if (route == null) return;
locator<NavigationService>().navigateTo(route);
},
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: TylerTheme,
builder: (BuildContext context, Widget? childWidget) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
alwaysUse24HourFormat: true,
),
child: childWidget!,
);
},
initialRoute: route,
navigatorObservers: [
StackedService.routeObserver,
SentryNavigatorObserver()
],
navigatorKey: StackedService.navigatorKey,
onGenerateRoute: StackedRouter().onGenerateRoute,
),
),
);
}
}
Would be perfect if you have any suggestions. Thank you!
You just have to print the error via print method.
try {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
} catch (e) {
print("Catch Exception is $e");
}
Related
My longin screen has following functions :
loginUIController() {
return Consumer<ControllerLogin>(builder: (context, model, child) {
// if user are already login
if (model.userModel != null) {
return Center(
// show user details
child: alreadyLoggedInScreen(model),
);
} else {
// if user not login
return notLoginScreen(model);
}
});
}
notLoginScreen(ControllerLogin model) {
return Center(
child: Column(
children: [
Padding(
padding: EdgeInsets.all(10),
child: Image.asset('assets/googleback.jpg'),
),
GestureDetector(
onTap: () {
Provider.of<ControllerLogin>(context, listen: false).allowUserToLogin();
},
child: Image.asset(
'assets/google.png',
width: 250,
),
)
],
),
);
}
The builder is :
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: loginUIController(),
);
}
The notLoginScreen is displayed OK but every time I click Login button , the log shows a exception:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following TypeErrorImpl was thrown building Consumer<ControllerLogin>(dirty, dependencies:
[_InheritedProviderScope<ControllerLogin?>]):
Expected a value of type '(() => void)?', but got one of type '_Future<dynamic>'
The relevant error-causing widget was:
Consumer<ControllerLogin>
Consumer:file:///E:/CoderLife/Learning/flutter-learning/google_signin_authentication/lib/loginScreen.dart:17:12
The ControllerLogin is:
class ControllerLogin with ChangeNotifier {
FirebaseAuth auth = FirebaseAuth.instance;
var googleSignIn = GoogleSignIn();
GoogleSignInAccount? googleSignInAccount;
UserCredential? userCredential;
UserModel? userModel;
User? user;
allowUserToLogin() async {
if (kIsWeb) {
GoogleAuthProvider authProvider = GoogleAuthProvider();
try {
userCredential = await auth.signInWithPopup(authProvider);
user = userCredential!.user;
} catch (e) {
print(e);
}
} else {
googleSignInAccount = await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount!.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
try {
userCredential = await auth.signInWithCredential(credential);
user = userCredential!.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
print(e);
} else if (e.code == 'invalid-credential') {
print(e);
}
} catch (e) {
print(e);
}
}
}
if (user != null) {
userModel = new UserModel(
displayName: user!.displayName,
email: user!.email,
photoUrl: user!.photoURL);
print(userModel!.toJson());
notifyListeners();
}
}
allowUserToLogOut() async {
this.googleSignInAccount = await googleSignIn.signOut();
userModel = null;
notifyListeners();
}
}
The build function where Provider used is following:
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => ControllerLogin()),
],
child: MaterialApp(
title: 'Google Login',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FutureBuilder(
future: _initApp,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
print('error');
}
if (snapshot.connectionState == ConnectionState.done) {
return LoginScreen();
}
return CircularProgressIndicator();
},
),
),
);
}
I'v made onTap as a async function, but it didn't work.
It seems like I do sth wrong with Consumer stuff. Anybody can help me?
Dont use consumer use Provider like this
model =
Provider.of<ControllerLogin>(context, listen: false).allowUserToLogin();
I am using Hive with app_profile data model to store the app settings in local DB, and using riverpod to call HivedataStore (dependency injection).
The problem is that when I update the hive box of the local type, the app needs to be restarted to take effect, but if I update the Theme to Dark it work as it supposed to.
Here is my code:
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// await AppAssets.preloadSVGs();
final dataStore = HiveDataStore();
await dataStore.init();
await dataStore.createDefaultProfile(
appProfile: AppProfile(
onBoardingCompleted: false,
locale: 'en',
themeMode: ThemeModeCustomized.light,
));
runApp(ProviderScope(overrides: [
hiveDataStoreProvider.overrideWithValue(dataStore),
], child: const MyApp()));
}
hive_data_store.dart
class HiveDataStore {
static const profileBoxName = 'appProfile';
static const themeColor = 'themeColor';
Future<void> init() async {
await Hive.initFlutter();
Hive.registerAdapter<AppProfile>(AppProfileAdapter());
Hive.registerAdapter(ThemeModeCustomizedAdapter());
await Hive.openBox<AppProfile>(profileBoxName);
}
Future<void> createDefaultProfile({
required AppProfile appProfile,
}) async {
final box = Hive.box<AppProfile>(profileBoxName);
if (box.isEmpty) {
await box.put('0', appProfile);
} else {
print('box already have these Values : ${box.get(0)?.locale}');
}
}
Future<void> updateBox({
bool? onBoardingCompleted,
String? locale,
ThemeModeCustomized? themeMode,
}) async {
final box = Hive.box<AppProfile>(profileBoxName);
final userProfile = box.get('0');
final newProfile = userProfile!.copyWith(
onBoardingCompleted: onBoardingCompleted,
locale: locale,
themeMode: themeMode);
await box.put('0', newProfile);
}
AppProfile? appProfile() {
final box = Hive.box<AppProfile>(profileBoxName);
return box.get(0);
}
ValueListenable<Box<AppProfile>> appProfileListenable() {
return Hive.box<AppProfile>(profileBoxName).listenable();
}
}
final hiveDataStoreProvider = Provider<HiveDataStore>((ref) {
throw UnimplementedError();
});
myapp.dart
class MyApp extends ConsumerWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
final provider = ref.watch(hiveDataStoreProvider);
return ValueListenableBuilder(
valueListenable: provider.appProfileListenable(),
builder: (context, Box<AppProfile> box, __) {
print('myapp rebuilds listenablebuilder');
final appProfile = box.get('0');
return MaterialApp(
debugShowCheckedModeBanner: false,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppAssets.getLocals(appProfile!),
onGenerateTitle: (context) {
var t = AppLocalizations.of(context);
return t!.appTitle;
},
themeMode: AppAssets.themeModeGeter(appProfile),
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
initialRoute: '/',
routes: {
'/': (context) {
return const HomePage();
}
},
);
});
}
}
homepage.dart
class HomePage extends StatelessWidget {
const HomePage({super.key});
#override
Widget build(BuildContext context) {
print('homepage rebuils');
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.appTitle),
),
body: Center(
child: Consumer(builder: (context, WidgetRef ref, __) {
return Column(
children: [
TextButton(
onPressed: () {
ref.read(hiveDataStoreProvider).updateBox(
locale: 'ar', themeMode: ThemeModeCustomized.dark
);
},
child: const Text('العربية')),
TextButton(
onPressed: () {
ref.read(hiveDataStoreProvider).updateBox(
locale: 'en', themeMode: ThemeModeCustomized.light
);
},
child: const Text('English')),
],
);
}),
),
);
}
}
I think something need to be Changed in MyApp class, I use ValueListenableBuilder because I've seen in it in the Hive official package page.
Why the app need to be restarted to take effect for the locales? Unlike the app Theme which works perfectly.
Here my app_assets.dart code (just extra info):
class AppAssets {
static List<Locale> getLocals(AppProfile appProfile) {
switch (appProfile.locale) {
case 'ar':
return [const Locale('ar', '')];
case 'en':
return [const Locale('en', '')];
case '':
return AppLocalizations.supportedLocales;
default:
return AppLocalizations.supportedLocales;
}
}
static ThemeMode themeModeGeter(AppProfile? appProfile) {
switch (appProfile?.themeMode.name) {
case 'dark':
{
return ThemeMode.dark;
}
case 'light':
{
return ThemeMode.light;
}
case 'system':
{
return ThemeMode.system;
}
default:
ThemeMode.system;
}
return ThemeMode.system;
}
}
my mistake is that I was updating supportedLocales without updating locale in the MaterialApp Widget , I will keep the question though it might have a hint for others ..
supportedLocales: AppAssets.getLocals(appProfile),
locale: Locale('$appProfile.locale',''),
I'm trying to change localized words through my whole app. But it only changes when I restart my App or when I do subscription on lang changes. Is there any native way to change localized word without any subscription and have the same result as I get when restart the app?
As an example by what do I mean under subscription:
//sets_bloc.dart
void subscribeLocale(AppLanguagesCubit cubit) {
cubit.stream.listen((event) {
add(const OnSetCardsDownloading()); // refresh page
});
}
// home_view.dart
MultiBlocProvider(
providers: [
BlocProvider<SetsBloc>(
create: (_) => SetsBloc()
..subscribeLocale(BlocProvider.of<AppLanguagesCubit>(context))
),
//..//
],
child: SetsView(),
// main.dart
/** */
Future<void> main() async {
/** */
await SentryFlutter.init(
(options) {
options.dsn =
/** */
},
appRunner: () => runApp(
MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
/** */
ExtendedSecureStorage get storage => DiManager.getIt<ExtendedSecureStorage>();
#override
void initState() {
/** */
}
#override
void dispose() {
/** */
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
final FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
},
child: MultiBlocProvider(
providers: [
//** */
],
child: BlocBuilder<AppLanguagesCubit, AppLanguagesState>(
builder: (_, AppLanguagesState state) {
return OverlaySupport(
child: MaterialApp(
builder: (context, widget) {
if (widget != null) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1),
child: widget,
);
}
return widget ?? const SizedBox();
},
locale: state.status == ChangeLangStatus.success
? state.selectedLanguage?.locale
: const Locale('en'),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
debugShowCheckedModeBanner:
environmentConfig == EnvironmentConfig.dev ||
environmentConfig == EnvironmentConfig.qa,
title: getAppName(),
theme: ThemeData(
primarySwatch: Colors.orange,
unselectedWidgetColor:
LibraryColors.secondaryFont.withOpacity(0.5),
canvasColor: Colors.white,
primaryColorBrightness: Brightness.light,
),
home: BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
if (state is ***) {
loadLanguage(context);
}
},
builder: (_, AuthState state) {
if (state is ** ) {
return _spinner();
}
if (state is AuthorizationCompleted) {
if (**) {
return MultiBlocProvider(
providers:
/** */
child: CongratsView(),
);
}
if (Platform.isIOS) {
return const CupertinoScaffold(
body: HomeView(
initialTab: AppTab.home,
),
);
}
return const HomeView(
initialTab: AppTab.home,
);
}
if (state is AuthorizationError) {
return WelcomeView();
}
return WelcomeView();
},
),
),
);
}),
),
);
}
Future<void> loadLanguage(BuildContext context) async {
try {
final String? code = await storage.read(key: 'languageCode');
final Locale locale = getLocale(code, context);
await S.load(locale);
BlocProvider.of<AppLanguagesCubit>(context).init(locale);
if (code == null) {
await storage.write(
key: 'languageCode',
value: locale.languageCode,
);
}
CurrentLocaleDi()
..setLocale(locale)
..inject();
} catch (error) {
await ErrorReporter.writeLogs(error);
}
}
Locale getLocale(String? code, BuildContext context) {
if (code == null) {
return Localizations.localeOf(context);
}
return S.delegate.supportedLocales
.firstWhereOrNull((locale) => locale.languageCode == code) ??
S.delegate.supportedLocales.first;
}
Widget _spinner() {
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.dark,
child: Scaffold(
body: Center(
child: Image.asset(
LibraryAssets.appLogo,
width: 121,
height: 121,
),
),
),
);
}
String getAppName() {
const String appName = '***';
switch (environmentConfig) {
case EnvironmentConfig.dev:
return '$appName dev';
case EnvironmentConfig.qa:
return '$appName qa';
case EnvironmentConfig.prod:
return appName;
}
}
}
//app_languages_cubit.dart
//** //
class AppLanguagesCubit extends Cubit<AppLanguagesState> {
AppLanguagesCubit()
: super(
const AppLanguagesState.loading(),
);
ExtendedSecureStorage get _storage =>
DiManager.getIt<ExtendedSecureStorage>();
final List<AppLanguage> appLanguages = List<AppLanguage>.from(
S.delegate.supportedLocales.map(
(locale) => AppLanguage(
locale: locale,
code: locale.languageCode,
lang: targetLangs[locale.languageCode] ?? '',
langInNativeForm: locale.scriptCode ?? '',
),
),
);
void init(Locale locale) {
final AppLanguage selectedLanguage = AppLanguage(
code: locale.languageCode,
lang: targetLangs[locale.languageCode] ?? '',
locale: locale,
);
Intl.defaultLocale = selectedLanguage.locale.languageCode;
emit(
AppLanguagesState.success(
status: ChangeLangStatus.success,
selectedLanguage: selectedLanguage,
),
);
}
Future<void> changeLanguage(AppLanguage selectedLanguage) async {
try {
emit(
const AppLanguagesState.loading(),
);
Intl.defaultLocale = selectedLanguage.locale.languageCode;
await S.load(selectedLanguage.locale);
await _storage.write(
key: 'languageCode',
value: selectedLanguage.locale.languageCode,
);
CurrentLocaleDi()
..setLocale(selectedLanguage.locale)
..inject();
emit(
AppLanguagesState.success(
status: ChangeLangStatus.success,
selectedLanguage: selectedLanguage,
),
);
} catch (error) {
await ErrorReporter.writeLogs(error);
emit(
const AppLanguagesState.failure(),
);
}
}
}
//ln10.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'intl/messages_all.dart';
// **************************************************************************
// Generator: Flutter Intl IDE plugin
// Made by Localizely
// **************************************************************************
// ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars
// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each
// ignore_for_file: avoid_redundant_argument_values, avoid_escaping_inner_quotes
class S {
S();
static S? _current;
static S get current {
assert(_current != null,
'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.');
return _current!;
}
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
static Future<S> load(Locale locale) {
final name = (locale.countryCode?.isEmpty ?? false)
? locale.languageCode
: locale.toString();
final localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;
final instance = S();
S._current = instance;
return instance;
});
}
static S of(BuildContext context) {
final instance = S.maybeOf(context);
assert(instance != null,
'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?');
return instance!;
}
static S? maybeOf(BuildContext context) {
return Localizations.of<S>(context, S);
}
/// `**`
String get sliderText1 {
return Intl.message(
'some text'
name: 'sliderText1',
desc: '',
args: [],
);
}
//** */
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
const AppLocalizationDelegate();
List<Locale> get supportedLocales {
return const <Locale>[
Locale.fromSubtags(languageCode: 'en'),
Locale.fromSubtags(languageCode: 'de'),
Locale.fromSubtags(languageCode: 'es'),
Locale.fromSubtags(languageCode: 'fr'),
Locale.fromSubtags(languageCode: 'ja'),
Locale.fromSubtags(languageCode: 'pl'),
Locale.fromSubtags(languageCode: 'pt'),
Locale.fromSubtags(languageCode: 'ru'),
Locale.fromSubtags(languageCode: 'tr'),
Locale.fromSubtags(languageCode: 'uk'),
Locale.fromSubtags(languageCode: 'zh'),
];
}
#override
bool isSupported(Locale locale) => _isSupported(locale);
#override
Future<S> load(Locale locale) => S.load(locale);
#override
bool shouldReload(AppLocalizationDelegate old) => false;
bool _isSupported(Locale locale) {
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode) {
return true;
}
}
return false;
}
}
You can change the whole app without any subscription and set state. You have to use await WidgetsBinding.instance.performReassemble(); which is triggered the whole app with your updated value.This is the function
I added firestore and autologin with google to my app. So now when the user starts the app he get for a few seconds a grey screen. How can I create a loading screen, so that the user see that something happen instead of having a grey screen?
My code when starting the app looks like this:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FireBaseHandler handler = new FireBaseHandler();
GoogleSignIn _googleSignIn = GoogleSignIn();
print("Debug 1");
_googleSignIn.isSignedIn().then((logged) async => {
print("Debug 2" + logged.toString()),
if (!logged)
{
print("Debug 3"),
runApp(MyApp(screen: WelcomeScreen())),
}
else
{
print("Debug 4"),
_googleSignIn.signInSilently().then((user) => {
print(user.toString()),
handler
.is_user_registered(user.email.toString())
.then((value) => {
print("Debug 5"),
print(value.docs[0].data().toString()),
UserManager.userdata = value.docs[0].data(),
runApp(MyApp(screen: NavBar())),
})
})
}
});
}
You should move the async calls into the MyApp widget and use a FutureBuilder to wait for the results.
You then show the loading indicator when the data is null.
Check out this update to your code:
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
FireBaseHandler handler = new FireBaseHandler();
GoogleSignIn _googleSignIn = GoogleSignIn();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder<bool>(
future: _googleSignIn.isSignedIn(),
builder: (BuildContext context, AsyncSnapshot<bool> signInSnapshot) {
if (signInSnapshot.data == null) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} else {
bool isLoggedIn = signInSnapshot.data;
if (!isLoggedIn) {
return WelcomeScreen();
} else {
return FutureBuilder<GoogleSignInAccount>(
future: _googleSignIn.signInSilently(),
builder: (_,
AsyncSnapshot<GoogleSignInAccount>
signInSilentlySnapshot) {
if (signInSilentlySnapshot.data == null) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} else {
GoogleSignInAccount user = signInSilentlySnapshot.data;
return FutureBuilder(
future:
handler.is_user_registered(user.email.toString()),
builder: (_, isUserRegisteredSnapshot) {
if (isUserRegisteredSnapshot.data == null) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} else {
var value = isUserRegisteredSnapshot.data;
UserManager.userdata = value.docs[0].data();
return NavBar();
}
});
}
});
}
}
},
),
);
}
}
I am trying to Widget test my WelcomeScreen(). WelcomeScreen has a BlocProvider and a BlocBuilder. After I load WelcomeBloc() it checks with an if statement inside the builder to check if the state is WelcomeLoadSuccessState.
How do I find something under the if statement if the statement is true?
My Welcome screen:
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => WelcomeBloc(),
child: BlocBuilder<WelcomeBloc, WelcomeState>(
builder: (context, state) {
if (state is WelcomeLoadSuccessState) {
return Scaffold(
body: Container(
child: Column(
children: [
Wrap(
direction: Axis.vertical,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(8),
child: ShowUp(
delay: _delay + 200,
child: Text('Welcome user’, // <——— I want to find this one
)),
),
],
),
],
)),
);
}
// return LoadingWidget();
return Text('Something'); // <——— This one I can find
},
),
);
}
The test that I have now:
main() {
WelcomeBloc welcomeBloc;
WelcomeService welcomeService;
final Brand brand = Brand();
setUp(() {
setUpMocks();
welcomeService = localServices<WelcomeService>();
welcomeBloc = MockWelcomeBloc();
});
_createWidget(WidgetTester tester) async {
when(welcomeService.getBrand(id: '609a88d324a01928242d1ca9')).thenAnswer((realInvocation) => Future.value(brand));
welcomeBloc.add(WelcomeLoadRequestEvent(id: '609a88d324a01928242d1ca9'));
when(welcomeBloc.state).thenAnswer((_) => WelcomeLoadSuccessState(brand: brand));
print(welcomeBloc.state); //Correct State (WelcomeLoadSuccessState)
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: WelcomeScreen(),
)
);
await tester.pump();
}
testWidgets('Welcome Screen Test', (WidgetTester tester) async {
await _createWidget(tester);
await tester.pump();
//expect(find.textContaining('Welcome user'), findsOneWidget); //What I want
expect(find.text('Something'), findsOneWidget); //This works
});
tearDown(() {
welcomeBloc?.close();
});
}
Thank you for helping.
I solved it:
change:
create: (context) => WelcomeBloc()
to:
create: (context) => WelcomeBloc()..add(WelcomeLoadRequestEvent(id: '609a88d324a01928242d1ca9')),
and my test is now this:
main() {
WelcomeBloc welcomeBloc;
WelcomeService welcomeService;
final Brand brand = Brand();
setUp(() {
setUpMocks();
welcomeService = localServices<WelcomeService>();
welcomeBloc = MockWelcomeBloc();
});
_createWidget(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
title: 'Flutter Demo',
home: WelcomeScreen(),
));
await tester.pump(Duration(seconds: 10));
}
testWidgets('Welcome Screen Test', (WidgetTester tester) async {
when(welcomeService.getBrand(id: '609a88d324a01928242d1ca9'))
.thenAnswer((realInvocation) => Future.value(brand));
whenListen(
welcomeBloc,
Stream.fromIterable([
WelcomeLoadInProgressState(),
WelcomeLoadSuccessState(brand: brand),
]));
await _createWidget(tester);
await tester.pump(Duration(seconds: 5));
expect(find.textContaining('Welcome user'), findsOneWidget);
});
tearDown(() {
welcomeBloc?.close();
unRegister();
});
}
Edit to add:
For my other pages it was useful to separate the blocProvider and the blocBuilder. This way I was able to Mock my blocProvider with a MockMyBloc() and then give the screen in the child.
My real widgets:
MyWidgetMakeBlocProviders(
Widget build(context) {
return BlocProvider<MyBloc>(
create: (context) => MyBloc(),
child: MyScreen(),
);
}
)
MyScreen(
Widget build(context) {
return BlocBuilder<MyBloc, MyBlocState>(
builder: (context, state) {...}
);
}
)
My test:
testWidgets('', (tester) async {
whenListen(MockMyBloc, Stream.fromIterable([
InitState(),
LoadedState()
]));
await _createWidget(tester);
await tester.pump();
//expect()
});
_createWidget(tester) async {
await tester.pumpWidget(
MaterialApp(
title: '',
home: BlocProvider<MockMyBloc>(
create: (context) => MockMyBloc(),
child: MyScreen(),
)
)
);
await tester.pump();
}