page_test.dart 12.3 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2017 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/cupertino.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
Ian Hickson's avatar
Ian Hickson committed
9
  testWidgets('test iOS page transition (LTR)', (WidgetTester tester) async {
10
    await tester.pumpWidget(
11
      CupertinoApp(
12
        onGenerateRoute: (RouteSettings settings) {
13
          return CupertinoPageRoute<void>(
14 15
            settings: settings,
            builder: (BuildContext context) {
Ian Hickson's avatar
Ian Hickson committed
16
              final String pageNumber = settings.name == '/' ? '1' : '2';
17
              return Center(child: Text('Page $pageNumber'));
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
            }
          );
        },
      ),
    );

    final Offset widget1InitialTopLeft = tester.getTopLeft(find.text('Page 1'));

    tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');

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

    Offset widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
    Offset widget2TopLeft = tester.getTopLeft(find.text('Page 2'));

    // Page 1 is moving to the left.
35
    expect(widget1TransientTopLeft.dx, lessThan(widget1InitialTopLeft.dx));
36
    // Page 1 isn't moving vertically.
37
    expect(widget1TransientTopLeft.dy, equals(widget1InitialTopLeft.dy));
38
    // iOS transition is horizontal only.
39
    expect(widget1InitialTopLeft.dy, equals(widget2TopLeft.dy));
40
    // Page 2 is coming in from the right.
41
    expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

    await tester.pumpAndSettle();

    // Page 2 covers page 1.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    tester.state<NavigatorState>(find.byType(Navigator)).pop();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
    widget2TopLeft = tester.getTopLeft(find.text('Page 2'));

    // Page 1 is coming back from the left.
57
    expect(widget1TransientTopLeft.dx, lessThan(widget1InitialTopLeft.dx));
58
    // Page 1 isn't moving vertically.
59
    expect(widget1TransientTopLeft.dy, equals(widget1InitialTopLeft.dy));
60
    // iOS transition is horizontal only.
61
    expect(widget1InitialTopLeft.dy, equals(widget2TopLeft.dy));
62
    // Page 2 is leaving towards the right.
63
    expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
64 65 66 67 68 69 70 71 72

    await tester.pumpAndSettle();

    expect(find.text('Page 1'), isOnstage);
    expect(find.text('Page 2'), findsNothing);

    widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));

    // Page 1 is back where it started.
73
    expect(widget1InitialTopLeft, equals(widget1TransientTopLeft));
74 75
  });

Ian Hickson's avatar
Ian Hickson committed
76 77
  testWidgets('test iOS page transition (RTL)', (WidgetTester tester) async {
    await tester.pumpWidget(
78
      CupertinoApp(
79
        localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
80
          RtlOverrideWidgetsDelegate(),
Ian Hickson's avatar
Ian Hickson committed
81 82
        ],
        onGenerateRoute: (RouteSettings settings) {
83
          return CupertinoPageRoute<void>(
Ian Hickson's avatar
Ian Hickson committed
84 85 86
            settings: settings,
            builder: (BuildContext context) {
              final String pageNumber = settings.name == '/' ? '1' : '2';
87
              return Center(child: Text('Page $pageNumber'));
Ian Hickson's avatar
Ian Hickson committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
            }
          );
        },
      ),
    );
    await tester.pump(); // to load the localization, since it doesn't use a synchronous future

    final Offset widget1InitialTopLeft = tester.getTopLeft(find.text('Page 1'));

    tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');

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

    Offset widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
    Offset widget2TopLeft = tester.getTopLeft(find.text('Page 2'));

    // Page 1 is moving to the right.
    expect(widget1TransientTopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
    // Page 1 isn't moving vertically.
    expect(widget1TransientTopLeft.dy, equals(widget1InitialTopLeft.dy));
    // iOS transition is horizontal only.
    expect(widget1InitialTopLeft.dy, equals(widget2TopLeft.dy));
    // Page 2 is coming in from the left.
    expect(widget2TopLeft.dx, lessThan(widget1InitialTopLeft.dx));

    await tester.pumpAndSettle();

    // Page 2 covers page 1.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    tester.state<NavigatorState>(find.byType(Navigator)).pop();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
    widget2TopLeft = tester.getTopLeft(find.text('Page 2'));

    // Page 1 is coming back from the right.
    expect(widget1TransientTopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
    // Page 1 isn't moving vertically.
    expect(widget1TransientTopLeft.dy, equals(widget1InitialTopLeft.dy));
    // iOS transition is horizontal only.
    expect(widget1InitialTopLeft.dy, equals(widget2TopLeft.dy));
    // Page 2 is leaving towards the left.
    expect(widget2TopLeft.dx, lessThan(widget1InitialTopLeft.dx));

    await tester.pumpAndSettle();

    expect(find.text('Page 1'), isOnstage);
    expect(find.text('Page 2'), findsNothing);

    widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));

    // Page 1 is back where it started.
    expect(widget1InitialTopLeft, equals(widget1TransientTopLeft));
  });

147 148
  testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async {
    await tester.pumpWidget(
149 150
      const CupertinoApp(
        home: Center(child: Text('Page 1')),
151 152 153 154 155
      ),
    );

    final Offset widget1InitialTopLeft = tester.getTopLeft(find.text('Page 1'));

156
    tester.state<NavigatorState>(find.byType(Navigator)).push(CupertinoPageRoute<void>(
157
      builder: (BuildContext context) {
158
        return const Center(child: Text('Page 2'));
159 160 161 162 163 164 165 166 167 168 169
      },
      fullscreenDialog: true,
    ));

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

    Offset widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
    Offset widget2TopLeft = tester.getTopLeft(find.text('Page 2'));

    // Page 1 doesn't move.
170
    expect(widget1TransientTopLeft, equals(widget1InitialTopLeft));
171
    // Fullscreen dialogs transitions vertically only.
172
    expect(widget1InitialTopLeft.dx, equals(widget2TopLeft.dx));
173
    // Page 2 is coming in from the bottom.
174
    expect(widget2TopLeft.dy, greaterThan(widget1InitialTopLeft.dy));
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

    await tester.pumpAndSettle();

    // Page 2 covers page 1.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    tester.state<NavigatorState>(find.byType(Navigator)).pop();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
    widget2TopLeft = tester.getTopLeft(find.text('Page 2'));

    // Page 1 doesn't move.
190
    expect(widget1TransientTopLeft, equals(widget1InitialTopLeft));
191
    // Fullscreen dialogs transitions vertically only.
192
    expect(widget1InitialTopLeft.dx, equals(widget2TopLeft.dx));
193
    // Page 2 is leaving towards the bottom.
194
    expect(widget2TopLeft.dy, greaterThan(widget1InitialTopLeft.dy));
195 196 197 198 199 200 201 202 203

    await tester.pumpAndSettle();

    expect(find.text('Page 1'), isOnstage);
    expect(find.text('Page 2'), findsNothing);

    widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));

    // Page 1 is back where it started.
204
    expect(widget1InitialTopLeft, equals(widget1TransientTopLeft));
205
  });
206

Ian Hickson's avatar
Ian Hickson committed
207
  testWidgets('test only edge swipes work (LTR)', (WidgetTester tester) async {
208
    await tester.pumpWidget(
209
      CupertinoApp(
210
        onGenerateRoute: (RouteSettings settings) {
211
          return CupertinoPageRoute<void>(
212 213
            settings: settings,
            builder: (BuildContext context) {
Ian Hickson's avatar
Ian Hickson committed
214
              final String pageNumber = settings.name == '/' ? '1' : '2';
215
              return Center(child: Text('Page $pageNumber'));
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
            }
          );
        },
      ),
    );

    tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');

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

    // Page 2 covers page 1.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    // Drag from the middle to the right.
    TestGesture gesture = await tester.startGesture(const Offset(200.0, 200.0));
    await gesture.moveBy(const Offset(300.0, 0.0));
    await tester.pump();

    // Nothing should happen.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

Ian Hickson's avatar
Ian Hickson committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
    // Drag from the right to the left.
    gesture = await tester.startGesture(const Offset(795.0, 200.0));
    await gesture.moveBy(const Offset(-300.0, 0.0));
    await tester.pump();

    // Nothing should happen.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    // Drag from the right to the further right.
    gesture = await tester.startGesture(const Offset(795.0, 200.0));
    await gesture.moveBy(const Offset(300.0, 0.0));
    await tester.pump();

    // Nothing should happen.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    // Now drag from the left edge.
    gesture = await tester.startGesture(const Offset(5.0, 200.0));
    await gesture.moveBy(const Offset(300.0, 0.0));
    await tester.pump();

    // Page 1 is now visible.
    expect(find.text('Page 1'), isOnstage);
    expect(find.text('Page 2'), isOnstage);
  });

  testWidgets('test only edge swipes work (RTL)', (WidgetTester tester) async {
    await tester.pumpWidget(
270
      CupertinoApp(
271
        localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
272
          RtlOverrideWidgetsDelegate(),
Ian Hickson's avatar
Ian Hickson committed
273 274
        ],
        onGenerateRoute: (RouteSettings settings) {
275
          return CupertinoPageRoute<void>(
Ian Hickson's avatar
Ian Hickson committed
276 277 278
            settings: settings,
            builder: (BuildContext context) {
              final String pageNumber = settings.name == '/' ? '1' : '2';
279
              return Center(child: Text('Page $pageNumber'));
Ian Hickson's avatar
Ian Hickson committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
            }
          );
        },
      ),
    );
    await tester.pump(); // to load the localization, since it doesn't use a synchronous future

    tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');

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

    // Page 2 covers page 1.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    // Drag from the middle to the left.
    TestGesture gesture = await tester.startGesture(const Offset(200.0, 200.0));
    await gesture.moveBy(const Offset(-300.0, 0.0));
    await tester.pump();

    // Nothing should happen.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    // Drag from the left to the right.
306 307 308 309
    gesture = await tester.startGesture(const Offset(5.0, 200.0));
    await gesture.moveBy(const Offset(300.0, 0.0));
    await tester.pump();

Ian Hickson's avatar
Ian Hickson committed
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    // Nothing should happen.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    // Drag from the left to the further left.
    gesture = await tester.startGesture(const Offset(5.0, 200.0));
    await gesture.moveBy(const Offset(-300.0, 0.0));
    await tester.pump();

    // Nothing should happen.
    expect(find.text('Page 1'), findsNothing);
    expect(find.text('Page 2'), isOnstage);

    // Now drag from the right edge.
    gesture = await tester.startGesture(const Offset(795.0, 200.0));
    await gesture.moveBy(const Offset(-300.0, 0.0));
    await tester.pump();

328 329 330 331 332
    // Page 1 is now visible.
    expect(find.text('Page 1'), isOnstage);
    expect(find.text('Page 2'), isOnstage);
  });
}
Ian Hickson's avatar
Ian Hickson committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347

class RtlOverrideWidgetsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
  const RtlOverrideWidgetsDelegate();
  @override
  bool isSupported(Locale locale) => true;
  @override
  Future<WidgetsLocalizations> load(Locale locale) async => const RtlOverrideWidgetsLocalization();
  @override
  bool shouldReload(LocalizationsDelegate<WidgetsLocalizations> oldDelegate) => false;
}

class RtlOverrideWidgetsLocalization implements WidgetsLocalizations {
  const RtlOverrideWidgetsLocalization();
  @override
  TextDirection get textDirection => TextDirection.rtl;
348
}