Unverified Commit de7da494 authored by chunhtai's avatar chunhtai Committed by GitHub

Navigator 2.0: Refactor the imperative api to continue working in the new...

Navigator 2.0: Refactor the imperative api to continue working in the new navigation system (#44930)
parent 3f2c6ea7
......@@ -103,7 +103,6 @@ void main() {
expect(route['settings'] is Map<dynamic, dynamic>);
final Map<dynamic, dynamic> settings = route['settings'] as Map<dynamic, dynamic>;
expect(settings.containsKey('name'));
expect(settings['isInitialRoute'] is bool);
run.stdin.write('q');
final int result = await run.exitCode;
......
......@@ -61,7 +61,7 @@ class VideoCard extends StatelessWidget {
void pushFullScreenWidget() {
final TransitionRoute<void> route = PageRouteBuilder<void>(
settings: RouteSettings(name: title, isInitialRoute: false),
settings: RouteSettings(name: title),
pageBuilder: fullScreenRoutePageBuilder,
);
......
......@@ -75,6 +75,7 @@ class CupertinoApp extends StatefulWidget {
this.routes = const <String, WidgetBuilder>{},
this.initialRoute,
this.onGenerateRoute,
this.onGenerateInitialRoutes,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
......@@ -131,6 +132,9 @@ class CupertinoApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
final RouteFactory onGenerateRoute;
/// {@macro flutter.widgets.widgetsApp.onGenerateInitialRoutes}
final InitialRouteListFactory onGenerateInitialRoutes;
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
final RouteFactory onUnknownRoute;
......@@ -348,6 +352,7 @@ class _CupertinoAppState extends State<CupertinoApp> {
routes: widget.routes,
initialRoute: widget.initialRoute,
onGenerateRoute: widget.onGenerateRoute,
onGenerateInitialRoutes: widget.onGenerateInitialRoutes,
onUnknownRoute: widget.onUnknownRoute,
builder: widget.builder,
title: widget.title,
......
......@@ -169,6 +169,7 @@ class MaterialApp extends StatefulWidget {
this.routes = const <String, WidgetBuilder>{},
this.initialRoute,
this.onGenerateRoute,
this.onGenerateInitialRoutes,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
......@@ -224,6 +225,9 @@ class MaterialApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
final RouteFactory onGenerateRoute;
/// {@macro flutter.widgets.widgetsApp.onGenerateInitialRoutes}
final InitialRouteListFactory onGenerateInitialRoutes;
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
final RouteFactory onUnknownRoute;
......@@ -624,6 +628,7 @@ class _MaterialAppState extends State<MaterialApp> {
routes: widget.routes,
initialRoute: widget.initialRoute,
onGenerateRoute: widget.onGenerateRoute,
onGenerateInitialRoutes: widget.onGenerateInitialRoutes,
onUnknownRoute: widget.onUnknownRoute,
builder: (BuildContext context, Widget child) {
// Use a light theme, dark theme, or fallback theme.
......
......@@ -91,6 +91,11 @@ typedef GenerateAppTitle = String Function(BuildContext context);
/// Creates a [PageRoute] using the given [RouteSettings] and [WidgetBuilder].
typedef PageRouteFactory = PageRoute<T> Function<T>(RouteSettings settings, WidgetBuilder builder);
/// The signature of [WidgetsApp.onGenerateInitialRoutes].
///
/// Creates a series of one or more initial routes.
typedef InitialRouteListFactory = List<Route<dynamic>> Function(String initialRoute);
/// A convenience widget that wraps a number of widgets that are commonly
/// required for an application.
///
......@@ -164,6 +169,7 @@ class WidgetsApp extends StatefulWidget {
Key key,
this.navigatorKey,
this.onGenerateRoute,
this.onGenerateInitialRoutes,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.initialRoute,
......@@ -191,6 +197,12 @@ class WidgetsApp extends StatefulWidget {
this.actions,
}) : assert(navigatorObservers != null),
assert(routes != null),
assert(
home == null ||
onGenerateInitialRoutes == null,
'If onGenerateInitialRoutes is specifiied, the home argument will be '
'redundant.'
),
assert(
home == null ||
!routes.containsKey(Navigator.defaultRouteName),
......@@ -290,6 +302,16 @@ class WidgetsApp extends StatefulWidget {
/// default handler will know what routes and [PageRoute]s to build.
final RouteFactory onGenerateRoute;
/// {@template flutter.widgets.widgetsApp.onGenerateInitialRoutes}
/// The routes generator callback used for generating initial routes if
/// [initialRoute] is provided.
///
/// If this property is not set, the underlying
/// [Navigator.onGenerateInitialRoutes] will default to
/// [Navigator.defaultGenerateInitialRoutes].
/// {@endtemplate}
final InitialRouteListFactory onGenerateInitialRoutes;
/// The [PageRoute] generator callback used when the app is navigated to a
/// named route.
///
......@@ -1265,6 +1287,11 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
? WidgetsBinding.instance.window.defaultRouteName
: widget.initialRoute ?? WidgetsBinding.instance.window.defaultRouteName,
onGenerateRoute: _onGenerateRoute,
onGenerateInitialRoutes: widget.onGenerateInitialRoutes == null
? Navigator.defaultGenerateInitialRoutes
: (NavigatorState navigator, String initialRouteName) {
return widget.onGenerateInitialRoutes(initialRouteName);
},
onUnknownRoute: _onUnknownRoute,
observers: widget.navigatorObservers,
);
......
......@@ -34,14 +34,6 @@ abstract class PageRoute<T> extends ModalRoute<T> {
@override
bool canTransitionFrom(TransitionRoute<dynamic> previousRoute) => previousRoute is PageRoute;
@override
AnimationController createAnimationController() {
final AnimationController controller = super.createAnimationController();
if (settings.isInitialRoute)
controller.value = 1.0;
return controller;
}
}
Widget _defaultTransitionsBuilder(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
......
......@@ -32,17 +32,15 @@ abstract class OverlayRoute<T> extends Route<T> {
/// Subclasses should override this getter to return the builders for the overlay.
Iterable<OverlayEntry> createOverlayEntries();
/// The entries this route has placed in the overlay.
@override
List<OverlayEntry> get overlayEntries => _overlayEntries;
final List<OverlayEntry> _overlayEntries = <OverlayEntry>[];
@override
void install(OverlayEntry insertionPoint) {
void install() {
assert(_overlayEntries.isEmpty);
_overlayEntries.addAll(createOverlayEntries());
navigator.overlay?.insertAll(_overlayEntries, above: insertionPoint);
super.install(insertionPoint);
super.install();
}
/// Controls whether [didPop] calls [NavigatorState.finalizeRoute].
......@@ -68,8 +66,6 @@ abstract class OverlayRoute<T> extends Route<T> {
@override
void dispose() {
for (final OverlayEntry entry in _overlayEntries)
entry.remove();
_overlayEntries.clear();
super.dispose();
}
......@@ -111,6 +107,10 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
/// the opaque route will not be built to save resources.
bool get opaque;
// This ensures that if we got to the dismissed state while still current,
// we will still be disposed when we are eventually popped.
//
// This situation arises when dealing with the Cupertino dismiss gesture.
@override
bool get finishedWhenPopped => _controller.status == AnimationStatus.dismissed;
......@@ -185,13 +185,13 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
}
@override
void install(OverlayEntry insertionPoint) {
void install() {
assert(!_transitionCompleter.isCompleted, 'Cannot install a $runtimeType after disposing it.');
_controller = createAnimationController();
assert(_controller != null, '$runtimeType.createAnimationController() returned null.');
_animation = createAnimation();
assert(_animation != null, '$runtimeType.createAnimation() returned null.');
super.install(insertionPoint);
super.install();
}
@override
......@@ -203,6 +203,15 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
return _controller.forward();
}
@override
void didAdd() {
assert(_controller != null, '$runtimeType.didPush called before calling install() or after calling dispose().');
assert(!_transitionCompleter.isCompleted, 'Cannot reuse a $runtimeType after disposing it.');
_didPushOrReplace();
super.didAdd();
_controller.value = _controller.upperBound;
}
@override
void didReplace(Route<dynamic> oldRoute) {
assert(_controller != null, '$runtimeType.didReplace called before calling install() or after calling dispose().');
......@@ -548,7 +557,7 @@ mixin LocalHistoryRoute<T> on Route<T> {
Future<RoutePopDisposition> willPop() async {
if (willHandlePopInternally)
return RoutePopDisposition.pop;
return await super.willPop();
return super.willPop();
}
@override
......@@ -968,8 +977,8 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
}
@override
void install(OverlayEntry insertionPoint) {
super.install(insertionPoint);
void install() {
super.install();
_animationProxy = ProxyAnimation(super.animation);
_secondaryAnimationProxy = ProxyAnimation(super.secondaryAnimation);
}
......@@ -982,6 +991,14 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
return super.didPush();
}
@override
void didAdd() {
if (_scopeKey.currentState != null) {
navigator.focusScopeNode.setFirstFocus(_scopeKey.currentState.focusScopeNode);
}
super.didAdd();
}
// The API for subclasses to override - used by this class
/// Whether you can dismiss this route by tapping the modal barrier.
......
......@@ -84,4 +84,49 @@ void main() {
expect(tester.widget<Title>(find.byType(Title)).color.value, 0xFF000001);
});
testWidgets('Can customize initial routes', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
await tester.pumpWidget(
CupertinoApp(
navigatorKey: navigatorKey,
onGenerateInitialRoutes: (String initialRoute) {
expect(initialRoute, '/abc');
return <Route<void>>[
PageRouteBuilder<void>(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return const Text('non-regular page one');
}
),
PageRouteBuilder<void>(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return const Text('non-regular page two');
}
),
];
},
initialRoute: '/abc',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => const Text('regular page one'),
'/abc': (BuildContext context) => const Text('regular page two'),
},
)
);
expect(find.text('non-regular page two'), findsOneWidget);
expect(find.text('non-regular page one'), findsNothing);
expect(find.text('regular page one'), findsNothing);
expect(find.text('regular page two'), findsNothing);
navigatorKey.currentState.pop();
await tester.pumpAndSettle();
expect(find.text('non-regular page two'), findsNothing);
expect(find.text('non-regular page one'), findsOneWidget);
expect(find.text('regular page one'), findsNothing);
expect(find.text('regular page two'), findsNothing);
});
}
......@@ -788,6 +788,51 @@ void main() {
expect(themeBeforeBrightnessChange.brightness, Brightness.light);
expect(themeAfterBrightnessChange.brightness, Brightness.dark);
});
testWidgets('MaterialApp can customize initial routes', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
await tester.pumpWidget(
MaterialApp(
navigatorKey: navigatorKey,
onGenerateInitialRoutes: (String initialRoute) {
expect(initialRoute, '/abc');
return <Route<void>>[
PageRouteBuilder<void>(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return const Text('non-regular page one');
}
),
PageRouteBuilder<void>(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return const Text('non-regular page two');
}
),
];
},
initialRoute: '/abc',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => const Text('regular page one'),
'/abc': (BuildContext context) => const Text('regular page two'),
},
)
);
expect(find.text('non-regular page two'), findsOneWidget);
expect(find.text('non-regular page one'), findsNothing);
expect(find.text('regular page one'), findsNothing);
expect(find.text('regular page two'), findsNothing);
navigatorKey.currentState.pop();
await tester.pumpAndSettle();
expect(find.text('non-regular page two'), findsNothing);
expect(find.text('non-regular page one'), findsOneWidget);
expect(find.text('regular page one'), findsNothing);
expect(find.text('regular page two'), findsNothing);
});
}
class MockAccessibilityFeature extends Mock implements AccessibilityFeatures {}
......@@ -163,4 +163,54 @@ void main() {
);
});
});
testWidgets('WidgetsApp can customize initial routes', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
await tester.pumpWidget(
WidgetsApp(
navigatorKey: navigatorKey,
onGenerateInitialRoutes: (String initialRoute) {
expect(initialRoute, '/abc');
return <Route<void>>[
PageRouteBuilder<void>(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return const Text('non-regular page one');
}
),
PageRouteBuilder<void>(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return const Text('non-regular page two');
}
),
];
},
initialRoute: '/abc',
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<void>(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return const Text('regular page');
}
);
},
color: const Color(0xFF123456),
)
);
expect(find.text('non-regular page two'), findsOneWidget);
expect(find.text('non-regular page one'), findsNothing);
expect(find.text('regular page'), findsNothing);
navigatorKey.currentState.pop();
await tester.pumpAndSettle();
expect(find.text('non-regular page two'), findsNothing);
expect(find.text('non-regular page one'), findsOneWidget);
expect(find.text('regular page'), findsNothing);
});
}
......@@ -2188,7 +2188,7 @@ Future<void> main() async {
// The element should be mounted and unique.
expect(state1.mounted, isTrue);
expect(navigatorKey.currentState.pop(), isTrue);
navigatorKey.currentState.pop();
await tester.pumpAndSettle();
// State is preserved.
......
......@@ -197,7 +197,7 @@ void main() {
height: 300.0,
child: Navigator(
onGenerateRoute: (RouteSettings settings) {
if (settings.isInitialRoute) {
if (settings.name == '/') {
return MaterialPageRoute<void>(
builder: (BuildContext context) {
return RaisedButton(
......@@ -453,7 +453,7 @@ void main() {
expect(isPopped, isFalse);
});
testWidgets('replaceNamed', (WidgetTester tester) async {
testWidgets('replaceNamed replaces', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/' : (BuildContext context) => OnTapPage(id: '/', onTap: () { Navigator.pushReplacementNamed(context, '/A'); }),
'/A': (BuildContext context) => OnTapPage(id: 'A', onTap: () { Navigator.pushReplacementNamed(context, '/B'); }),
......@@ -1332,10 +1332,10 @@ void main() {
error.toStringDeep(),
equalsIgnoringHashCodes(
'FlutterError\n'
' If a Navigator has no onUnknownRoute, then its onGenerateRoute\n'
' must never return null.\n'
' When trying to build the route "/", onGenerateRoute returned\n'
' null, but there was no onUnknownRoute callback specified.\n'
' Navigator.onGenerateRoute returned null when requested to build\n'
' route "/".\n'
' The onGenerateRoute callback must never return null, unless an\n'
' onUnknownRoute callback is provided as well.\n'
' The Navigator was:\n'
' NavigatorState#4d6bf(lifecycle state: created)\n',
),
......@@ -1359,10 +1359,9 @@ void main() {
error.toStringDeep(),
equalsIgnoringHashCodes(
'FlutterError\n'
' A Navigator\'s onUnknownRoute returned null.\n'
' When trying to build the route "/", both onGenerateRoute and\n'
' onUnknownRoute returned null. The onUnknownRoute callback should\n'
' never return null.\n'
' Navigator.onUnknownRoute returned null when requested to build\n'
' route "/".\n'
' The onUnknownRoute callback must never return null.\n'
' The Navigator was:\n'
' NavigatorState#38036(lifecycle state: created)\n',
),
......@@ -1492,6 +1491,165 @@ void main() {
expect(tester.state<StatefulTestState>(find.byKey(topRoute)).rebuildCount, 1);
});
testWidgets('initial routes below opaque route are offstage', (WidgetTester tester) async {
final GlobalKey<NavigatorState> g = GlobalKey<NavigatorState>();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Navigator(
key: g,
initialRoute: '/a/b',
onGenerateRoute: (RouteSettings s) {
return MaterialPageRoute<void>(
builder: (BuildContext c) {
return Text('+${s.name}+');
},
settings: s,
);
},
),
),
);
expect(find.text('+/+'), findsNothing);
expect(find.text('+/+', skipOffstage: false), findsOneWidget);
expect(find.text('+/a+'), findsNothing);
expect(find.text('+/a+', skipOffstage: false), findsOneWidget);
expect(find.text('+/a/b+'), findsOneWidget);
g.currentState.pop();
await tester.pumpAndSettle();
expect(find.text('+/+'), findsNothing);
expect(find.text('+/+', skipOffstage: false), findsOneWidget);
expect(find.text('+/a+'), findsOneWidget);
expect(find.text('+/a/b+'), findsNothing);
g.currentState.pop();
await tester.pumpAndSettle();
expect(find.text('+/+'), findsOneWidget);
expect(find.text('+/a+'), findsNothing);
expect(find.text('+/a/b+'), findsNothing);
});
testWidgets('Can provide custom onGenerateInitialRoutes', (WidgetTester tester) async {
bool onGenerateInitialRoutesCalled = false;
final GlobalKey<NavigatorState> g = GlobalKey<NavigatorState>();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Navigator(
key: g,
initialRoute: 'Hello World',
onGenerateInitialRoutes: (NavigatorState navigator, String initialRoute) {
onGenerateInitialRoutesCalled = true;
final List<Route<void>> result = <Route<void>>[];
for (final String route in initialRoute.split(' ')) {
result.add(MaterialPageRoute<void>(builder: (BuildContext context) {
return Text(route);
}));
}
return result;
},
),
),
);
expect(onGenerateInitialRoutesCalled, true);
expect(find.text('Hello'), findsNothing);
expect(find.text('World'), findsOneWidget);
g.currentState.pop();
await tester.pumpAndSettle();
expect(find.text('Hello'), findsOneWidget);
expect(find.text('World'), findsNothing);
});
testWidgets('pushAndRemove until animates the push', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/25080.
const Duration kFourTenthsOfTheTransitionDuration = Duration(milliseconds: 120);
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
final Map<String, MaterialPageRoute<dynamic>> routeNameToContext = <String, MaterialPageRoute<dynamic>>{};
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Navigator(
key: navigator,
initialRoute: 'root',
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
routeNameToContext[settings.name] = ModalRoute.of(context) as MaterialPageRoute<dynamic>;
return Text('Route: ${settings.name}');
},
);
},
),
),
);
expect(find.text('Route: root'), findsOneWidget);
navigator.currentState.pushNamed('1');
await tester.pumpAndSettle();
expect(find.text('Route: 1'), findsOneWidget);
navigator.currentState.pushNamed('2');
await tester.pumpAndSettle();
expect(find.text('Route: 2'), findsOneWidget);
navigator.currentState.pushNamed('3');
await tester.pumpAndSettle();
expect(find.text('Route: 3'), findsOneWidget);
expect(find.text('Route: 2', skipOffstage: false), findsOneWidget);
expect(find.text('Route: 1', skipOffstage: false), findsOneWidget);
expect(find.text('Route: root', skipOffstage: false), findsOneWidget);
navigator.currentState.pushNamedAndRemoveUntil('4', (Route<dynamic> route) => route.isFirst);
await tester.pump();
expect(find.text('Route: 3'), findsOneWidget);
expect(find.text('Route: 4'), findsOneWidget);
final Animation<double> route4Entry = routeNameToContext['4'].animation;
expect(route4Entry.value, 0.0); // Entry animation has not started.
await tester.pump(kFourTenthsOfTheTransitionDuration);
expect(find.text('Route: 3'), findsOneWidget);
expect(find.text('Route: 4'), findsOneWidget);
expect(route4Entry.value, 0.4);
await tester.pump(kFourTenthsOfTheTransitionDuration);
expect(find.text('Route: 3'), findsOneWidget);
expect(find.text('Route: 4'), findsOneWidget);
expect(route4Entry.value, 0.8);
expect(find.text('Route: 2', skipOffstage: false), findsOneWidget);
expect(find.text('Route: 1', skipOffstage: false), findsOneWidget);
expect(find.text('Route: root', skipOffstage: false), findsOneWidget);
// When we hit 1.0 all but root and current have been removed.
await tester.pump(kFourTenthsOfTheTransitionDuration);
expect(find.text('Route: 3', skipOffstage: false), findsNothing);
expect(find.text('Route: 4'), findsOneWidget);
expect(route4Entry.value, 1.0);
expect(find.text('Route: 2', skipOffstage: false), findsNothing);
expect(find.text('Route: 1', skipOffstage: false), findsNothing);
expect(find.text('Route: root', skipOffstage: false), findsOneWidget);
navigator.currentState.pop();
await tester.pumpAndSettle();
expect(find.text('Route: root'), findsOneWidget);
expect(find.text('Route: 4', skipOffstage: false), findsNothing);
});
}
class NoAnimationPageRoute extends PageRouteBuilder<void> {
......
......@@ -28,16 +28,15 @@ class TestRoute extends Route<String> with LocalHistoryRoute<String> {
}
@override
void install(OverlayEntry insertionPoint) {
void install() {
log('install');
final OverlayEntry entry = OverlayEntry(
builder: (BuildContext context) => Container(),
opaque: true,
);
_entries.add(entry);
navigator.overlay?.insert(entry, above: insertionPoint);
routes.add(this);
super.install(insertionPoint);
super.install();
}
@override
......@@ -46,6 +45,12 @@ class TestRoute extends Route<String> with LocalHistoryRoute<String> {
return super.didPush();
}
@override
void didAdd() {
log('didAdd');
super.didAdd();
}
@override
void didReplace(Route<dynamic> oldRoute) {
expect(oldRoute, isA<TestRoute>());
......@@ -82,8 +87,6 @@ class TestRoute extends Route<String> with LocalHistoryRoute<String> {
@override
void dispose() {
log('dispose');
for (final OverlayEntry entry in _entries)
entry.remove();
_entries.clear();
routes.remove(this);
super.dispose();
......@@ -110,10 +113,6 @@ void main() {
expect(settings, hasOneLineDescription);
final RouteSettings settings2 = settings.copyWith(name: 'B');
expect(settings2.name, 'B');
expect(settings2.isInitialRoute, false);
final RouteSettings settings3 = settings2.copyWith(isInitialRoute: true);
expect(settings3.name, 'B');
expect(settings3.isInitialRoute, true);
});
testWidgets('Route settings arguments', (WidgetTester tester) async {
......@@ -133,7 +132,7 @@ void main() {
expect(settings4.arguments, isNot(same(arguments)));
});
testWidgets('Route management - push, replace, pop', (WidgetTester tester) async {
testWidgets('Route management - push, replace, pop sequence', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
await tester.pumpWidget(
Directionality(
......@@ -151,7 +150,7 @@ void main() {
() { },
<String>[
'initial: install',
'initial: didPush',
'initial: didAdd',
'initial: didChangeNext null',
],
);
......@@ -160,7 +159,7 @@ void main() {
tester,
host,
() { host.push(second = TestRoute('second')); },
<String>[
<String>[ // stack is: initial, second
'second: install',
'second: didPush',
'second: didChangeNext null',
......@@ -171,7 +170,7 @@ void main() {
tester,
host,
() { host.push(TestRoute('third')); },
<String>[
<String>[ // stack is: initial, second, third
'third: install',
'third: didPush',
'third: didChangeNext null',
......@@ -182,7 +181,7 @@ void main() {
tester,
host,
() { host.replace(oldRoute: second, newRoute: TestRoute('two')); },
<String>[
<String>[ // stack is: initial, two, third
'two: install',
'two: didReplace second',
'two: didChangeNext third',
......@@ -194,20 +193,20 @@ void main() {
tester,
host,
() { host.pop('hello'); },
<String>[
<String>[ // stack is: initial, two
'third: didPop hello',
'third: dispose',
'two: didPopNext third',
'third: dispose',
],
);
await runNavigatorTest(
tester,
host,
() { host.pop('good bye'); },
<String>[
<String>[ // stack is: initial
'two: didPop good bye',
'two: dispose',
'initial: didPopNext two',
'two: dispose',
],
);
await tester.pumpWidget(Container());
......@@ -234,7 +233,7 @@ void main() {
() { },
<String>[
'first: install',
'first: didPush',
'first: didAdd',
'first: didChangeNext null',
],
);
......@@ -275,8 +274,8 @@ void main() {
() { host.pop('good bye'); },
<String>[
'third: didPop good bye',
'third: dispose',
'second: didPopNext third',
'third: dispose',
],
);
await runNavigatorTest(
......@@ -317,8 +316,8 @@ void main() {
() { host.pop('the end'); },
<String>[
'four: didPop the end',
'four: dispose',
'second: didPopNext four',
'four: dispose',
],
);
await tester.pumpWidget(Container());
......@@ -345,7 +344,7 @@ void main() {
() { },
<String>[
'A: install',
'A: didPush',
'A: didAdd',
'A: didChangeNext null',
],
);
......@@ -392,8 +391,8 @@ void main() {
() { host.popUntil((Route<dynamic> route) => route == routeB); },
<String>[
'C: didPop null',
'C: dispose',
'b: didPopNext C',
'C: dispose',
],
);
await tester.pumpWidget(Container());
......@@ -427,7 +426,7 @@ void main() {
() { host.popUntil((Route<dynamic> route) => !route.willHandlePopInternally); },
<String>[
'A: install',
'A: didPush',
'A: didAdd',
'A: didChangeNext null',
'A: didPop null',
'A: onRemove 1',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment