The testWidgets function is apparently only a subcase of the test function.
A use case I'm trying to solve right now is to pump the same widget for multiple testWidgets, a setUp for multiple testWidgets. However, how can I do this if it creates a new instance inside each test?
I've tried to initialize a WidgetTester outside the tests, in the main(), but WidgetTester has only a private constructor:
class WidgetTester
extends WidgetController
implements HitTestDispatcher, TickerProvider {
WidgetTester._(TestWidgetsFlutterBinding binding) : super(binding) {
if (binding is LiveTestWidgetsFlutterBinding)
binding.deviceEventDispatcher = this;
}
I don't quite get how the Flutter team made this work, but initializing a WidgetTester in the same way they did inside the testWidgets function isn't working for me:
final TestWidgetsFlutterBinding binding
= TestWidgetsFlutterBinding.ensureInitialized()
as TestWidgetsFlutterBinding;
final WidgetTester tester = WidgetTester._(binding);
A simple example would be to try to break down the tests of the Flutter demo that is created with each new Flutter project from flutter create. In it, we could try to separate the initial setup test of the app from the tapping action test:
testWidgets('Initial setup', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
});
testWidgets('Increment the counter on tap', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
The idea would be to try to move the await tester.pumpWidget(MyApp()); into a setUp function.
For that, we will use a widget tester to tap the submit button and Mockito's verify method. The snippet is the same for both create and update tests. final saveButton = find. byKey(const Key('submit-button')); expect(saveButton, findsOneWidget); await tester.
Below is what looks like the current way to solve for this in Flutter.
To summarize:
group(..) structure inside main()
WidgetTester instanceasync
testWidgets(..)
await, so they don't run concurrentlySo far I didn't find a way for the output to indicate each "sub-test" it ran, so just using print(...) statements for now.
This is a demo for some QR Code logic:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:qr_code_demo/app/appRoutes.dart';
import 'package:qr_code_demo/view/appHome.dart';
import 'package:qr_code_demo/view/qrScanner.dart';
class MockNavigatorObserver extends Mock implements NavigatorObserver {}
void main() {
group('MainPage navigation tests', () {
NavigatorObserver mockObserver;
_loadAppHomeScreen(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
routes: AppRoutes.getRouteMap(),
home: AppHomeScreen(),
navigatorObservers: [mockObserver],
),
);
}
setUp(() {
mockObserver = MockNavigatorObserver();
});
Future<Null> _verifyLayoutElements(WidgetTester tester) async {
print('_verifyLayoutElements');
expect(find.byIcon(Icons.scanner), findsOneWidget);
expect(find.byType(FloatingActionButton), findsOneWidget);
expect(find.byType(RaisedButton), findsOneWidget);
}
Future<Null> _navigateToQrScannerScreen(WidgetTester tester) async {
print('_navigateToQrScannerScreen');
await tester.tap(find.byIcon(Icons.scanner));
await tester.pumpAndSettle();
verify(mockObserver.didPush(any, any));
expect(find.byType(AppHomeScreen), findsNothing);
expect(find.byType(QrScannerScreen), findsOneWidget);
}
testWidgets('AppHomeScreen WidgetTester', (WidgetTester tester) async {
await _loadAppHomeScreen(tester);
await _verifyLayoutElements(tester);
await _navigateToQrScannerScreen(tester);
});
});
}
Thanks to: https://iiro.dev/2018/08/22/writing-widget-tests-for-navigation-events/
test/navigation_test.dart
====
And double-thanks, because the navigation testing logic including with this example is thanks to @iiro's post: https://stackoverflow.com/a/51983194/2162226
Here is the appRoutes.dart file:
import 'package:qr_code_demo/view/appHome.dart';
import 'package:qr_code_demo/view/qrScanner.dart';
class AppRoutes {
static const String AppHome = 'AppHome';
static const String QrScanner = 'QrScanner';
static String initialRoute() {
return AppHome;
}
static getRouteMap() {
return {
AppRoutes.AppHome: (context) => AppHomeScreen(),
AppRoutes.QrScanner: (context) => QrScannerScreen()
};
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With