Not sure why I am not able to sign out.
When I click a button on the app bar, see 'sign out',
I click it,
system then asks me to confirm to sign out, I click it.
then I get an error and I am not signed out,
The expected result should be signing out without an error
CODE SNIP::
class _NotesViewState extends State<NotesView> {
void _popupMenuActionsPressed(value) async {
devtools.log('App bar $value was pressed');
switch (value) {
case MenuAction.logout:
final shouldLogout = await showLogOutDialog(context);
devtools.log('User logout');
if (shouldLogout) {
devtools.log('inside if statement');
await FirebaseAuth.instance.signOut();
Navigator.of(context)
.pushNamedAndRemoveUntil(homeRoute, (_) => false);
}
break;
default:
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Main UI'),
actions: [
PopupMenuButton<MenuAction>(
onSelected: (value) {
_popupMenuActionsPressed(value);
},
itemBuilder: (context) {
return [
const PopupMenuItem<MenuAction>(
value: MenuAction.logout,
child: Text('Sign out'),
)
];
},
)
],
),
body: const Text('Hello world'),
);
}
}
ERROR SNIP
User logout
[log] inside if statement
E/flutter (10193): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: [core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
E/flutter (10193): #0 MethodChannelFirebase.app
package:firebase_core_platform_interface/…/method_channel/method_channel_firebase.dart:193
E/flutter (10193): #1 Firebase.app
package:firebase_core/src/firebase.dart:56
E/flutter (10193): #2 FirebaseAuth.instance
package:firebase_auth/src/firebase_auth.dart:44
E/flutter (10193): #3 _NotesViewState._popupMenuActionsPressed
package:ijob_clone_app/main.dart:81
E/flutter (10193): <asynchronous suspension>
E/flutter (10193):
The error is not from the code, it is because you are not initializing firebase in your main function.
Edit your main function as follows:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(myApp());
}
Go to your main.dart file and in the main function, you have to initialize Firebase first before you can use any of its services:
void main() async {
await Firebase.initializeApp();
...
runApp(your_widget_here);
}
Related
I have a push notification manager class that is singleton where I listen for notifications from Firebase FCM and I handle them based on the logic and open specific screens.
I init with BuildContext that PushtNotificatonManager class inside HomePage that iS called from main.dart.
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
PushNotificationsManager().listen(context);
}
This is code from main.dart
Future<void> backgroundHandler(RemoteMessage message) async {
print('Handling a background message ${message.messageId}');
print('Content of message: ' + message.toString());
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
configureInjections();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(backgroundHandler);
runApp(SayApp());
}
This is part of the code from PushNotificationsManager class
#injectable
class PushNotificationsManager {
static final PushNotificationsManager _instance = PushNotificationsManager._internal();
factory PushNotificationsManager() {
return _instance;
}
PushNotificationsManager._internal();
Future<void> listen(BuildContext context) async {
if (Platform.isIOS) {
NotificationSettings settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
await _handleNotifications(context);
}
} else {
await _handleNotifications(context);
}
}
Future<void> _handleNotifications(BuildContext context) async {
// gives the message on which user taps and it opened the app from terminated state
FirebaseMessaging.instance.getInitialMessage().then((message) {
if (message != null) {
openNotification(message, context);
}
});
// foreground
FirebaseMessaging.onMessage.listen((message) {
if (message.notification != null) {
_showInAppNotification(message);
}
});
// When the app is in background but opened and user taps on the notification
FirebaseMessaging.onMessageOpenedApp.listen((message) {
openNotification(message, context);
});
}
Inside showInAppNotifications I am trying to display notifications as pop up and when the user clicks on it, I try to open a specific screen.
void _displayInAppNotifications(RemoteMessage message) {
FlutterRingtonePlayer.playNotification();
showOverlayNotification((context) {
return GestureDetector(
onTap: () {
openNotification(message, context);
OverlaySupportEntry.of(context)!.dismiss();
},
child: SafeArea(
child: Card(
child: ListTile(
leading: message.data[NotificationType.NOTIFICATION_TYPE] ==
NotificationType.PRIVATE_MESSAGE_1_ON_1
? Avatar(text: message.notification!.title!)
: SizedBox.fromSize(
size: const Size(40, 40),
child: ClipOval(
child: Container(
child: SvgPicture.asset(SvgIcons.sayAppWaveLogo),
))),
title:
Text(message.notification!.title!, overflow: TextOverflow.ellipsis, maxLines: 1),
subtitle: Text(
message.notification!.body!,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
trailing: IconButton(
icon: Icon(Icons.close),
onPressed: () {
OverlaySupportEntry.of(context)!.dismiss();
}),
),
),
),
);
}, duration: Duration(seconds: 4), position: NotificationPosition.top);
}
I have this method navigateToChannelDetailsPage that is called from the above method and here I am getting an exception.
Future<void> navigateToChannelDetailsPage(ChannelEntity channel, BuildContext context) async {
var cubit = BlocProvider.of<HomeCubit>(context);
var isUserChannelMember = await cubit.isCurrentUserChannelMember(channel);
if (!isUserChannelMember) return;
var isUserMutedPublic = await cubit.getIsUserMutedPublic(channel);
if (isUserMutedPublic) channel.isUserMutedPublic = isUserMutedPublic;
return PageNavigator.navigate(
context, ChannelDetailsPage(channel: channel, isFromAdminNotification: true))
.then((_) {
FocusManager.instance.primaryFocus?.unfocus();
cubit.updateChannelMemberChatDetailsDataOnChannelClosed(channel);
});
}
This is the exception:
E/flutter (25412): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter (25412): At this point the state of the widget's element tree is no longer stable.
E/flutter (25412): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter (25412): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:4241:9)
E/flutter (25412): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:4255:6)
E/flutter (25412): #2 Element.getElementForInheritedWidgetOfExactType (package:flutter/src/widgets/framework.dart:4286:12)
E/flutter (25412): #3 Provider._inheritedElementOf (package:provider/src/provider.dart:339:38)
E/flutter (25412): #4 Provider.of (package:provider/src/provider.dart:293:30)
E/flutter (25412): #5 BlocProvider.of (package:flutter_bloc/src/bloc_provider.dart:100:23)
E/flutter (25412): #6 PushNotificationsManager.navigateToChannelDetailsPage (package:say_app/presentation/notification/push_notifications_manager.dart:204:30)
E/flutter (25412): #7 PushNotificationsManager.openNotification (package:say_app/presentation/notification/push_notifications_manager.dart:180:9)
E/flutter (25412): <asynchronous suspension>
Any ideas?
You get that error because, by the time you wait for some things to finish the execution, you do something else on the app (go back one or few screens let's say) so your widget/screen gets disposed of and is no longer in the widget tree when you call PageNavigator.navigate(context, ...).
So to prevent that from happening, you can use the mounted flag to check if your StatefulWidget is still active, like:
if(mounted) PageNavigator.navigate(context, ...)
But in that case, the page will not get pushed if the widget is disposed of. So if you still want to push the new screen, no matter what happens in the meantime (even if that widget gets disposed of), you can have your global navigatorKey which you assign to the MaterialApp key property and use the context from navigatorKey while navigating, since it should always be usable (i.e. the MaterialApp should always be present in the widget tree). Solution example:
import 'package:flutter/material.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
home: const HomePage(),
);
}
}
So now you navigate like:
PageNavigator.navigate(navigatorKey.currentContext!, ...) // your use case
Navigator.of(navigatorKey.currentContext!).push(...) // the usual way using global navigatorKey
When I execute, (click on the "show Longitude and Latitude" button) I have two problems, a wrong position and an error:
**W/GooglePlayServicesUtil( 5181): com.example.geolocalisation_youtube requires the Google Play Store, but it is missing.
I/flutter ( 5181): 10681894.898369517
I/flutter ( 5181): long c.longitude
I/flutter ( 5181): 37.421998333333335
E/flutter ( 5181): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(IO_ERROR, A network error occurred trying to lookup the supplied coordinates (latitude: 37.421998, longitude: -122.084000)., null, null)
E/flutter ( 5181): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7)
E/flutter ( 5181): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:296:18)
E/flutter ( 5181): <asynchronous suspension>
E/flutter ( 5181): #2 MethodChannelGeocoding.placemarkFromCoordinates (package:geocoding_platform_interface/src/implementations/method_channel_geocoding.dart:56:24)
E/flutter ( 5181): <asynchronous suspension>
E/flutter ( 5181): #3 _MyHomePageState.build.<anonymous closure> (package:geolocalisation_youtube/main.dart:84:47)
E/flutter ( 5181): <asynchronous suspension>
**
Here’s the code:
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:geocoding/geocoding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future getPosition() async{
bool service= await Geolocator.isLocationServiceEnabled();
LocationPermission per= await Geolocator.checkPermission();
if (per==LocationPermission.denied){
per= await Geolocator.requestPermission();
if(per!=LocationPermission.denied){
}
}
print(service);
print("---------------");
print(per);
print("---------------");
if(!service ){
AwesomeDialog(
context: context,
title: "services",
body:
Text("service is enabled")
)..show();
}
}
Future <Position> getLatandLong() async{
return await Geolocator.getCurrentPosition().then((value) => value);
}
#override
void initState(){
getPosition();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Container(
height: 500,
width:400 ,
),
ElevatedButton(
onPressed: () async{
var c = await getLatandLong();
var distance= await Geolocator.distanceBetween(c.latitude, c.longitude, 28.033886, 1.659626);
print(distance);
print("long c.longitude ");
print(c.latitude);
List<Placemark> placemarks = await placemarkFromCoordinates(c.latitude, c.longitude);
print(placemarks[0].administrativeArea);
},
child: Text(" show Longitude and Latitude"))
],
),
);
}
}
I got this error on the latest version of Android Studio.
When moving to the login screen by clicking a button on the home screen this error was thrown. I couldn't understand why this occurred. As in the error message shown in the emulator I visited https://flutter.dev/docs/testing/errors but couldn't figure out much in there either.
class Body extends StatelessWidget {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
//this provide total height and width of screen
return Background(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"WELCOME TO BATCHMATE",
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: size.height * 0.07),
SvgPicture.asset(
'assets/icons/chat.svg',
height: size.height * 0.45,
),
FlatedButton(
text: 'LOGIN',
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
},
),
SizedBox(height: size.height * 0.01),
FlatedButton(
text: 'SIGN UP',
color: Colors.greenAccent,
textColor: Colors.black87,
press: () {},
),
],
),
),
);
}
}
This was the thrown error:
E/flutter ( 7445): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 3022 pos 18: '!navigator._debugLocked': is not true.
E/flutter ( 7445): #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39)
E/flutter ( 7445): #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5)
E/flutter ( 7445): #2 _RouteEntry.handlePush.<anonymous closure> (package:flutter/src/widgets/navigator.dart:3022:18)
E/flutter ( 7445): #3 TickerFuture.whenCompleteOrCancel.thunk (package:flutter/src/scheduler/ticker.dart:407:15)
E/flutter ( 7445): #4 _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter ( 7445): #5 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter ( 7445): <asynchronous suspension>
E/flutter ( 7445): #6 TickerFuture.whenCompleteOrCancel.thunk (package:flutter/src/scheduler/ticker.dart)
E/flutter ( 7445): <asynchronous suspension>
I handle routes this way, maybe it can help you fix your issue.
Its a little complicated at first but once you understand how it works, it saves a lot of time.
on each of your screens you add a static constant with whichever name you want, i usually call them screenId.
static const String screenId = 'screen_name';
create a file called routeGenerator where you are going to put all the routes that your app has.
import 'package:flutter/material.dart';
import 'main.dart';
import 'screens/chat_screen.dart';
import 'screens/login_screen.dart';
import 'screens/email_registration_screen.dart';
import 'screens/welcome_screen.dart';
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch (settings.name) {
case WelcomeScreen.screenId:
return MaterialPageRoute(
builder: (_) => WelcomeScreen(),
);
case EmailRegistrationScreen.screenId:
return MaterialPageRoute(
builder: (_) => EmailRegistrationScreen(),
);
case LoginScreen.screenId:
return MaterialPageRoute(
builder: (_) => LoginScreen(),
);
case ChatScreen.screenId:
return MaterialPageRoute(
builder: (_) => ChatScreen(),
);
default:
return _errorRoute();
}
}
static Route<dynamic> _errorRoute() {
return MaterialPageRoute(builder: (_) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('404'),
RaisedButton(
onPressed: () {
navigatorKey.currentState.pop();
},
child: Text('Regresar'),
),
],
),
),
);
});
}
}
then on your main.dart you add a gobal key and some parameters to your MaterialApp();
import 'route_generator.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: WelcomeScreen.screenId,
onGenerateRoute: RouteGenerator.generateRoute,
navigatorKey: navigatorKey,
);
}
}
And to navigate to the screen you can add the static constant of the screen to navigate to that particular screen.
LongButton(
text: 'Regístrate',
color: Colors.blueAccent,
callback: () {
Navigator.pushNamed(context, EmailRegistrationScreen.screenId);
},
),
I am trying to display a splash screen for a few seconds then trying to navigate it to the next screen but I am getting this error. Probably because of accessing context in iniState methods but I am also using async so I don't think there's should be any issue.
E/flutter ( 6663): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: NoSuchMethodError: The method 'findAncestorStateOfType' was called on null.
E/flutter ( 6663): Receiver: null
E/flutter ( 6663): Tried calling: findAncestorStateOfType<NavigatorState>()
E/flutter ( 6663): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
E/flutter ( 6663): #1 Navigator.of
package:flutter/…/widgets/navigator.dart:2185
import 'package:awsomeNotes/appUtilities/dimensions.dart';
import 'package:awsomeNotes/views/phoneAuthPage/phoneAuthPage.dart';
import 'package:flutter/material.dart';
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
nextPage() async {
await Future.delayed(Duration(seconds: 5));
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhoneAuthPage(),
),
);
}
#override
void initState() {
nextPage();
super.initState();
}
#override
Widget build(BuildContext context) {
Dimensions(context);
return Material(
child: Center(
child: Text(
"This is Splash Screen",
style: TextStyle(fontSize: Dimensions.boxHeight * 5),
),
),
);
}
}
I am navigating to the next page but with the error specified.
I have a test where I'm trying to observe the behaviour of the [Navigator] when the app navigates from contacts_footer.dart to create_and_edit_contact.dart (push) and back (pop). Using verify from the Mockito package, I can successfully verify that the push behaviour works however, verifying the pop behaviour fails. The function _navigateToBack works as expected and testing for widgets that appear only in the contacts_footer.dart is successful, but observing the pop behaviour fails.
contacts_footer.dart
class ContactsFooter extends StatelessWidget {
static const navigateToEditPage = Key('navigateEdit');
const ContactsFooter({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return BottomAppBar(
color: Color.fromRGBO(244, 244, 244, 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
Provider.of<Contacts>(context).setEditMode(true);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CreateAndEditContact()));
},
key: ContactsFooter.navigateToEditPage,
)
],
),
);
}
}
create_and_edit_contact.dart
class CreateAndEditContact extends StatefulWidget {
static const routeName = 'edit-contact';
static var editOrCreateDetails = Key('editOrCreate');
#override
_CreateAndEditContactState createState() => _CreateAndEditContactState();
}
class _CreateAndEditContactState extends State<CreateAndEditContact> {
...
Widget build(BuildContext context) {
_isEditMode = Provider.of<Contacts>(context).isEditMode;
...
return Scaffold (
..
RaisedButton(key: CreateAndEditContact.editOrCreateDetails,
onPressed: () {
....
if (_isEditMode) {
print(true);
Provider.of<Contacts>(context)
.updateContact(context,formData, _selectedContact.vUuid)
.then((data) {
Navigator.of(context).pop();
});
} else {
print(false);
Provider.of<Contacts>(context)
.createContact(context,formData)
.then((data) {
Navigator.of(context).pop();
}).catchError(
(error) => showDialog(
context: context,
builder: (context) => ErrorDialog(
error.toString(),
),
),
);
}
},
child: Text(
'Sumbit',
style: TextStyle(color: Colors.white),
),
color: Theme.of(context).accentColor,
),
)
}
}
test file .
group('EditPage navigation tests', () {
NavigatorObserver mockObserver;
setUp(() {
mockObserver = MockNavigatorObserver();
});
Future<Null> _buildMainPage(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Builder(
builder: (context) => Center(
child: MultiProvider(
providers: [
ChangeNotifierProvider<Contacts>(create: (_) => Contacts()),
],
child: Builder(
builder: (_) => MaterialApp(home: ContactsFooter(),
),
);,
),
),
),
/// This mocked observer will now receive all navigation events
/// that happen in our app.
navigatorObservers: <NavigatorObserver>[mockObserver],
));
/// The tester.pumpWidget() call above just built our app widget
/// and triggered the pushObserver method on the mockObserver once.
}
Future<Null> _navigateToDetailsPage(WidgetTester tester) async {
/// Tap the button which should navigate to the edit details page.
/// By calling tester.pumpAndSettle(), we ensure that all animations
/// have completed before we continue further.
await tester.tap(find.byKey(ContactsFooter.navigateToEditPage));
await tester.pumpAndSettle();
}
Future<Null> _navigateToBack(WidgetTester tester) async {
await tester.tap(find.byKey(CreateAndEditContact.editOrCreateDetails));
int num = await tester.pumpAndSettle();
print(num);
}
testWidgets(
'when tapping "navigate to edit details" button, should navigate to details page',
(WidgetTester tester) async {
await _buildMainPage(tester);
//CreateAndEditContact widget not present on screen as push event is not triggered yet
expect(find.byType(CreateAndEditContact), findsNothing);
//Trigger push event
await _navigateToDetailsPage(tester);
// By tapping the button, we should've now navigated to the edit details
// page. The didPush() method should've been called...
final Route pushedRoute =
verify(mockObserver.didPush(captureAny, any)).captured.single;
print(pushedRoute);
// there should be a CreateAndEditContact page present in the widget tree...
var createAndEdit = find.byType(CreateAndEditContact);
expect(createAndEdit, findsOneWidget);
await _navigateToBack(tester);
verify(mockObserver.didPop(any, any));
expect(find.byType(CreateAndEditContact), findsNothing);
expect(find.byKey(ContactsFooter.navigateToEditPage), findsWidgets);
});
}
All the expect statements execute correctly. However verify(mockObserver.didPop(any, any)); results in an exception as if [NavigatorObserver] did not recognize the pop behaviour.
>(RouteSettings("/", null), animation: AnimationController#1a3c6(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/)))
5
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
No matching calls. All calls: MockNavigatorObserver.navigator,
MockNavigatorObserver._navigator==NavigatorState#36772(tickers: tracking 1 ticker), [VERIFIED]
MockNavigatorObserver.didPush(MaterialPageRoute<dynamic>(RouteSettings("/", null), animation:
AnimationController#1a3c6(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))), null)
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
When the exception was thrown, this was the stack:
#0 fail (package:test_api/src/frontend/expect.dart:153:30)
#1 _VerifyCall._checkWith (package:mockito/src/mock.dart:648:7)
#2 _makeVerify.<anonymous closure> (package:mockito/src/mock.dart:935:18)
#3 main.<anonymous closure>.<anonymous closure> (file:///Users/calvin.gonsalves/Projects/Flutter/Dec23-2019/cmic_mobile_field/test/main_widget_test.dart:316:13)
<asynchronous suspension>
#4 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:124:25)
#5 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:696:19)
<asynchronous suspension>
#8 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:679:14)
#9 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1050:24)
#15 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1047:15)
#16 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:121:22)
#17 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:171:27)
<asynchronous suspension>
#18 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:242:15)
#23 Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:239:5)
#24 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:33)
#29 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:168:13)
#30 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:392:25)
#44 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:384:19)
#45 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:418:5)
#46 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
(elided 28 frames from class _FakeAsync, package dart:async, package dart:async-patch, and package stack_trace)
The test description was:
when tapping "navigate to edit details" button, should navigate to details page
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: when tapping "navigate to edit details" button, should navigate to details page
✖ EditPage navigation tests when tapping "navigate to edit details" button, should navigate to details page
I referred https://iirokrankka.com/2018/08/22/writing-widget-tests-for-navigation-events/
The issue seems to be caused by Navigator lacking context - usually provided by MaterialApp in this case. As you've mentioned in the comments, moving navigatorObservers inside MaterialApp solves the issue. Another workaround is to use navigatorKey to directly manage Navigator without obtaining it first from a BuildContext. See this similar Stack Overflow post on how you can utilize navigatorKey.