diff --git a/lib/pages/test_page.dart b/lib/pages/test_page.dart new file mode 100644 index 00000000..e8afbc20 --- /dev/null +++ b/lib/pages/test_page.dart @@ -0,0 +1,13 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +@RoutePage() +class SailTestPage extends StatelessWidget { + final Widget child; + const SailTestPage({super.key, required this.child}); + + @override + Widget build(BuildContext context) { + return child; + } +} diff --git a/lib/routing/router.dart b/lib/routing/router.dart index 7dc489bc..56f2d782 100644 --- a/lib/routing/router.dart +++ b/lib/routing/router.dart @@ -1,5 +1,6 @@ import 'package:auto_route/auto_route.dart'; -import 'package:sidesail/pages/home_page.dart'; +import 'package:flutter/widgets.dart'; +import 'package:sidesail/routing/routes_export.dart'; part 'router.gr.dart'; @@ -25,5 +26,9 @@ class AppRouter extends _$AppRouter { page: HomeRoute.page, initial: true, ), + + /// This route is used in tests so that we can pump a widget into a route + /// and use the real router for our test + AutoRoute(page: SailTestRoute.page), ]; } diff --git a/lib/routing/router.gr.dart b/lib/routing/router.gr.dart index 2cf29d79..b0142c4c 100644 --- a/lib/routing/router.gr.dart +++ b/lib/routing/router.gr.dart @@ -20,7 +20,17 @@ abstract class _$AppRouter extends RootStackRouter { routeData: routeData, child: const HomePage(), ); - } + }, + SailTestRoute.name: (routeData) { + final args = routeData.argsAs(); + return AutoRoutePage( + routeData: routeData, + child: SailTestPage( + key: args.key, + child: args.child, + ), + ); + }, }; } @@ -37,3 +47,40 @@ class HomeRoute extends PageRouteInfo { static const PageInfo page = PageInfo(name); } + +/// generated route for +/// [SailTestPage] +class SailTestRoute extends PageRouteInfo { + SailTestRoute({ + Key? key, + required Widget child, + List? children, + }) : super( + SailTestRoute.name, + args: SailTestRouteArgs( + key: key, + child: child, + ), + initialChildren: children, + ); + + static const String name = 'SailTestRoute'; + + static const PageInfo page = PageInfo(name); +} + +class SailTestRouteArgs { + const SailTestRouteArgs({ + this.key, + required this.child, + }); + + final Key? key; + + final Widget child; + + @override + String toString() { + return 'SailTestRouteArgs{key: $key, child: $child}'; + } +} diff --git a/lib/routing/routes_export.dart b/lib/routing/routes_export.dart index 3eb807bb..84ee2dfb 100644 --- a/lib/routing/routes_export.dart +++ b/lib/routing/routes_export.dart @@ -1,3 +1,4 @@ // all routes should be exported from this file! export 'package:sidesail/pages/home_page.dart'; +export 'package:sidesail/pages/test_page.dart'; diff --git a/test/mocks/storage_mock.dart b/test/mocks/storage_mock.dart new file mode 100644 index 00000000..fb3890b4 --- /dev/null +++ b/test/mocks/storage_mock.dart @@ -0,0 +1,18 @@ +import 'package:sidesail/storage/client_settings.dart'; + +class MockStore implements KeyValueStore { + final _db = {}; + + @override + Future getString(String key) async => _db[key]; + + @override + Future setString(String key, String value) async { + _db[key] = value; + } + + @override + Future delete(String key) async { + _db[key] = null; + } +} diff --git a/test/test_utils.dart b/test/test_utils.dart new file mode 100644 index 00000000..10fd7767 --- /dev/null +++ b/test/test_utils.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get_it/get_it.dart'; +import 'package:sidesail/app.dart'; +import 'package:sidesail/routing/router.dart'; +import 'package:sidesail/storage/client_settings.dart'; + +import 'mocks/storage_mock.dart'; + +Future _setDeviceSize() async { + final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); + await binding.setSurfaceSize(const Size(1200, 720)); +} + +Future loadFonts() async { + final sourceCodePro = rootBundle.load('fonts/SourceCodePro-Regular.ttf'); + final fontLoader = FontLoader('SourceCodePro')..addFont(sourceCodePro); + await fontLoader.load(); +} + +extension TestExtension on WidgetTester { + Future pumpSailPage( + Widget child, { + bool requireIntensionKyc = false, + bool requireKycLevel2 = false, + }) async { + await _setDeviceSize(); + await loadFonts(); + await registerTestDependencies(); + + await pumpWidget( + SailApp( + builder: (context, router) { + final appRouter = GetIt.I.get(); + + return MaterialApp.router( + routerDelegate: appRouter.delegate( + initialRoutes: [SailTestRoute(child: child)], + ), + routeInformationParser: appRouter.defaultRouteParser(), + title: 'SideSail', + theme: ThemeData( + fontFamily: 'SourceCodePro', + ), + ); + }, + ), + ); + await pumpAndSettle(); + } +} + +Future registerTestDependencies() async { + if (!GetIt.I.isRegistered()) { + GetIt.I.registerLazySingleton( + () => AppRouter(), + ); + } + + if (!GetIt.I.isRegistered()) { + GetIt.I.registerLazySingleton( + () => ClientSettings(store: MockStore()), + ); + } +} diff --git a/test/widget_test.dart b/test/widget_test.dart index 0ac4eab0..d1346a72 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -6,16 +6,20 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter_test/flutter_test.dart'; +import 'package:sidesail/pages/home_page.dart'; -import 'package:sidesail/main.dart'; +import 'test_utils.dart'; void main() { testWidgets('RPC submit smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); + await tester.pumpSailPage( + const HomePage(), + ); // Verify that there's a submit button. expect(find.text('Submit'), findsOneWidget); + expect(find.text('SideSail'), findsOneWidget); // TODO: something more meaningful. Would have to mock the RPC interfaces });