
Replace didPushNext() and didReplaceNext() with didChangeNext(), and call it in more cases, so that a route can easily track the next route. Use this to make TransitionRoute properly track its next route so that you can do next-route-driven animations that work even with removes, replaces, and other crazy manipulations of the navigator stack.
379 lines
9.3 KiB
Dart
379 lines
9.3 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 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
final List<String> results = <String>[];
|
|
|
|
Set<TestRoute> routes = new Set<TestRoute>();
|
|
|
|
class TestRoute extends Route<String> {
|
|
TestRoute(this.name);
|
|
final String name;
|
|
|
|
List<OverlayEntry> get overlayEntries => _entries;
|
|
|
|
List<OverlayEntry> _entries = <OverlayEntry>[];
|
|
|
|
void log(String s) {
|
|
results.add('$name: $s');
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void didPush() {
|
|
log('didPush');
|
|
}
|
|
|
|
void didReplace(TestRoute oldRoute) {
|
|
log('didReplace ${oldRoute.name}');
|
|
}
|
|
|
|
bool didPop(String result) {
|
|
log('didPop $result');
|
|
bool returnValue;
|
|
if (returnValue = super.didPop(result))
|
|
dispose();
|
|
return returnValue;
|
|
}
|
|
|
|
void didPopNext(TestRoute nextRoute) {
|
|
log('didPopNext ${nextRoute.name}');
|
|
}
|
|
|
|
void didChangeNext(TestRoute nextRoute) {
|
|
log('didChangeNext ${nextRoute?.name}');
|
|
}
|
|
|
|
void dispose() {
|
|
log('dispose');
|
|
_entries.forEach((OverlayEntry entry) { entry.remove(); });
|
|
_entries.clear();
|
|
routes.remove(this);
|
|
}
|
|
|
|
}
|
|
|
|
void runNavigatorTest(
|
|
WidgetTester tester,
|
|
NavigatorState host,
|
|
NavigatorTransactionCallback test,
|
|
List<String> expectations
|
|
) {
|
|
expect(host, isNotNull);
|
|
host.openTransaction(test);
|
|
expect(results, equals(expectations));
|
|
results.clear();
|
|
tester.pump();
|
|
}
|
|
|
|
void main() {
|
|
test('Route management - push, replace, pop', () {
|
|
testWidgets((WidgetTester tester) {
|
|
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
|
tester.pumpWidget(new Navigator(
|
|
key: navigatorKey,
|
|
onGenerateRoute: (_) => new TestRoute('initial')
|
|
));
|
|
NavigatorState host = navigatorKey.currentState;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
},
|
|
[
|
|
'initial: install',
|
|
'initial: didPush',
|
|
'initial: didChangeNext null',
|
|
]
|
|
);
|
|
TestRoute second;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(second = new TestRoute('second'));
|
|
},
|
|
[
|
|
'second: install',
|
|
'second: didPush',
|
|
'second: didChangeNext null',
|
|
'initial: didChangeNext second',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(new TestRoute('third'));
|
|
},
|
|
[
|
|
'third: install',
|
|
'third: didPush',
|
|
'third: didChangeNext null',
|
|
'second: didChangeNext third',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.replace(oldRoute: second, newRoute: new TestRoute('two'));
|
|
},
|
|
[
|
|
'two: install',
|
|
'two: didReplace second',
|
|
'two: didChangeNext third',
|
|
'initial: didChangeNext two',
|
|
'second: dispose',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.pop('hello');
|
|
},
|
|
[
|
|
'third: didPop hello',
|
|
'third: dispose',
|
|
'two: didPopNext third',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.pop('good bye');
|
|
},
|
|
[
|
|
'two: didPop good bye',
|
|
'two: dispose',
|
|
'initial: didPopNext two',
|
|
]
|
|
);
|
|
tester.pumpWidget(new Container());
|
|
expect(results, equals(['initial: dispose']));
|
|
expect(routes.isEmpty, isTrue);
|
|
results.clear();
|
|
});
|
|
});
|
|
|
|
test('Route management - push, remove, pop', () {
|
|
testWidgets((WidgetTester tester) {
|
|
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
|
tester.pumpWidget(new Navigator(
|
|
key: navigatorKey,
|
|
onGenerateRoute: (_) => new TestRoute('first')
|
|
));
|
|
NavigatorState host = navigatorKey.currentState;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
},
|
|
[
|
|
'first: install',
|
|
'first: didPush',
|
|
'first: didChangeNext null',
|
|
]
|
|
);
|
|
TestRoute second;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(second = new TestRoute('second'));
|
|
},
|
|
[
|
|
'second: install',
|
|
'second: didPush',
|
|
'second: didChangeNext null',
|
|
'first: didChangeNext second',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(new TestRoute('third'));
|
|
},
|
|
[
|
|
'third: install',
|
|
'third: didPush',
|
|
'third: didChangeNext null',
|
|
'second: didChangeNext third',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.removeRouteBefore(second);
|
|
},
|
|
[
|
|
'first: dispose',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.pop('good bye');
|
|
},
|
|
[
|
|
'third: didPop good bye',
|
|
'third: dispose',
|
|
'second: didPopNext third',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(new TestRoute('three'));
|
|
},
|
|
[
|
|
'three: install',
|
|
'three: didPush',
|
|
'three: didChangeNext null',
|
|
'second: didChangeNext three',
|
|
]
|
|
);
|
|
TestRoute four;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(four = new TestRoute('four'));
|
|
},
|
|
[
|
|
'four: install',
|
|
'four: didPush',
|
|
'four: didChangeNext null',
|
|
'three: didChangeNext four',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.removeRouteBefore(four);
|
|
},
|
|
[
|
|
'second: didChangeNext four',
|
|
'three: dispose',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.pop('the end');
|
|
},
|
|
[
|
|
'four: didPop the end',
|
|
'four: dispose',
|
|
'second: didPopNext four',
|
|
]
|
|
);
|
|
tester.pumpWidget(new Container());
|
|
expect(results, equals(['second: dispose']));
|
|
expect(routes.isEmpty, isTrue);
|
|
results.clear();
|
|
});
|
|
});
|
|
|
|
test('Route management - push, replace, popUntil', () {
|
|
testWidgets((WidgetTester tester) {
|
|
GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
|
|
tester.pumpWidget(new Navigator(
|
|
key: navigatorKey,
|
|
onGenerateRoute: (_) => new TestRoute('A')
|
|
));
|
|
NavigatorState host = navigatorKey.currentState;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
},
|
|
[
|
|
'A: install',
|
|
'A: didPush',
|
|
'A: didChangeNext null',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(new TestRoute('B'));
|
|
},
|
|
[
|
|
'B: install',
|
|
'B: didPush',
|
|
'B: didChangeNext null',
|
|
'A: didChangeNext B',
|
|
]
|
|
);
|
|
TestRoute routeC;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.push(routeC = new TestRoute('C'));
|
|
},
|
|
[
|
|
'C: install',
|
|
'C: didPush',
|
|
'C: didChangeNext null',
|
|
'B: didChangeNext C',
|
|
]
|
|
);
|
|
TestRoute routeB;
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.replaceRouteBefore(anchorRoute: routeC, newRoute: routeB = new TestRoute('b'));
|
|
},
|
|
[
|
|
'b: install',
|
|
'b: didReplace B',
|
|
'b: didChangeNext C',
|
|
'A: didChangeNext b',
|
|
'B: dispose',
|
|
]
|
|
);
|
|
runNavigatorTest(
|
|
tester,
|
|
host,
|
|
(NavigatorTransaction transaction) {
|
|
transaction.popUntil(routeB);
|
|
},
|
|
[
|
|
'C: didPop null',
|
|
'C: dispose',
|
|
'b: didPopNext C',
|
|
]
|
|
);
|
|
tester.pumpWidget(new Container());
|
|
expect(results, equals(['A: dispose', 'b: dispose']));
|
|
expect(routes.isEmpty, isTrue);
|
|
results.clear();
|
|
});
|
|
});
|
|
}
|