Jonny Borges
Committed by GitHub

Merge pull request #824 from SchabanBo/master

Get Page Children And GetMiddleware
@@ -9,6 +9,7 @@ export 'src/routes/custom_transition.dart'; @@ -9,6 +9,7 @@ export 'src/routes/custom_transition.dart';
9 export 'src/routes/default_route.dart'; 9 export 'src/routes/default_route.dart';
10 export 'src/routes/get_route.dart'; 10 export 'src/routes/get_route.dart';
11 export 'src/routes/observers/route_observer.dart'; 11 export 'src/routes/observers/route_observer.dart';
  12 +export 'src/routes/route_middleware.dart';
12 export 'src/routes/transitions_type.dart'; 13 export 'src/routes/transitions_type.dart';
13 export 'src/snackbar/snack.dart'; 14 export 'src/snackbar/snack.dart';
14 export 'src/snackbar/snack_route.dart'; 15 export 'src/snackbar/snack_route.dart';
@@ -188,44 +188,7 @@ class GetCupertinoApp extends StatelessWidget { @@ -188,44 +188,7 @@ class GetCupertinoApp extends StatelessWidget {
188 super(key: key); 188 super(key: key);
189 189
190 Route<dynamic> generator(RouteSettings settings) { 190 Route<dynamic> generator(RouteSettings settings) {
191 - final match = Get.routeTree.matchRoute(settings.name);  
192 - Get.parameters = match?.parameters;  
193 -  
194 - if (match?.route == null) {  
195 - return GetPageRoute(  
196 - page: unknownRoute.page,  
197 - parameter: unknownRoute.parameter,  
198 - settings:  
199 - RouteSettings(name: settings.name, arguments: settings.arguments),  
200 - curve: unknownRoute.curve,  
201 - opaque: unknownRoute.opaque,  
202 - customTransition: unknownRoute.customTransition,  
203 - binding: unknownRoute.binding,  
204 - bindings: unknownRoute.bindings,  
205 - transitionDuration:  
206 - (unknownRoute.transitionDuration ?? Get.defaultTransitionDuration),  
207 - transition: unknownRoute.transition,  
208 - popGesture: unknownRoute.popGesture,  
209 - fullscreenDialog: unknownRoute.fullscreenDialog,  
210 - );  
211 - }  
212 -  
213 - return GetPageRoute(  
214 - page: match.route.page,  
215 - parameter: match.route.parameter,  
216 - settings:  
217 - RouteSettings(name: settings.name, arguments: settings.arguments),  
218 - curve: match.route.curve,  
219 - opaque: match.route.opaque,  
220 - customTransition: match.route.customTransition,  
221 - binding: match.route.binding,  
222 - bindings: match.route.bindings,  
223 - transitionDuration:  
224 - (match.route.transitionDuration ?? Get.defaultTransitionDuration),  
225 - transition: match.route.transition,  
226 - popGesture: match.route.popGesture,  
227 - fullscreenDialog: match.route.fullscreenDialog,  
228 - ); 191 + return PageRedirect(settings, unknownRoute).page();
229 } 192 }
230 193
231 List<Route<dynamic>> initialRoutesGenerate(String name) { 194 List<Route<dynamic>> initialRoutesGenerate(String name) {
@@ -199,44 +199,7 @@ class GetMaterialApp extends StatelessWidget { @@ -199,44 +199,7 @@ class GetMaterialApp extends StatelessWidget {
199 super(key: key); 199 super(key: key);
200 200
201 Route<dynamic> generator(RouteSettings settings) { 201 Route<dynamic> generator(RouteSettings settings) {
202 - final match = Get.routeTree.matchRoute(settings.name);  
203 - Get.parameters = match?.parameters;  
204 -  
205 - if (match?.route == null) {  
206 - return GetPageRoute(  
207 - page: unknownRoute.page,  
208 - parameter: unknownRoute.parameter,  
209 - settings:  
210 - RouteSettings(name: settings.name, arguments: settings.arguments),  
211 - curve: unknownRoute.curve,  
212 - opaque: unknownRoute.opaque,  
213 - customTransition: unknownRoute.customTransition,  
214 - binding: unknownRoute.binding,  
215 - bindings: unknownRoute.bindings,  
216 - transitionDuration:  
217 - (unknownRoute.transitionDuration ?? Get.defaultTransitionDuration),  
218 - transition: unknownRoute.transition,  
219 - popGesture: unknownRoute.popGesture,  
220 - fullscreenDialog: unknownRoute.fullscreenDialog,  
221 - );  
222 - }  
223 -  
224 - return GetPageRoute(  
225 - page: match.route.page,  
226 - parameter: match.route.parameter,  
227 - settings:  
228 - RouteSettings(name: settings.name, arguments: settings.arguments),  
229 - curve: match.route.curve,  
230 - opaque: match.route.opaque,  
231 - customTransition: match.route.customTransition,  
232 - binding: match.route.binding,  
233 - bindings: match.route.bindings,  
234 - transitionDuration:  
235 - (match.route.transitionDuration ?? Get.defaultTransitionDuration),  
236 - transition: match.route.transition,  
237 - popGesture: match.route.popGesture,  
238 - fullscreenDialog: match.route.fullscreenDialog,  
239 - ); 202 + return PageRedirect(settings, unknownRoute).page();
240 } 203 }
241 204
242 List<Route<dynamic>> initialRoutesGenerate(String name) { 205 List<Route<dynamic>> initialRoutesGenerate(String name) {
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
  2 +import 'package:get/get.dart';
2 import '../routes/get_route.dart'; 3 import '../routes/get_route.dart';
3 4
4 class ParseRouteTree { 5 class ParseRouteTree {
5 final List<_ParseRouteTreeNode> _nodes = <_ParseRouteTreeNode>[]; 6 final List<_ParseRouteTreeNode> _nodes = <_ParseRouteTreeNode>[];
6 7
7 // bool _hasDefaultRoute = false; 8 // bool _hasDefaultRoute = false;
8 -  
9 void addRoute(GetPage route) { 9 void addRoute(GetPage route) {
10 var path = route.name; 10 var path = route.name;
11 11
@@ -46,8 +46,57 @@ class ParseRouteTree { @@ -46,8 +46,57 @@ class ParseRouteTree {
46 } 46 }
47 parent = node; 47 parent = node;
48 } 48 }
  49 +
  50 + // Add Page children.
  51 + for (var page in _flattenPage(route)) {
  52 + addRoute(page);
  53 + }
  54 + }
  55 +
  56 + List<GetPage> _flattenPage(GetPage route) {
  57 + final result = <GetPage>[];
  58 + if (route.children == null || route.children.isEmpty) {
  59 + return result;
  60 + }
  61 +
  62 + final parentPath = route.name;
  63 + for (var page in route.children) {
  64 + // Add Parent middlewares to children
  65 + final pageMiddlewares = page.middlewares ?? <GetMiddleware>[];
  66 + pageMiddlewares.addAll(route.middlewares ?? <GetMiddleware>[]);
  67 + result.add(_addChild(page, parentPath, pageMiddlewares));
  68 + final children = _flattenPage(page);
  69 + for (var child in children) {
  70 + pageMiddlewares.addAll(child.middlewares ?? <GetMiddleware>[]);
  71 + result.add(_addChild(child, parentPath, pageMiddlewares));
  72 + }
  73 + }
  74 + return result;
49 } 75 }
50 76
  77 + /// Change the Path for a [GetPage]
  78 + GetPage _addChild(
  79 + GetPage origin, String parentPath, List<GetMiddleware> middlewares) =>
  80 + GetPage(
  81 + name: parentPath + origin.name,
  82 + page: origin.page,
  83 + title: origin.title,
  84 + alignment: origin.alignment,
  85 + transition: origin.transition,
  86 + binding: origin.binding,
  87 + bindings: origin.bindings,
  88 + curve: origin.curve,
  89 + customTransition: origin.customTransition,
  90 + fullscreenDialog: origin.fullscreenDialog,
  91 + maintainState: origin.maintainState,
  92 + opaque: origin.opaque,
  93 + parameter: origin.parameter,
  94 + popGesture: origin.popGesture,
  95 + settings: origin.settings,
  96 + transitionDuration: origin.transitionDuration,
  97 + middlewares: middlewares,
  98 + );
  99 +
51 _GetPageMatch matchRoute(String path) { 100 _GetPageMatch matchRoute(String path) {
52 var usePath = path; 101 var usePath = path;
53 if (usePath.startsWith("/")) { 102 if (usePath.startsWith("/")) {
@@ -11,26 +11,27 @@ import 'default_transitions.dart'; @@ -11,26 +11,27 @@ import 'default_transitions.dart';
11 import 'transitions_type.dart'; 11 import 'transitions_type.dart';
12 12
13 class GetPageRoute<T> extends PageRoute<T> { 13 class GetPageRoute<T> extends PageRoute<T> {
14 - GetPageRoute({  
15 - RouteSettings settings,  
16 - this.transitionDuration = const Duration(milliseconds: 300),  
17 - this.opaque = true,  
18 - this.parameter,  
19 - this.curve,  
20 - this.alignment,  
21 - this.transition,  
22 - this.popGesture,  
23 - this.customTransition,  
24 - this.barrierDismissible = false,  
25 - this.barrierColor,  
26 - this.binding,  
27 - this.bindings,  
28 - this.routeName,  
29 - this.page,  
30 - this.barrierLabel,  
31 - this.maintainState = true,  
32 - bool fullscreenDialog = false,  
33 - }) : assert(opaque != null), 14 + GetPageRoute(
  15 + {RouteSettings settings,
  16 + this.transitionDuration = const Duration(milliseconds: 300),
  17 + this.opaque = true,
  18 + this.parameter,
  19 + this.curve,
  20 + this.alignment,
  21 + this.transition,
  22 + this.popGesture,
  23 + this.customTransition,
  24 + this.barrierDismissible = false,
  25 + this.barrierColor,
  26 + this.binding,
  27 + this.bindings,
  28 + this.routeName,
  29 + this.page,
  30 + this.barrierLabel,
  31 + this.maintainState = true,
  32 + bool fullscreenDialog = false,
  33 + this.middlewares})
  34 + : assert(opaque != null),
34 assert(barrierDismissible != null), 35 assert(barrierDismissible != null),
35 assert(maintainState != null), 36 assert(maintainState != null),
36 assert(fullscreenDialog != null), 37 assert(fullscreenDialog != null),
@@ -68,6 +69,8 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -68,6 +69,8 @@ class GetPageRoute<T> extends PageRoute<T> {
68 69
69 final Alignment alignment; 70 final Alignment alignment;
70 71
  72 + final List<GetMiddleware> middlewares;
  73 +
71 @override 74 @override
72 final Color barrierColor; 75 final Color barrierColor;
73 76
@@ -113,15 +116,21 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -113,15 +116,21 @@ class GetPageRoute<T> extends PageRoute<T> {
113 Animation<double> animation, 116 Animation<double> animation,
114 Animation<double> secondaryAnimation, 117 Animation<double> secondaryAnimation,
115 ) { 118 ) {
116 - // Get.reference = settings.name ?? routeName; 119 +
  120 + // Get.reference = settings.name ?? routeName;
  121 +
  122 + final middlewareRunner = MiddlewareRunner(middlewares);
  123 + final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings);
  124 +
117 binding?.dependencies(); 125 binding?.dependencies();
118 - if (bindings != null) {  
119 - for (final binding in bindings) { 126 + if (bindingsToBind != null) {
  127 + for (final binding in bindingsToBind) {
120 binding.dependencies(); 128 binding.dependencies();
121 } 129 }
122 } 130 }
123 - // final pageWidget = page();  
124 - return page(); 131 +
  132 + final pageToBuild = middlewareRunner.runOnPageBuildStart(page);
  133 + return middlewareRunner.runOnPageBuilt(pageToBuild());
125 } 134 }
126 135
127 static bool isPopGestureInProgress(PageRoute<dynamic> route) { 136 static bool isPopGestureInProgress(PageRoute<dynamic> route) {
@@ -384,6 +393,10 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -384,6 +393,10 @@ class GetPageRoute<T> extends PageRoute<T> {
384 WidgetsBinding.instance.addPostFrameCallback( 393 WidgetsBinding.instance.addPostFrameCallback(
385 (_) => GetInstance().removeDependencyByRoute("$reference")); 394 (_) => GetInstance().removeDependencyByRoute("$reference"));
386 } 395 }
  396 +
  397 + final middlewareRunner = MiddlewareRunner(middlewares);
  398 + middlewareRunner.runOnPageDispose();
  399 +
387 } 400 }
388 } 401 }
389 402
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
  2 +
2 import '../../../get_instance/get_instance.dart'; 3 import '../../../get_instance/get_instance.dart';
  4 +import '../../get_navigation.dart';
3 import 'custom_transition.dart'; 5 import 'custom_transition.dart';
4 import 'transitions_type.dart'; 6 import 'transitions_type.dart';
5 7
@@ -20,6 +22,8 @@ class GetPage { @@ -20,6 +22,8 @@ class GetPage {
20 final Duration transitionDuration; 22 final Duration transitionDuration;
21 final bool fullscreenDialog; 23 final bool fullscreenDialog;
22 final RouteSettings settings; 24 final RouteSettings settings;
  25 + final List<GetPage> children;
  26 + final List<GetMiddleware> middlewares;
23 27
24 const GetPage({ 28 const GetPage({
25 @required this.name, 29 @required this.name,
@@ -38,8 +42,52 @@ class GetPage { @@ -38,8 +42,52 @@ class GetPage {
38 this.transition, 42 this.transition,
39 this.customTransition, 43 this.customTransition,
40 this.fullscreenDialog = false, 44 this.fullscreenDialog = false,
  45 + this.children,
  46 + this.middlewares,
41 }) : assert(page != null), 47 }) : assert(page != null),
42 assert(name != null), 48 assert(name != null),
43 assert(maintainState != null), 49 assert(maintainState != null),
44 assert(fullscreenDialog != null); 50 assert(fullscreenDialog != null);
  51 +
  52 + GetPage copyWith({
  53 + String name,
  54 + GetPageBuilder page,
  55 + bool popGesture,
  56 + Map<String, String> parameter,
  57 + String title,
  58 + Transition transition,
  59 + Curve curve,
  60 + Alignment alignment,
  61 + bool maintainState,
  62 + bool opaque,
  63 + Bindings binding,
  64 + List<Bindings> bindings,
  65 + CustomTransition customTransition,
  66 + Duration transitionDuration,
  67 + bool fullscreenDialog,
  68 + RouteSettings settings,
  69 + List<GetPage> children,
  70 + List<GetMiddleware> middlewares,
  71 + }) {
  72 + return GetPage(
  73 + name: name ?? this.name,
  74 + page: page ?? this.page,
  75 + popGesture: popGesture ?? this.popGesture,
  76 + parameter: parameter ?? this.parameter,
  77 + title: title ?? this.title,
  78 + transition: transition ?? this.transition,
  79 + curve: curve ?? this.curve,
  80 + alignment: alignment ?? this.alignment,
  81 + maintainState: maintainState ?? this.maintainState,
  82 + opaque: opaque ?? this.opaque,
  83 + binding: binding ?? this.binding,
  84 + bindings: bindings ?? this.bindings,
  85 + customTransition: customTransition ?? this.customTransition,
  86 + transitionDuration: transitionDuration ?? this.transitionDuration,
  87 + fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog,
  88 + settings: settings ?? this.settings,
  89 + children: children ?? this.children,
  90 + middlewares: middlewares ?? this.middlewares,
  91 + );
  92 + }
45 } 93 }
  1 +import 'package:flutter/cupertino.dart';
  2 +import '../../../get.dart';
  3 +
  4 +abstract class _RouteMiddleware {
  5 + /// The Order of the Middlewares to run.
  6 + ///
  7 + /// {@tool snippet}
  8 + /// This Middewares will be called in this order.
  9 + /// ```dart
  10 + /// final middlewares = [
  11 + /// GetMiddleware(priority: 2),
  12 + /// GetMiddleware(priority: 5),
  13 + /// GetMiddleware(priority: 4),
  14 + /// GetMiddleware(priority: -8),
  15 + /// ];
  16 + /// ```
  17 + /// -8 => 2 => 4 => 5
  18 + /// {@end-tool}
  19 + int priority;
  20 +
  21 + /// This function will be called when the page of
  22 + /// the called route is being searched for.
  23 + /// It take RouteSettings as a result an redirect to the new settings or
  24 + /// give it null and there will be no redirecting.
  25 + /// {@tool snippet}
  26 + /// ```dart
  27 + /// GetPage redirect(String route) {
  28 + /// final authService = Get.find<AuthService>();
  29 + /// return authService.authed.value ? null : RouteSettings(name: '/login');
  30 + /// }
  31 + /// ```
  32 + /// {@end-tool}
  33 + RouteSettings redirect(String route);
  34 +
  35 + /// This function will be called when this Page is called
  36 + /// you can use it to change something about the page or give it new page
  37 + /// {@tool snippet}
  38 + /// ```dart
  39 + /// GetPage onPageCalled(GetPage page) {
  40 + /// final authService = Get.find<AuthService>();
  41 + /// return page.copyWith(title: 'Wellcome ${authService.UserName}');
  42 + /// }
  43 + /// ```
  44 + /// {@end-tool}
  45 + GetPage onPageCalled(GetPage page);
  46 +
  47 + /// This function will be called right before the [Bindings] are initialize.
  48 + /// Here you can change [Bindings] for this page
  49 + /// {@tool snippet}
  50 + /// ```dart
  51 + /// List<Bindings> onBindingsStart(List<Bindings> bindings) {
  52 + /// final authService = Get.find<AuthService>();
  53 + /// if (authService.isAdmin) {
  54 + /// bindings.add(AdminBinding());
  55 + /// }
  56 + /// return bindings;
  57 + /// }
  58 + /// ```
  59 + /// {@end-tool}
  60 + List<Bindings> onBindingsStart(List<Bindings> bindings);
  61 +
  62 + /// This function will be called right after the [Bindings] are initialize.
  63 + GetPageBuilder onPageBuildStart(GetPageBuilder page);
  64 +
  65 + /// This function will be called right after the
  66 + /// GetPage.page function is called and will give you the result
  67 + /// of the function. and take the widget that will be showed.
  68 + Widget onPageBuilt(Widget page);
  69 +
  70 + void onPageDispose();
  71 +}
  72 +
  73 +/// The Page Middlewares.
  74 +/// The Functions will be called in this order
  75 +/// (( [redirect] -> [onPageCalled] -> [onBindingsStart] ->
  76 +/// [onPageBuildStart] -> [onPageBuilt] -> [onPageDispose] ))
  77 +class GetMiddleware implements _RouteMiddleware {
  78 + @override
  79 + int priority = 0;
  80 +
  81 + GetMiddleware({this.priority});
  82 +
  83 + @override
  84 + RouteSettings redirect(String route) => null;
  85 +
  86 + @override
  87 + GetPage onPageCalled(GetPage page) => page;
  88 +
  89 + @override
  90 + List<Bindings> onBindingsStart(List<Bindings> bindings) => bindings;
  91 +
  92 + @override
  93 + GetPageBuilder onPageBuildStart(GetPageBuilder page) => page;
  94 +
  95 + @override
  96 + Widget onPageBuilt(Widget page) => page;
  97 +
  98 + @override
  99 + void onPageDispose() {}
  100 +}
  101 +
  102 +class MiddlewareRunner {
  103 + MiddlewareRunner(this._middlewares);
  104 +
  105 + final List<GetMiddleware> _middlewares;
  106 +
  107 + List<GetMiddleware> _getMiddlewares() {
  108 + if (_middlewares != null) {
  109 + _middlewares.sort((a, b) => a.priority.compareTo(b.priority));
  110 + return _middlewares;
  111 + }
  112 + return <GetMiddleware>[];
  113 + }
  114 +
  115 + GetPage runOnPageCalled(GetPage page) {
  116 + _getMiddlewares().forEach((element) {
  117 + page = element.onPageCalled(page);
  118 + });
  119 + return page;
  120 + }
  121 +
  122 + RouteSettings runRedirect(String route) {
  123 + RouteSettings to;
  124 + _getMiddlewares().forEach((element) {
  125 + to = element.redirect(route);
  126 + });
  127 + if (to != null) {
  128 + Get.log('Redirect to $to');
  129 + }
  130 + return to;
  131 + }
  132 +
  133 + List<Bindings> runOnBindingsStart(List<Bindings> bindings) {
  134 + _getMiddlewares().forEach((element) {
  135 + bindings = element.onBindingsStart(bindings);
  136 + });
  137 + return bindings;
  138 + }
  139 +
  140 + GetPageBuilder runOnPageBuildStart(GetPageBuilder page) {
  141 + _getMiddlewares().forEach((element) {
  142 + page = element.onPageBuildStart(page);
  143 + });
  144 + return page;
  145 + }
  146 +
  147 + Widget runOnPageBuilt(Widget page) {
  148 + _getMiddlewares().forEach((element) {
  149 + page = element.onPageBuilt(page);
  150 + });
  151 + return page;
  152 + }
  153 +
  154 + void runOnPageDispose() =>
  155 + _getMiddlewares().forEach((element) => element.onPageDispose());
  156 +}
  157 +
  158 +class PageRedirect {
  159 + GetPage route;
  160 + GetPage unknownRoute;
  161 + RouteSettings settings;
  162 + bool isUnknown;
  163 +
  164 + PageRedirect(this.settings, this.unknownRoute,
  165 + {this.isUnknown = false, this.route});
  166 +
  167 + // redirect all pages that needes redirecting
  168 + GetPageRoute page() {
  169 + while (needRecheck()) {}
  170 + return isUnknown
  171 + ? GetPageRoute(
  172 + page: unknownRoute.page,
  173 + parameter: unknownRoute.parameter,
  174 + settings: RouteSettings(
  175 + name: settings.name, arguments: settings.arguments),
  176 + curve: unknownRoute.curve,
  177 + opaque: unknownRoute.opaque,
  178 + customTransition: unknownRoute.customTransition,
  179 + binding: unknownRoute.binding,
  180 + bindings: unknownRoute.bindings,
  181 + transitionDuration: (unknownRoute.transitionDuration ??
  182 + Get.defaultTransitionDuration),
  183 + transition: unknownRoute.transition,
  184 + popGesture: unknownRoute.popGesture,
  185 + fullscreenDialog: unknownRoute.fullscreenDialog,
  186 + middlewares: unknownRoute.middlewares,
  187 + )
  188 + : GetPageRoute(
  189 + page: route.page,
  190 + parameter: route.parameter,
  191 + settings: RouteSettings(
  192 + name: settings.name, arguments: settings.arguments),
  193 + curve: route.curve,
  194 + opaque: route.opaque,
  195 + customTransition: route.customTransition,
  196 + binding: route.binding,
  197 + bindings: route.bindings,
  198 + transitionDuration:
  199 + (route.transitionDuration ?? Get.defaultTransitionDuration),
  200 + transition: route.transition,
  201 + popGesture: route.popGesture,
  202 + fullscreenDialog: route.fullscreenDialog,
  203 + middlewares: route.middlewares);
  204 + }
  205 +
  206 + /// check if redirect is needed
  207 + bool needRecheck() {
  208 + final match = Get.routeTree.matchRoute(settings.name);
  209 + Get.parameters = match?.parameters;
  210 +
  211 + // No Match found
  212 + if (match?.route == null) {
  213 + isUnknown = true;
  214 + return false;
  215 + }
  216 +
  217 + final runner = MiddlewareRunner(match.route.middlewares);
  218 + route = runner.runOnPageCalled(match.route);
  219 +
  220 + // No middlewares found return match.
  221 + if (match.route.middlewares == null || match.route.middlewares.isEmpty) {
  222 + return false;
  223 + }
  224 + final newSettings = runner.runRedirect(settings.name);
  225 + if (newSettings == null) {
  226 + return false;
  227 + }
  228 + settings = newSettings;
  229 + return true;
  230 + }
  231 +}
  1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter_test/flutter_test.dart';
  3 +import 'package:get/get.dart';
  4 +
  5 +import 'get_main_test.dart';
  6 +
  7 +class RedirectMiddleware extends GetMiddleware {
  8 + @override
  9 + RouteSettings redirect(String route) => RouteSettings(name: '/second');
  10 +}
  11 +
  12 +main() {
  13 + testWidgets("Middleware redirect smoke test", (tester) async {
  14 + await tester.pumpWidget(
  15 + GetMaterialApp(
  16 + initialRoute: '/',
  17 + getPages: [
  18 + GetPage(name: '/', page: () => Container()),
  19 + GetPage(
  20 + name: '/first',
  21 + page: () => FirstScreen(),
  22 + middlewares: [RedirectMiddleware()]),
  23 + GetPage(name: '/second', page: () => SecondScreen()),
  24 + GetPage(name: '/third', page: () => ThirdScreen()),
  25 + ],
  26 + ),
  27 + );
  28 +
  29 + Get.toNamed('/first');
  30 +
  31 + await tester.pumpAndSettle();
  32 + print(Get.routing.current);
  33 + expect(find.byType(SecondScreen), findsOneWidget);
  34 + });
  35 +}
  1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter_test/flutter_test.dart';
  3 +import 'package:get/get.dart';
  4 +import 'package:get/get_navigation/src/root/parse_route.dart';
  5 +
  6 +void main() {
  7 + test('Parse Page with children', () {
  8 + final tree = ParseRouteTree();
  9 + final pageTree = GetPage(name: '/city', page: () => Container(), children: [
  10 + GetPage(name: '/home', page: () => Container(), children: [
  11 + GetPage(name: '/bed-room', page: () => Container()),
  12 + GetPage(name: '/living-room', page: () => Container()),
  13 + ]),
  14 + GetPage(name: '/work', page: () => Container(), children: [
  15 + GetPage(name: '/office', page: () => Container(), children: [
  16 + GetPage(name: '/pen', page: () => Container()),
  17 + GetPage(name: '/paper', page: () => Container()),
  18 + ]),
  19 + GetPage(name: '/meeting-room', page: () => Container()),
  20 + ]),
  21 + ]);
  22 +
  23 + tree.addRoute(pageTree);
  24 + final searchRoute = '/city/work/office/pen';
  25 + final match = tree.matchRoute(searchRoute);
  26 + expect(match, isNotNull);
  27 + expect(match.route.name, searchRoute);
  28 + });
  29 +
  30 + test('Parse Page without children', () {
  31 + final tree = ParseRouteTree();
  32 + final pageTree = [
  33 + GetPage(name: '/city', page: () => Container()),
  34 + GetPage(name: '/city/home', page: () => Container()),
  35 + GetPage(name: '/city/home/bed-room', page: () => Container()),
  36 + GetPage(name: '/city/home/living-room', page: () => Container()),
  37 + GetPage(name: '/city/work', page: () => Container()),
  38 + GetPage(name: '/city/work/office', page: () => Container()),
  39 + GetPage(name: '/city/work/office/pen', page: () => Container()),
  40 + GetPage(name: '/city/work/office/paper', page: () => Container()),
  41 + GetPage(name: '/city/work/meeting-room', page: () => Container()),
  42 + ];
  43 +
  44 + for (var p in pageTree) {
  45 + tree.addRoute(p);
  46 + }
  47 +
  48 + final searchRoute = '/city/work/office/pen';
  49 + final match = tree.matchRoute(searchRoute);
  50 + expect(match, isNotNull);
  51 + expect(match.route.name, searchRoute);
  52 + });
  53 +}