page_forward_transitions_test.dart 8.01 KB
Newer Older
Hixie's avatar
Hixie committed
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.

5
import 'package:flutter_test/flutter_test.dart' hide TypeMatcher;
Hixie's avatar
Hixie committed
6
import 'package:flutter/material.dart';
7
import 'package:flutter/rendering.dart';
Hixie's avatar
Hixie committed
8

9
class TestTransition extends AnimatedWidget {
10
  const TestTransition({
Hixie's avatar
Hixie committed
11 12 13
    Key key,
    this.childFirstHalf,
    this.childSecondHalf,
14
    Animation<double> animation
15
  }) : super(key: key, listenable: animation);
Hixie's avatar
Hixie committed
16 17 18 19

  final Widget childFirstHalf;
  final Widget childSecondHalf;

20
  @override
Hixie's avatar
Hixie committed
21
  Widget build(BuildContext context) {
22
    final Animation<double> animation = listenable;
23
    if (animation.value >= 0.5)
Hixie's avatar
Hixie committed
24 25 26 27 28
      return childSecondHalf;
    return childFirstHalf;
  }
}

29
class TestRoute<T> extends PageRoute<T> {
30
  TestRoute({ this.child, RouteSettings settings, this.barrierColor }) : super(settings: settings);
31

32
  final Widget child;
33 34

  @override
35
  Duration get transitionDuration => const Duration(milliseconds: 150);
36 37

  @override
38
  final Color barrierColor;
39

40 41 42
  @override
  String get barrierLabel => null;

43 44 45
  @override
  bool get maintainState => false;

46
  @override
47
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
48 49
    return child;
  }
50 51
}

Hixie's avatar
Hixie committed
52
void main() {
53 54
  const Duration kTwoTenthsOfTheTransitionDuration = const Duration(milliseconds: 30);
  const Duration kFourTenthsOfTheTransitionDuration = const Duration(milliseconds: 60);
Hixie's avatar
Hixie committed
55

56
  testWidgets('Check onstage/offstage handling around transitions', (WidgetTester tester) async {
57

58
    final GlobalKey insideKey = new GlobalKey();
59

60
    String state({ bool skipOffstage: true }) {
61
      String result = '';
62
      if (tester.any(find.text('A', skipOffstage: skipOffstage)))
63
        result += 'A';
64
      if (tester.any(find.text('B', skipOffstage: skipOffstage)))
65
        result += 'B';
66
      if (tester.any(find.text('C', skipOffstage: skipOffstage)))
67
        result += 'C';
68
      if (tester.any(find.text('D', skipOffstage: skipOffstage)))
69
        result += 'D';
70
      if (tester.any(find.text('E', skipOffstage: skipOffstage)))
71
        result += 'E';
72
      if (tester.any(find.text('F', skipOffstage: skipOffstage)))
73
        result += 'F';
74
      if (tester.any(find.text('G', skipOffstage: skipOffstage)))
75 76 77 78
        result += 'G';
      return result;
    }

79
    await tester.pumpWidget(
80 81 82 83 84 85 86 87 88
      new MaterialApp(
        onGenerateRoute: (RouteSettings settings) {
          switch (settings.name) {
            case '/':
              return new TestRoute<Null>(
                settings: settings,
                child: new Builder(
                  key: insideKey,
                  builder: (BuildContext context) {
89
                    final PageRoute<Null> route = ModalRoute.of(context);
90 91 92
                    return new Column(
                      children: <Widget>[
                        new TestTransition(
93 94
                          childFirstHalf: const Text('A'),
                          childSecondHalf: const Text('B'),
95 96 97
                          animation: route.animation
                        ),
                        new TestTransition(
98 99
                          childFirstHalf: const Text('C'),
                          childSecondHalf: const Text('D'),
100
                          animation: route.secondaryAnimation
101 102 103 104 105 106
                        ),
                      ]
                    );
                  }
                )
              );
107 108 109
            case '/2': return new TestRoute<Null>(settings: settings, child: const Text('E'));
            case '/3': return new TestRoute<Null>(settings: settings, child: const Text('F'));
            case '/4': return new TestRoute<Null>(settings: settings, child: const Text('G'));
Hixie's avatar
Hixie committed
110
          }
111 112 113
        }
      )
    );
Hixie's avatar
Hixie committed
114

115
    final NavigatorState navigator = insideKey.currentContext.ancestorStateOfType(const TypeMatcher<NavigatorState>());
Hixie's avatar
Hixie committed
116

117
    expect(state(), equals('BC')); // transition ->1 is at 1.0
Hixie's avatar
Hixie committed
118

119
    navigator.pushNamed('/2');
120
    expect(state(), equals('BC')); // transition 1->2 is not yet built
121
    await tester.pump();
122 123
    expect(state(), equals('BC')); // transition 1->2 is at 0.0
    expect(state(skipOffstage: false), equals('BCE')); // E is offstage
Hixie's avatar
Hixie committed
124

125
    await tester.pump(kFourTenthsOfTheTransitionDuration);
126
    expect(state(), equals('BCE')); // transition 1->2 is at 0.4
Hixie's avatar
Hixie committed
127

128
    await tester.pump(kFourTenthsOfTheTransitionDuration);
129
    expect(state(), equals('BDE')); // transition 1->2 is at 0.8
Hixie's avatar
Hixie committed
130

131
    await tester.pump(kFourTenthsOfTheTransitionDuration);
132
    expect(state(), equals('E')); // transition 1->2 is at 1.0
133
    expect(state(skipOffstage: false), equals('E')); // B and C are gone, the route is inactive with maintainState=false
Hixie's avatar
Hixie committed
134

135
    navigator.pop();
136
    expect(state(), equals('E')); // transition 1<-2 is at 1.0, just reversed
137
    await tester.pump();
Hans Muller's avatar
Hans Muller committed
138 139
    await tester.pump();

140
    expect(state(), equals('BDE')); // transition 1<-2 is at 1.0
Hixie's avatar
Hixie committed
141

142
    await tester.pump(kFourTenthsOfTheTransitionDuration);
143
    expect(state(), equals('BDE')); // transition 1<-2 is at 0.6
Hixie's avatar
Hixie committed
144

145
    navigator.pushNamed('/3');
146
    expect(state(), equals('BDE')); // transition 1<-2 is at 0.6
147
    await tester.pump();
148 149
    expect(state(), equals('BDE')); // transition 1<-2 is at 0.6, 1->3 is at 0.0
    expect(state(skipOffstage: false), equals('BDEF')); // F is offstage since we're at 0.0
Hixie's avatar
Hixie committed
150

151
    await tester.pump(kFourTenthsOfTheTransitionDuration);
152
    expect(state(), equals('BCEF')); // transition 1<-2 is at 0.2, 1->3 is at 0.4
153
    expect(state(skipOffstage: false), equals('BCEF')); // nothing secret going on here
Hixie's avatar
Hixie committed
154

155
    await tester.pump(kFourTenthsOfTheTransitionDuration);
156
    expect(state(), equals('BDF')); // transition 1<-2 is done, 1->3 is at 0.8
Hixie's avatar
Hixie committed
157

158
    navigator.pop();
159
    expect(state(), equals('BDF')); // transition 1<-3 is at 0.8, just reversed
160
    await tester.pump();
161
    expect(state(), equals('BDF')); // transition 1<-3 is at 0.8
Hixie's avatar
Hixie committed
162

163
    await tester.pump(kTwoTenthsOfTheTransitionDuration); // notice that dT=0.2 here, not 0.4
164
    expect(state(), equals('BDF')); // transition 1<-3 is at 0.6
Hixie's avatar
Hixie committed
165

166
    await tester.pump(kFourTenthsOfTheTransitionDuration);
167
    expect(state(), equals('BCF')); // transition 1<-3 is at 0.2
Hixie's avatar
Hixie committed
168

169
    navigator.pushNamed('/4');
170
    expect(state(), equals('BCF')); // transition 1<-3 is at 0.2, 1->4 is not yet built
171
    await tester.pump();
172 173
    expect(state(), equals('BCF')); // transition 1<-3 is at 0.2, 1->4 is at 0.0
    expect(state(skipOffstage: false), equals('BCFG')); // G is offstage
Hixie's avatar
Hixie committed
174

175
    await tester.pump(kFourTenthsOfTheTransitionDuration);
176
    expect(state(), equals('BCG')); // transition 1<-3 is done, 1->4 is at 0.4
Hixie's avatar
Hixie committed
177

178
    await tester.pump(kFourTenthsOfTheTransitionDuration);
179
    expect(state(), equals('BDG')); // transition 1->4 is at 0.8
Hixie's avatar
Hixie committed
180

181
    await tester.pump(kFourTenthsOfTheTransitionDuration);
182
    expect(state(), equals('G')); // transition 1->4 is done
183
    expect(state(skipOffstage: false), equals('G')); // route 1 is not around any more
Hixie's avatar
Hixie committed
184 185

  });
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

  testWidgets('Check onstage/offstage handling of barriers around transitions', (WidgetTester tester) async {
    await tester.pumpWidget(
      new MaterialApp(
        onGenerateRoute: (RouteSettings settings) {
          switch (settings.name) {
            case '/': return new TestRoute<Null>(settings: settings, child: const Text('A'));
            case '/1': return new TestRoute<Null>(settings: settings, barrierColor: const Color(0xFFFFFF00), child: const Text('B'));
          }
        }
      )
    );
    expect(find.byType(ModalBarrier), findsOneWidget);

    tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/1');
    expect(find.byType(ModalBarrier), findsOneWidget);

    await tester.pump();
    expect(find.byType(ModalBarrier), findsNWidgets(2));
    expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).first).color, isNull);
    expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, isNull);

    await tester.pump(const Duration(seconds: 1));
    expect(find.byType(ModalBarrier), findsOneWidget);
    expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier)).color, const Color(0xFFFFFF00));

  });
Hixie's avatar
Hixie committed
213
}