flutter/packages/unit/test/widget/routes_test.dart
Hixie 18d5c5e7ae didChangeNext()
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.
2015-12-07 15:39:56 -08:00

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();
});
});
}