drawer_test.dart 10.8 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 6
import 'dart:ui';

Adam Barth's avatar
Adam Barth committed
7
import 'package:flutter_test/flutter_test.dart';
8
import 'package:flutter/foundation.dart';
9
import 'package:flutter/material.dart';
10
import 'package:flutter/rendering.dart';
11
import 'package:flutter/widgets.dart';
12
import 'package:flutter/gestures.dart' show DragStartBehavior;
Hixie's avatar
Hixie committed
13

14 15
import 'semantics_tester.dart';

Hixie's avatar
Hixie committed
16 17
void main() {

18
  testWidgets('Drawer control test', (WidgetTester tester) async {
19
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
20
    BuildContext savedContext;
21
    await tester.pumpWidget(
22 23
      MaterialApp(
        home: Builder(
24 25
          builder: (BuildContext context) {
            savedContext = context;
26
            return Scaffold(
27
              key: scaffoldKey,
28
              drawer: const Text('drawer'),
29
              body: Container(),
30
            );
31 32 33
          },
        ),
      ),
34
    );
35
    await tester.pump(); // no effect
36 37
    expect(find.text('drawer'), findsNothing);
    scaffoldKey.currentState.openDrawer();
38
    await tester.pump(); // drawer should be starting to animate in
39
    expect(find.text('drawer'), findsOneWidget);
40
    await tester.pump(const Duration(seconds: 1)); // animation done
41 42
    expect(find.text('drawer'), findsOneWidget);
    Navigator.pop(savedContext);
43
    await tester.pump(); // drawer should be starting to animate away
44
    expect(find.text('drawer'), findsOneWidget);
45
    await tester.pump(const Duration(seconds: 1)); // animation done
46
    expect(find.text('drawer'), findsNothing);
Hixie's avatar
Hixie committed
47 48
  });

49
  testWidgets('Drawer tap test', (WidgetTester tester) async {
50
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
51
    await tester.pumpWidget(
52 53
      MaterialApp(
        home: Scaffold(
54
          key: scaffoldKey,
55
          drawer: const Text('drawer'),
56
          body: Container(),
57 58
        ),
      ),
59
    );
60
    await tester.pump(); // no effect
61 62
    expect(find.text('drawer'), findsNothing);
    scaffoldKey.currentState.openDrawer();
63
    await tester.pump(); // drawer should be starting to animate in
64
    expect(find.text('drawer'), findsOneWidget);
65
    await tester.pump(const Duration(seconds: 1)); // animation done
66
    expect(find.text('drawer'), findsOneWidget);
67 68
    await tester.tap(find.text('drawer'));
    await tester.pump(); // nothing should have happened
69
    expect(find.text('drawer'), findsOneWidget);
70
    await tester.pump(const Duration(seconds: 1)); // ditto
71
    expect(find.text('drawer'), findsOneWidget);
72
    await tester.tapAt(const Offset(750.0, 100.0)); // on the mask
73
    await tester.pump();
74
    await tester.pump(const Duration(milliseconds: 10));
75 76
    // drawer should be starting to animate away
    expect(find.text('drawer'), findsOneWidget);
77
    await tester.pump(const Duration(seconds: 1)); // animation done
78
    expect(find.text('drawer'), findsNothing);
Hixie's avatar
Hixie committed
79 80
  });

81
  testWidgets('Drawer drag cancel resume (LTR)', (WidgetTester tester) async {
82
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
83
    await tester.pumpWidget(
84 85
      MaterialApp(
        home: Scaffold(
86
          drawerDragStartBehavior: DragStartBehavior.down,
87
          key: scaffoldKey,
88 89
          drawer: Drawer(
            child: ListView(
90
              children: <Widget>[
91
                const Text('drawer'),
92
                Container(
93
                  height: 1000.0,
94
                  color: Colors.blue[500],
95
                ),
96 97
              ],
            ),
98
          ),
99
          body: Container(),
100 101
        ),
      ),
102 103 104
    );
    expect(find.text('drawer'), findsNothing);
    scaffoldKey.currentState.openDrawer();
105
    await tester.pump(); // drawer should be starting to animate in
106
    expect(find.text('drawer'), findsOneWidget);
107
    await tester.pump(const Duration(seconds: 1)); // animation done
108
    expect(find.text('drawer'), findsOneWidget);
109

110
    await tester.tapAt(const Offset(750.0, 100.0)); // on the mask
111
    await tester.pump();
112
    await tester.pump(const Duration(milliseconds: 10));
113
    // drawer should be starting to animate away
114
    final double textLeft = tester.getTopLeft(find.text('drawer')).dx;
115
    expect(textLeft, lessThan(0.0));
116

117
    final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
118
    // drawer should be stopped.
119
    await tester.pump();
120
    await tester.pump(const Duration(milliseconds: 10));
121
    expect(tester.getTopLeft(find.text('drawer')).dx, equals(textLeft));
122

123
    await gesture.moveBy(const Offset(50.0, 0.0));
124
    // drawer should be returning to visible
125
    await tester.pump();
126
    await tester.pump(const Duration(seconds: 1));
127 128 129 130 131 132
    expect(tester.getTopLeft(find.text('drawer')).dx, equals(0.0));

    await gesture.up();
  });

  testWidgets('Drawer drag cancel resume (RTL)', (WidgetTester tester) async {
133
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
134
    await tester.pumpWidget(
135 136
      MaterialApp(
        home: Directionality(
137
          textDirection: TextDirection.rtl,
138
          child: Scaffold(
139
            drawerDragStartBehavior: DragStartBehavior.down,
140
            key: scaffoldKey,
141 142
            drawer: Drawer(
              child: ListView(
143 144
                children: <Widget>[
                  const Text('drawer'),
145
                  Container(
146 147 148 149 150 151
                    height: 1000.0,
                    color: Colors.blue[500],
                  ),
                ],
              ),
            ),
152
            body: Container(),
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
          ),
        ),
      ),
    );
    expect(find.text('drawer'), findsNothing);
    scaffoldKey.currentState.openDrawer();
    await tester.pump(); // drawer should be starting to animate in
    expect(find.text('drawer'), findsOneWidget);
    await tester.pump(const Duration(seconds: 1)); // animation done
    expect(find.text('drawer'), findsOneWidget);

    await tester.tapAt(const Offset(50.0, 100.0)); // on the mask
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 10));
    // drawer should be starting to animate away
    final double textRight = tester.getTopRight(find.text('drawer')).dx;
    expect(textRight, greaterThan(800.0));

    final TestGesture gesture = await tester.startGesture(const Offset(700.0, 100.0));
    // drawer should be stopped.
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 10));
    expect(tester.getTopRight(find.text('drawer')).dx, equals(textRight));

    await gesture.moveBy(const Offset(-50.0, 0.0));
    // drawer should be returning to visible
    await tester.pump();
    await tester.pump(const Duration(seconds: 1));
    expect(tester.getTopRight(find.text('drawer')).dx, equals(800.0));
182

183
    await gesture.up();
184 185
  });

186
  testWidgets('Drawer navigator back button', (WidgetTester tester) async {
187
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
188 189 190
    bool buttonPressed = false;

    await tester.pumpWidget(
191 192
      MaterialApp(
        home: Builder(
193
          builder: (BuildContext context) {
194
            return Scaffold(
195
              key: scaffoldKey,
196 197
              drawer: Drawer(
                child: ListView(
198
                  children: <Widget>[
199
                    const Text('drawer'),
200
                    FlatButton(
201
                      child: const Text('close'),
202
                      onPressed: () => Navigator.pop(context),
203
                    ),
204 205
                  ],
                ),
206
              ),
207 208
              body: Container(
                child: FlatButton(
209
                  child: const Text('button'),
210 211 212
                  onPressed: () { buttonPressed = true; },
                ),
              ),
213
            );
214 215 216
          },
        ),
      ),
217 218 219 220 221 222 223 224
    );

    // Open the drawer.
    scaffoldKey.currentState.openDrawer();
    await tester.pump(); // drawer should be starting to animate in
    expect(find.text('drawer'), findsOneWidget);

    // Tap the close button to pop the drawer route.
225
    await tester.pump(const Duration(milliseconds: 100));
226 227
    await tester.tap(find.text('close'));
    await tester.pump();
228
    await tester.pump(const Duration(seconds: 1));
229 230 231 232 233 234 235
    expect(find.text('drawer'), findsNothing);

    // Confirm that a button in the scaffold body is still clickable.
    await tester.tap(find.text('button'));
    expect(buttonPressed, equals(true));
  });

236 237 238
  testWidgets('Dismissible ModalBarrier includes button in semantic tree on iOS', (WidgetTester tester) async {
    debugDefaultTargetPlatformOverride = TargetPlatform.iOS;

239 240
    final SemanticsTester semantics = SemanticsTester(tester);
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
241 242

    await tester.pumpWidget(
243 244
      MaterialApp(
        home: Builder(
245
          builder: (BuildContext context) {
246
            return Scaffold(
247 248 249 250 251 252
              key: scaffoldKey,
              drawer: const Drawer(),
            );
          },
        ),
      ),
253 254 255 256 257 258 259 260 261 262 263 264 265 266
    );

    // Open the drawer.
    scaffoldKey.currentState.openDrawer();
    await tester.pump(const Duration(milliseconds: 100));

    expect(semantics, includesNodeWith(actions: <SemanticsAction>[SemanticsAction.tap]));

    semantics.dispose();

    debugDefaultTargetPlatformOverride = null;
  });

  testWidgets('Dismissible ModalBarrier is hidden on Android (back button is used to dismiss)', (WidgetTester tester) async {
267 268
    final SemanticsTester semantics = SemanticsTester(tester);
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
269 270

    await tester.pumpWidget(
271 272
      MaterialApp(
        home: Builder(
273
          builder: (BuildContext context) {
274
            return Scaffold(
275 276
              key: scaffoldKey,
              drawer: const Drawer(),
277
              body: Container(),
278 279 280 281
            );
          },
        ),
      ),
282 283 284 285 286 287 288 289 290 291
    );

    // Open the drawer.
    scaffoldKey.currentState.openDrawer();
    await tester.pump(const Duration(milliseconds: 100));

    expect(semantics, isNot(includesNodeWith(actions: <SemanticsAction>[SemanticsAction.tap])));

    semantics.dispose();
  });
292 293

  testWidgets('Drawer contains route semantics flags', (WidgetTester tester) async {
294 295
    final SemanticsTester semantics = SemanticsTester(tester);
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
296 297

    await tester.pumpWidget(
298 299
      MaterialApp(
        home: Builder(
300
          builder: (BuildContext context) {
301
            return Scaffold(
302 303
              key: scaffoldKey,
              drawer: const Drawer(),
304
              body: Container(),
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
            );
          },
        ),
      ),
    );

    // Open the drawer.
    scaffoldKey.currentState.openDrawer();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    expect(semantics, includesNodeWith(
      label: 'Navigation menu',
      flags: <SemanticsFlag>[
        SemanticsFlag.scopesRoute,
        SemanticsFlag.namesRoute,
      ],
    ));

    semantics.dispose();
  });
Hixie's avatar
Hixie committed
326
}
327 328