mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
These futures complete when the route is popped off the navigator. This generalizes and simplifies a mechanism already in place for dialogs and menus. Fixes #5283
390 lines
9.4 KiB
Dart
390 lines
9.4 KiB
Dart
// Copyright 2015 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:collection';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:meta/meta.dart';
|
|
|
|
final List<String> results = <String>[];
|
|
|
|
Set<TestRoute> routes = new HashSet<TestRoute>();
|
|
|
|
class TestRoute extends LocalHistoryRoute<String> {
|
|
TestRoute(this.name);
|
|
final String name;
|
|
|
|
@override
|
|
List<OverlayEntry> get overlayEntries => _entries;
|
|
|
|
List<OverlayEntry> _entries = <OverlayEntry>[];
|
|
|
|
void log(String s) {
|
|
results.add('$name: $s');
|
|
}
|
|
|
|
@override
|
|
void install(OverlayEntry insertionPoint) {
|
|
log('install');
|
|
OverlayEntry entry = new OverlayEntry(
|
|
builder: (BuildContext context) => new Container(),
|
|
opaque: true
|
|
);
|
|
_entries.add(entry);
|
|
navigator.overlay?.insert(entry, above: insertionPoint);
|
|
routes.add(this);
|
|
super.install(insertionPoint);
|
|
}
|
|
|
|
@override
|
|
void didPush() {
|
|
log('didPush');
|
|
super.didPush();
|
|
}
|
|
|
|
@override
|
|
void didReplace(@checked TestRoute oldRoute) {
|
|
log('didReplace ${oldRoute.name}');
|
|
super.didReplace(oldRoute);
|
|
}
|
|
|
|
@override
|
|
bool didPop(String result) {
|
|
log('didPop $result');
|
|
bool returnValue;
|
|
if (returnValue = super.didPop(result))
|
|
dispose();
|
|
return returnValue;
|
|
}
|
|
|
|
@override
|
|
void didPopNext(@checked TestRoute nextRoute) {
|
|
log('didPopNext ${nextRoute.name}');
|
|
super.didPopNext(nextRoute);
|
|
}
|
|
|
|
@override
|
|
void didChangeNext(@checked TestRoute nextRoute) {
|
|
log('didChangeNext ${nextRoute?.name}');
|
|
super.didChangeNext(nextRoute);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
log('dispose');
|
|
_entries.forEach((OverlayEntry entry) { entry.remove(); });
|
|
_entries.clear();
|
|
routes.remove(this);
|
|
super.dispose();
|
|
}
|
|
|
|
}
|
|
|
|
Future<Null> runNavigatorTest(
|
|
WidgetTester tester,
|
|
NavigatorState host,
|
|
VoidCallback test,
|
|
List<String> expectations
|
|
) async {
|
|
expect(host, isNotNull);
|
|
test();
|
|
expect(results, equals(expectations));
|
|
results.clear();
|
|
await tester.pump();
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('Route management - push, replace, pop', (WidgetTester tester) async {
|
|
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
|
await tester.pumpWidget(new Navigator(
|
|
key: navigatorKey,
|
|
onGenerateRoute: (_) => new TestRoute('initial')
|
|
));
|
|
NavigatorState host = navigatorKey.currentState;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { },
|
|
<String>[
|
|
'initial: install',
|
|
'initial: didPush',
|
|
'initial: didChangeNext null',
|
|
]
|
|
);
|
|
TestRoute second;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(second = new TestRoute('second')); },
|
|
<String>[
|
|
'second: install',
|
|
'second: didPush',
|
|
'second: didChangeNext null',
|
|
'initial: didChangeNext second',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(new TestRoute('third')); },
|
|
<String>[
|
|
'third: install',
|
|
'third: didPush',
|
|
'third: didChangeNext null',
|
|
'second: didChangeNext third',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.replace(oldRoute: second, newRoute: new TestRoute('two')); },
|
|
<String>[
|
|
'two: install',
|
|
'two: didReplace second',
|
|
'two: didChangeNext third',
|
|
'initial: didChangeNext two',
|
|
'second: dispose',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.pop('hello'); },
|
|
<String>[
|
|
'third: didPop hello',
|
|
'third: dispose',
|
|
'two: didPopNext third',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.pop('good bye'); },
|
|
<String>[
|
|
'two: didPop good bye',
|
|
'two: dispose',
|
|
'initial: didPopNext two',
|
|
]
|
|
);
|
|
await tester.pumpWidget(new Container());
|
|
expect(results, equals(<String>['initial: dispose']));
|
|
expect(routes.isEmpty, isTrue);
|
|
results.clear();
|
|
});
|
|
|
|
testWidgets('Route management - push, remove, pop', (WidgetTester tester) async {
|
|
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
|
await tester.pumpWidget(new Navigator(
|
|
key: navigatorKey,
|
|
onGenerateRoute: (_) => new TestRoute('first')
|
|
));
|
|
NavigatorState host = navigatorKey.currentState;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { },
|
|
<String>[
|
|
'first: install',
|
|
'first: didPush',
|
|
'first: didChangeNext null',
|
|
]
|
|
);
|
|
TestRoute second;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(second = new TestRoute('second')); },
|
|
<String>[
|
|
'second: install',
|
|
'second: didPush',
|
|
'second: didChangeNext null',
|
|
'first: didChangeNext second',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(new TestRoute('third')); },
|
|
<String>[
|
|
'third: install',
|
|
'third: didPush',
|
|
'third: didChangeNext null',
|
|
'second: didChangeNext third',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.removeRouteBelow(second); },
|
|
<String>[
|
|
'first: dispose',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.pop('good bye'); },
|
|
<String>[
|
|
'third: didPop good bye',
|
|
'third: dispose',
|
|
'second: didPopNext third',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(new TestRoute('three')); },
|
|
<String>[
|
|
'three: install',
|
|
'three: didPush',
|
|
'three: didChangeNext null',
|
|
'second: didChangeNext three',
|
|
]
|
|
);
|
|
TestRoute four;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(four = new TestRoute('four')); },
|
|
<String>[
|
|
'four: install',
|
|
'four: didPush',
|
|
'four: didChangeNext null',
|
|
'three: didChangeNext four',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.removeRouteBelow(four); },
|
|
<String>[
|
|
'second: didChangeNext four',
|
|
'three: dispose',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.pop('the end'); },
|
|
<String>[
|
|
'four: didPop the end',
|
|
'four: dispose',
|
|
'second: didPopNext four',
|
|
]
|
|
);
|
|
await tester.pumpWidget(new Container());
|
|
expect(results, equals(<String>['second: dispose']));
|
|
expect(routes.isEmpty, isTrue);
|
|
results.clear();
|
|
});
|
|
|
|
testWidgets('Route management - push, replace, popUntil', (WidgetTester tester) async {
|
|
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
|
await tester.pumpWidget(new Navigator(
|
|
key: navigatorKey,
|
|
onGenerateRoute: (_) => new TestRoute('A')
|
|
));
|
|
NavigatorState host = navigatorKey.currentState;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { },
|
|
<String>[
|
|
'A: install',
|
|
'A: didPush',
|
|
'A: didChangeNext null',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(new TestRoute('B')); },
|
|
<String>[
|
|
'B: install',
|
|
'B: didPush',
|
|
'B: didChangeNext null',
|
|
'A: didChangeNext B',
|
|
]
|
|
);
|
|
TestRoute routeC;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.push(routeC = new TestRoute('C')); },
|
|
<String>[
|
|
'C: install',
|
|
'C: didPush',
|
|
'C: didChangeNext null',
|
|
'B: didChangeNext C',
|
|
]
|
|
);
|
|
TestRoute routeB;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.replaceRouteBelow(anchorRoute: routeC, newRoute: routeB = new TestRoute('b')); },
|
|
<String>[
|
|
'b: install',
|
|
'b: didReplace B',
|
|
'b: didChangeNext C',
|
|
'A: didChangeNext b',
|
|
'B: dispose',
|
|
]
|
|
);
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.popUntil((Route<dynamic> route) => route == routeB); },
|
|
<String>[
|
|
'C: didPop null',
|
|
'C: dispose',
|
|
'b: didPopNext C',
|
|
]
|
|
);
|
|
await tester.pumpWidget(new Container());
|
|
expect(results, equals(<String>['A: dispose', 'b: dispose']));
|
|
expect(routes.isEmpty, isTrue);
|
|
results.clear();
|
|
});
|
|
|
|
testWidgets('Route localHistory - popUntil', (WidgetTester tester) async {
|
|
TestRoute routeA = new TestRoute('A');
|
|
routeA.addLocalHistoryEntry(new LocalHistoryEntry(
|
|
onRemove: () { routeA.log('onRemove 0'); }
|
|
));
|
|
routeA.addLocalHistoryEntry(new LocalHistoryEntry(
|
|
onRemove: () { routeA.log('onRemove 1'); }
|
|
));
|
|
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
|
await tester.pumpWidget(new Navigator(
|
|
key: navigatorKey,
|
|
onGenerateRoute: (_) => routeA
|
|
));
|
|
NavigatorState host = navigatorKey.currentState;
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.popUntil((Route<dynamic> route) => !route.willHandlePopInternally); },
|
|
<String>[
|
|
'A: install',
|
|
'A: didPush',
|
|
'A: didChangeNext null',
|
|
'A: didPop null',
|
|
'A: onRemove 1',
|
|
'A: didPop null',
|
|
'A: onRemove 0',
|
|
]
|
|
);
|
|
|
|
await runNavigatorTest(
|
|
tester,
|
|
host,
|
|
() { host.popUntil((Route<dynamic> route) => !route.willHandlePopInternally); },
|
|
<String>[
|
|
]
|
|
);
|
|
});
|
|
}
|