Navigator.pop is never called while it actually was
Describe the bug
When I open a dialog with showDialog and I pop it, verify tells me it never called .pop while it did.
popping...
popped!
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
No matching calls. All calls: [VERIFIED] MockNavigator.canPop()
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
When the exception was thrown, this was the stack:
#0 fail (package:matcher/src/expect/expect.dart:149:31)
#1 _VerifyCall._checkWith (package:mocktail/src/mocktail.dart:728:7)
#2 _makeVerify.<anonymous closure> (package:mocktail/src/mocktail.dart:519:18)
#3 main.<anonymous closure>.<anonymous closure> (file:///Users/path/to/file/flutter_mockingjay/test/main_test.dart:33:13)
<asynchronous suspension>
#4 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:168:15)
<asynchronous suspension>
#5 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1013:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)
The test description was:
can pop a dialog
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: can pop a dialog
✖ MainApp can pop a dialog
popping...
popped!
✓ MainApp can pop a normal widget
To Reproduce
Reproducible example: https://github.com/egonm12/flutter_mockingjay/tree/main
void main() {
group(MainApp, () {
late MockNavigator mockNavigator;
setUp(() {
mockNavigator = MockNavigator();
when(() => mockNavigator.canPop()).thenReturn(true);
when(() => mockNavigator.pop(any())).thenReturn(null);
});
testWidgets('can pop a dialog', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: MockNavigatorProvider(
navigator: mockNavigator,
child: const MyFloatingActionButton(),
),
),
);
await tester.tap(find.byType(FloatingActionButton));
await tester.pump();
await tester.pumpAndSettle();
await tester.tap(find.byType(TextButton));
verify(() => mockNavigator.canPop()).called(1);
verify(() => mockNavigator.pop<Object?>(any())).called(1);
});
testWidgets('can pop a normal widget', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: MockNavigatorProvider(
navigator: mockNavigator,
child: const MyWidget(),
),
),
);
await tester.tap(find.byType(ElevatedButton));
verify(() => mockNavigator.canPop()).called(1);
verify(() => mockNavigator.pop<Object?>(any())).called(1);
});
});
}
Expected behavior
All tests pass
This happens because showDialog is looking up for the root Navigator created by the MaterialApp.
I think this test scenario it's not a test case for a mocked navigation, where you are navigating between two routes. You can cover these scenarios best with integration tests or using a concrete Navigator.
But if you really want to try, provide a Navigator above MaterialApp and replace it in tests, or, receive a Navigator as parameter in the MyFloatingActionButton, and pass the mock during tests.
Thanks @robsonsilv4 for taking the time to reply, @egonm12 did the reply help solve your issue?
Closing as resolved by https://github.com/VeryGoodOpenSource/mockingjay/issues/67#issuecomment-2248818879.