page_transitions_test.dart 11.6 KB
Newer Older
1 2 3 4
// 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.

Adam Barth's avatar
Adam Barth committed
5
import 'package:flutter_test/flutter_test.dart';
6 7
import 'package:flutter/material.dart';

8
class TestOverlayRoute extends OverlayRoute<Null> {
9
  @override
10 11 12
  Iterable<OverlayEntry> createOverlayEntries() sync* {
    yield new OverlayEntry(builder: _build);
  }
13
  Widget _build(BuildContext context) => const Text('Overlay');
14 15
}

16
class PersistentBottomSheetTest extends StatefulWidget {
17
  const PersistentBottomSheetTest({ Key key }) : super(key: key);
18 19 20 21 22 23 24 25 26 27 28

  @override
  PersistentBottomSheetTestState createState() => new PersistentBottomSheetTestState();
}

class PersistentBottomSheetTestState extends State<PersistentBottomSheetTest> {
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();

  bool setStateCalled = false;

  void showBottomSheet() {
29
    _scaffoldKey.currentState.showBottomSheet<Null>((BuildContext context) {
30
      return const Text('bottomSheet');
31
    })
32
    .closed.whenComplete(() {
33 34 35 36 37 38 39 40 41 42
      setState(() {
        setStateCalled = true;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: _scaffoldKey,
43
      body: const Text('Sheet')
44 45 46 47
    );
  }
}

48
void main() {
49
  testWidgets('Check onstage/offstage handling around transitions', (WidgetTester tester) async {
50 51
    final GlobalKey containerKey1 = new GlobalKey();
    final GlobalKey containerKey2 = new GlobalKey();
52
    final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
53 54
      '/': (_) => new Container(key: containerKey1, child: const Text('Home')),
      '/settings': (_) => new Container(key: containerKey2, child: const Text('Settings')),
55
    };
56

57
    await tester.pumpWidget(new MaterialApp(routes: routes));
58

59
    expect(find.text('Home'), isOnstage);
60 61
    expect(find.text('Settings'), findsNothing);
    expect(find.text('Overlay'), findsNothing);
62

63 64 65
    expect(Navigator.canPop(containerKey1.currentContext), isFalse);
    Navigator.pushNamed(containerKey1.currentContext, '/settings');
    expect(Navigator.canPop(containerKey1.currentContext), isTrue);
66

67
    await tester.pump();
68

69 70
    expect(find.text('Home'), isOnstage);
    expect(find.text('Settings', skipOffstage: false), isOffstage);
71
    expect(find.text('Overlay'), findsNothing);
72

73
    await tester.pump(const Duration(milliseconds: 16));
74

75 76
    expect(find.text('Home'), isOnstage);
    expect(find.text('Settings'), isOnstage);
77
    expect(find.text('Overlay'), findsNothing);
78

79
    await tester.pump(const Duration(seconds: 1));
80

81
    expect(find.text('Home'), findsNothing);
82
    expect(find.text('Settings'), isOnstage);
83
    expect(find.text('Overlay'), findsNothing);
84

85
    Navigator.push(containerKey2.currentContext, new TestOverlayRoute());
86

87
    await tester.pump();
88

89
    expect(find.text('Home'), findsNothing);
90 91
    expect(find.text('Settings'), isOnstage);
    expect(find.text('Overlay'), isOnstage);
92

93
    await tester.pump(const Duration(seconds: 1));
94

95
    expect(find.text('Home'), findsNothing);
96 97
    expect(find.text('Settings'), isOnstage);
    expect(find.text('Overlay'), isOnstage);
98

99 100
    expect(Navigator.canPop(containerKey2.currentContext), isTrue);
    Navigator.pop(containerKey2.currentContext);
101
    await tester.pump();
102

103
    expect(find.text('Home'), findsNothing);
104
    expect(find.text('Settings'), isOnstage);
105
    expect(find.text('Overlay'), findsNothing);
106

107
    await tester.pump(const Duration(seconds: 1));
108

109
    expect(find.text('Home'), findsNothing);
110
    expect(find.text('Settings'), isOnstage);
111
    expect(find.text('Overlay'), findsNothing);
112

113 114
    expect(Navigator.canPop(containerKey2.currentContext), isTrue);
    Navigator.pop(containerKey2.currentContext);
115
    await tester.pump();
Hans Muller's avatar
Hans Muller committed
116
    await tester.pump();
117

118 119
    expect(find.text('Home'), isOnstage);
    expect(find.text('Settings'), isOnstage);
120
    expect(find.text('Overlay'), findsNothing);
121

122
    await tester.pump(const Duration(seconds: 1));
123

124
    expect(find.text('Home'), isOnstage);
125 126
    expect(find.text('Settings'), findsNothing);
    expect(find.text('Overlay'), findsNothing);
127

128
    expect(Navigator.canPop(containerKey1.currentContext), isFalse);
129 130
  });

131
  testWidgets('Check back gesture disables Heroes', (WidgetTester tester) async {
132 133
    final GlobalKey containerKey1 = new GlobalKey();
    final GlobalKey containerKey2 = new GlobalKey();
134 135 136 137 138
    const String kHeroTag = 'hero';
    final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
      '/': (_) => new Scaffold(
        key: containerKey1,
        body: new Container(
139
          color: const Color(0xff00ffff),
140
          child: const Hero(
141
            tag: kHeroTag,
142
            child: const Text('Home')
143 144 145 146 147 148 149
          )
        )
      ),
      '/settings': (_) => new Scaffold(
        key: containerKey2,
        body: new Container(
          padding: const EdgeInsets.all(100.0),
150
          color: const Color(0xffff00ff),
151
          child: const Hero(
152
            tag: kHeroTag,
153
            child: const Text('Settings')
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
          )
        )
      ),
    };

    await tester.pumpWidget(new MaterialApp(
      routes: routes,
      theme: new ThemeData(platform: TargetPlatform.iOS),
    ));

    Navigator.pushNamed(containerKey1.currentContext, '/settings');

    await tester.pump();
    await tester.pump(const Duration(milliseconds: 16));

    expect(find.text('Settings'), isOnstage);

    // Settings text is heroing to its new location
172 173 174 175 176
    Offset settingsOffset = tester.getTopLeft(find.text('Settings'));
    expect(settingsOffset.dx, greaterThan(0.0));
    expect(settingsOffset.dx, lessThan(100.0));
    expect(settingsOffset.dy, greaterThan(0.0));
    expect(settingsOffset.dy, lessThan(100.0));
177 178 179 180 181 182 183

    await tester.pump(const Duration(seconds: 1));

    expect(find.text('Home'), findsNothing);
    expect(find.text('Settings'), isOnstage);

    // Drag from left edge to invoke the gesture.
184
    final TestGesture gesture = await tester.startGesture(const Offset(5.0, 100.0));
185
    await gesture.moveBy(const Offset(50.0, 0.0));
186 187 188 189 190 191 192
    await tester.pump();

    // Home is now visible.
    expect(find.text('Home'), isOnstage);
    expect(find.text('Settings'), isOnstage);

    // Home page is sliding in from the left, no heroes.
193 194 195
    final Offset homeOffset = tester.getTopLeft(find.text('Home'));
    expect(homeOffset.dx, lessThan(0.0));
    expect(homeOffset.dy, 0.0);
196 197 198

    // Settings page is sliding off to the right, no heroes.
    settingsOffset = tester.getTopLeft(find.text('Settings'));
199 200
    expect(settingsOffset.dx, greaterThan(100.0));
    expect(settingsOffset.dy, 100.0);
201
  });
202 203

  testWidgets('Check back gesture doesnt start during transitions', (WidgetTester tester) async {
204 205
    final GlobalKey containerKey1 = new GlobalKey();
    final GlobalKey containerKey2 = new GlobalKey();
206
    final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
207 208
      '/': (_) => new Scaffold(key: containerKey1, body: const Text('Home')),
      '/settings': (_) => new Scaffold(key: containerKey2, body: const Text('Settings')),
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
    };

    await tester.pumpWidget(new MaterialApp(
      routes: routes,
      theme: new ThemeData(platform: TargetPlatform.iOS),
    ));

    Navigator.pushNamed(containerKey1.currentContext, '/settings');

    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    // We are mid-transition, both pages are on stage.
    expect(find.text('Home'), isOnstage);
    expect(find.text('Settings'), isOnstage);

    // Drag from left edge to invoke the gesture. (near bottom so we grab
    // the Settings page as it comes up).
227
    TestGesture gesture = await tester.startGesture(const Offset(5.0, 550.0));
228
    await gesture.moveBy(const Offset(500.0, 0.0));
229 230 231 232 233 234 235 236 237 238
    await gesture.up();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 1000));

    // The original forward navigation should have completed, instead of the
    // back gesture, since we were mid transition.
    expect(find.text('Home'), findsNothing);
    expect(find.text('Settings'), isOnstage);

    // Try again now that we're settled.
239
    gesture = await tester.startGesture(const Offset(5.0, 550.0));
240
    await gesture.moveBy(const Offset(500.0, 0.0));
241 242 243 244 245 246 247
    await gesture.up();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 1000));

    expect(find.text('Home'), isOnstage);
    expect(find.text('Settings'), findsNothing);
  });
248 249 250

  // Tests bug https://github.com/flutter/flutter/issues/6451
  testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async {
251 252
    final GlobalKey containerKey1 = new GlobalKey();
    final GlobalKey containerKey2 = new GlobalKey();
253
    final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
254
      '/': (_) => new Scaffold(key: containerKey1, body: const Text('Home')),
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
      '/sheet': (_) => new PersistentBottomSheetTest(key: containerKey2),
    };

    await tester.pumpWidget(new MaterialApp(
      routes: routes,
      theme: new ThemeData(platform: TargetPlatform.iOS),
    ));

    Navigator.pushNamed(containerKey1.currentContext, '/sheet');

    await tester.pump();
    await tester.pump(const Duration(seconds: 1));

    expect(find.text('Home'), findsNothing);
    expect(find.text('Sheet'), isOnstage);

    // Show the bottom sheet.
272
    final PersistentBottomSheetTestState sheet = containerKey2.currentState;
273 274 275 276 277
    sheet.showBottomSheet();

    await tester.pump(const Duration(seconds: 1));

    // Drag from left edge to invoke the gesture.
278
    final TestGesture gesture = await tester.startGesture(const Offset(5.0, 100.0));
279
    await gesture.moveBy(const Offset(500.0, 0.0));
280 281 282 283 284 285 286 287 288 289
    await gesture.up();
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));

    expect(find.text('Home'), isOnstage);
    expect(find.text('Sheet'), findsNothing);

    // Sheet called setState and didn't crash.
    expect(sheet.setStateCalled, isTrue);
  });
290 291 292

  testWidgets('Test completed future', (WidgetTester tester) async {
    final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
293 294
      '/': (_) => const Center(child: const Text('home')),
      '/next': (_) => const Center(child: const Text('next')),
295 296 297 298
    };

    await tester.pumpWidget(new MaterialApp(routes: routes));

299
    final PageRoute<Null> route = new MaterialPageRoute<Null>(
300
      settings: const RouteSettings(name: '/page'),
301
      builder: (BuildContext context) => const Center(child: const Text('page')),
302 303 304
    );

    int popCount = 0;
305 306
    route.popped.whenComplete(() {
      popCount += 1;
307 308 309
    });

    int completeCount = 0;
310 311
    route.completed.whenComplete(() {
      completeCount += 1;
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    });

    expect(popCount, 0);
    expect(completeCount, 0);

    Navigator.push(tester.element(find.text('home')), route);

    expect(popCount, 0);
    expect(completeCount, 0);

    await tester.pump();

    expect(popCount, 0);
    expect(completeCount, 0);

    await tester.pump(const Duration(milliseconds: 100));

    expect(popCount, 0);
    expect(completeCount, 0);

    await tester.pump(const Duration(milliseconds: 100));

    expect(popCount, 0);
    expect(completeCount, 0);

    await tester.pump(const Duration(seconds: 1));

    expect(popCount, 0);
    expect(completeCount, 0);

    Navigator.pop(tester.element(find.text('page')));

    expect(popCount, 0);
    expect(completeCount, 0);

    await tester.pump();

    expect(popCount, 1);
    expect(completeCount, 0);

    await tester.pump(const Duration(milliseconds: 100));

    expect(popCount, 1);
    expect(completeCount, 0);

    await tester.pump(const Duration(milliseconds: 100));

    expect(popCount, 1);
    expect(completeCount, 0);

    await tester.pump(const Duration(seconds: 1));

    expect(popCount, 1);
    expect(completeCount, 1);
  });
367
}