date_picker_test.dart 30.6 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4
// Copyright 2016 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';

7
import 'package:flutter/rendering.dart';
Ian Hickson's avatar
Ian Hickson committed
8
import 'package:flutter/material.dart';
9
import 'package:flutter/widgets.dart';
Ian Hickson's avatar
Ian Hickson committed
10
import 'package:flutter_test/flutter_test.dart';
11
import 'package:flutter/gestures.dart' show DragStartBehavior;
Ian Hickson's avatar
Ian Hickson committed
12

13
import '../widgets/semantics_tester.dart';
14 15
import 'feedback_tester.dart';

Ian Hickson's avatar
Ian Hickson committed
16
void main() {
17 18 19 20 21 22
  group('showDatePicker', () {
    _tests();
  });
}

void _tests() {
23 24 25
  DateTime firstDate;
  DateTime lastDate;
  DateTime initialDate;
26
  SelectableDayPredicate selectableDayPredicate;
27
  DatePickerMode initialDatePickerMode;
28 29
  final Finder nextMonthIcon = find.byWidgetPredicate((Widget w) => w is IconButton && (w.tooltip?.startsWith('Next month') ?? false));
  final Finder previousMonthIcon = find.byWidgetPredicate((Widget w) => w is IconButton && (w.tooltip?.startsWith('Previous month') ?? false));
30 31

  setUp(() {
32 33 34
    firstDate = DateTime(2001, DateTime.january, 1);
    lastDate = DateTime(2031, DateTime.december, 31);
    initialDate = DateTime(2016, DateTime.january, 15);
35 36
    selectableDayPredicate = null;
    initialDatePickerMode = null;
37 38
  });

39
  testWidgets('tap-select a day', (WidgetTester tester) async {
40 41
    final Key _datePickerKey = UniqueKey();
    DateTime _selectedDate = DateTime(2016, DateTime.july, 26);
Ian Hickson's avatar
Ian Hickson committed
42 43

    await tester.pumpWidget(
44 45
      MaterialApp(
        home: StatefulBuilder(
46
          builder: (BuildContext context, StateSetter setState) {
47
            return Container(
48
              width: 400.0,
49
              child: SingleChildScrollView(
50
                dragStartBehavior: DragStartBehavior.down,
51 52
                child: Material(
                  child: MonthPicker(
53
                    dragStartBehavior: DragStartBehavior.down,
54 55
                    firstDate: DateTime(0),
                    lastDate: DateTime(9999),
56 57 58 59 60 61 62
                    key: _datePickerKey,
                    selectedDate: _selectedDate,
                    onChanged: (DateTime value) {
                      setState(() {
                        _selectedDate = value;
                      });
                    },
63
                  ),
64 65 66 67 68
                ),
              ),
            );
          },
        ),
69
      ),
Ian Hickson's avatar
Ian Hickson committed
70
    );
71

72
    expect(_selectedDate, equals(DateTime(2016, DateTime.july, 26)));
Ian Hickson's avatar
Ian Hickson committed
73

74
    await tester.tapAt(const Offset(50.0, 100.0));
75
    await tester.pumpAndSettle();
Ian Hickson's avatar
Ian Hickson committed
76 77
    await tester.pump(const Duration(seconds: 2));

78 79
    await tester.tap(find.text('1'));
    await tester.pumpAndSettle();
80
    expect(_selectedDate, equals(DateTime(2016, DateTime.july, 1)));
Ian Hickson's avatar
Ian Hickson committed
81

82
    await tester.tap(nextMonthIcon);
83
    await tester.pumpAndSettle();
84
    expect(_selectedDate, equals(DateTime(2016, DateTime.july, 1)));
Ian Hickson's avatar
Ian Hickson committed
85

86 87
    await tester.tap(find.text('5'));
    await tester.pumpAndSettle();
88
    expect(_selectedDate, equals(DateTime(2016, DateTime.august, 5)));
Ian Hickson's avatar
Ian Hickson committed
89

90 91
    await tester.drag(find.byKey(_datePickerKey), const Offset(-400.0, 0.0));
    await tester.pumpAndSettle();
92
    expect(_selectedDate, equals(DateTime(2016, DateTime.august, 5)));
Ian Hickson's avatar
Ian Hickson committed
93

94 95
    await tester.tap(find.text('25'));
    await tester.pumpAndSettle();
96
    expect(_selectedDate, equals(DateTime(2016, DateTime.september, 25)));
Ian Hickson's avatar
Ian Hickson committed
97

98 99
    await tester.drag(find.byKey(_datePickerKey), const Offset(800.0, 0.0));
    await tester.pumpAndSettle();
100
    expect(_selectedDate, equals(DateTime(2016, DateTime.september, 25)));
Ian Hickson's avatar
Ian Hickson committed
101

102 103
    await tester.tap(find.text('17'));
    await tester.pumpAndSettle();
104
    expect(_selectedDate, equals(DateTime(2016, DateTime.august, 17)));
Ian Hickson's avatar
Ian Hickson committed
105 106 107 108
  });

  testWidgets('render picker with intrinsic dimensions', (WidgetTester tester) async {
    await tester.pumpWidget(
109 110
      MaterialApp(
        home: StatefulBuilder(
111
          builder: (BuildContext context, StateSetter setState) {
112 113 114 115 116 117 118
            return IntrinsicWidth(
              child: IntrinsicHeight(
                child: Material(
                  child: SingleChildScrollView(
                    child: MonthPicker(
                      firstDate: DateTime(0),
                      lastDate: DateTime(9999),
119
                      onChanged: (DateTime value) { },
120
                      selectedDate: DateTime(2000, DateTime.january, 1),
121 122
                    ),
                  ),
123 124 125 126 127
                ),
              ),
            );
          },
        ),
128
      ),
Ian Hickson's avatar
Ian Hickson committed
129 130 131 132
    );
    await tester.pump(const Duration(seconds: 5));
  });

133
  Future<void> preparePicker(WidgetTester tester, Future<void> callback(Future<DateTime> date)) async {
134
    BuildContext buttonContext;
135 136 137
    await tester.pumpWidget(MaterialApp(
      home: Material(
        child: Builder(
138
          builder: (BuildContext context) {
139
            return RaisedButton(
140 141 142
              onPressed: () {
                buttonContext = context;
              },
143
              child: const Text('Go'),
144 145 146 147 148 149 150 151 152
            );
          },
        ),
      ),
    ));

    await tester.tap(find.text('Go'));
    expect(buttonContext, isNotNull);

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
    final Future<DateTime> date = initialDatePickerMode == null
        // Exercise the argument default for initialDatePickerMode.
        ?
            showDatePicker(
              context: buttonContext,
              initialDate: initialDate,
              firstDate: firstDate,
              lastDate: lastDate,
              selectableDayPredicate: selectableDayPredicate,
            )
        :
            showDatePicker(
              context: buttonContext,
              initialDate: initialDate,
              firstDate: firstDate,
              lastDate: lastDate,
              selectableDayPredicate: selectableDayPredicate,
              initialDatePickerMode: initialDatePickerMode,
            );
172

173
    await tester.pumpAndSettle(const Duration(seconds: 1));
174 175 176 177 178 179
    await callback(date);
  }

  testWidgets('Initial date is the default', (WidgetTester tester) async {
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('OK'));
180
      expect(await date, equals(DateTime(2016, DateTime.january, 15)));
181 182 183 184 185 186 187 188 189 190 191 192 193 194
    });
  });

  testWidgets('Can cancel', (WidgetTester tester) async {
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('CANCEL'));
      expect(await date, isNull);
    });
  });

  testWidgets('Can select a day', (WidgetTester tester) async {
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('12'));
      await tester.tap(find.text('OK'));
195
      expect(await date, equals(DateTime(2016, DateTime.january, 12)));
196 197 198 199 200
    });
  });

  testWidgets('Can select a month', (WidgetTester tester) async {
    await preparePicker(tester, (Future<DateTime> date) async {
201
      await tester.tap(previousMonthIcon);
202
      await tester.pumpAndSettle(const Duration(seconds: 1));
203 204
      await tester.tap(find.text('25'));
      await tester.tap(find.text('OK'));
205
      expect(await date, equals(DateTime(2015, DateTime.december, 25)));
206 207 208 209 210 211 212
    });
  });

  testWidgets('Can select a year', (WidgetTester tester) async {
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('2016'));
      await tester.pump();
213
      await tester.tap(find.text('2018'));
214
      await tester.tap(find.text('OK'));
215
      expect(await date, equals(DateTime(2018, DateTime.january, 15)));
216 217 218 219 220 221 222
    });
  });

  testWidgets('Can select a year and then a day', (WidgetTester tester) async {
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('2016'));
      await tester.pump();
223
      await tester.tap(find.text('2017'));
224
      await tester.pump();
Yegor's avatar
Yegor committed
225 226 227
      final MaterialLocalizations localizations = MaterialLocalizations.of(
        tester.element(find.byType(DayPicker))
      );
228
      final String dayLabel = localizations.formatMediumDate(DateTime(2017, DateTime.january, 15));
229 230 231 232
      await tester.tap(find.text(dayLabel));
      await tester.pump();
      await tester.tap(find.text('19'));
      await tester.tap(find.text('OK'));
233
      expect(await date, equals(DateTime(2017, DateTime.january, 19)));
234 235 236 237
    });
  });

  testWidgets('Current year is initially visible in year picker', (WidgetTester tester) async {
238 239 240
    initialDate = DateTime(2000);
    firstDate = DateTime(1900);
    lastDate = DateTime(2100);
241 242 243 244
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('2000'));
      await tester.pump();
      expect(find.text('2000'), findsNWidgets(2));
245 246
    });
  });
247 248

  testWidgets('Cannot select a day outside bounds', (WidgetTester tester) async {
249
    initialDate = DateTime(2017, DateTime.january, 15);
250 251 252 253 254 255
    firstDate = initialDate;
    lastDate = initialDate;
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('10')); // Earlier than firstDate. Should be ignored.
      await tester.tap(find.text('20')); // Later than lastDate. Should be ignored.
      await tester.tap(find.text('OK'));
256
      // We should still be on the initial date.
257 258 259 260 261
      expect(await date, equals(initialDate));
    });
  });

  testWidgets('Cannot select a month past last date', (WidgetTester tester) async {
262
    initialDate = DateTime(2017, DateTime.january, 15);
263
    firstDate = initialDate;
264
    lastDate = DateTime(2017, DateTime.february, 20);
265
    await preparePicker(tester, (Future<DateTime> date) async {
266
      await tester.tap(nextMonthIcon);
267
      await tester.pumpAndSettle(const Duration(seconds: 1));
268
      // Shouldn't be possible to keep going into March.
269
      expect(nextMonthIcon, findsNothing);
270 271 272 273
    });
  });

  testWidgets('Cannot select a month before first date', (WidgetTester tester) async {
274 275
    initialDate = DateTime(2017, DateTime.january, 15);
    firstDate = DateTime(2016, DateTime.december, 10);
276 277
    lastDate = initialDate;
    await preparePicker(tester, (Future<DateTime> date) async {
278
      await tester.tap(previousMonthIcon);
279
      await tester.pumpAndSettle(const Duration(seconds: 1));
280
      // Shouldn't be possible to keep going into November.
281
      expect(previousMonthIcon, findsNothing);
282 283
    });
  });
284

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
  testWidgets('Selecting firstDate year respects firstDate', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/17309
    initialDate = DateTime(2018, DateTime.may, 4);
    firstDate = DateTime(2016, DateTime.june, 9);
    lastDate = DateTime(2019, DateTime.january, 15);
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('2018'));
      await tester.pumpAndSettle();
      await tester.tap(find.text('2016'));
      await tester.pumpAndSettle();
      await tester.tap(find.text('OK'));
      await tester.pumpAndSettle();
      expect(await date, DateTime(2016, DateTime.june, 9));
    });
  });

  testWidgets('Selecting lastDate year respects lastDate', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/17309
    initialDate = DateTime(2018, DateTime.may, 4);
    firstDate = DateTime(2016, DateTime.june, 9);
    lastDate = DateTime(2019, DateTime.january, 15);
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('2018'));
      await tester.pumpAndSettle();
      await tester.tap(find.text('2019'));
      await tester.pumpAndSettle();
      await tester.tap(find.text('OK'));
      await tester.pumpAndSettle();
      expect(await date, DateTime(2019, DateTime.january, 15));
    });
  });


318
  testWidgets('Only predicate days are selectable', (WidgetTester tester) async {
319 320 321
    initialDate = DateTime(2017, DateTime.january, 16);
    firstDate = DateTime(2017, DateTime.january, 10);
    lastDate = DateTime(2017, DateTime.january, 20);
322 323 324 325 326 327
    selectableDayPredicate = (DateTime day) => day.day.isEven;
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.tap(find.text('10')); // Even, works.
      await tester.tap(find.text('13')); // Odd, doesn't work.
      await tester.tap(find.text('17')); // Odd, doesn't work.
      await tester.tap(find.text('OK'));
328
      expect(await date, equals(DateTime(2017, DateTime.january, 10)));
329 330
    });
  });
331

332
  testWidgets('Can select initial date picker mode', (WidgetTester tester) async {
333
    initialDate = DateTime(2014, DateTime.january, 15);
334 335 336 337 338 339 340
    initialDatePickerMode = DatePickerMode.year;
    await preparePicker(tester, (Future<DateTime> date) async {
      await tester.pump();
      // 2018 wouldn't be available if the year picker wasn't showing.
      // The initial current year is 2014.
      await tester.tap(find.text('2018'));
      await tester.tap(find.text('OK'));
341
      expect(await date, equals(DateTime(2018, DateTime.january, 15)));
342 343 344
    });
  });

345
  group('haptic feedback', () {
346
    const Duration kHapticFeedbackInterval = Duration(milliseconds: 10);
347
    FeedbackTester feedback;
348 349

    setUp(() {
350 351 352 353
      feedback = FeedbackTester();
      initialDate = DateTime(2017, DateTime.january, 16);
      firstDate = DateTime(2017, DateTime.january, 10);
      lastDate = DateTime(2018, DateTime.january, 20);
354 355 356
      selectableDayPredicate = (DateTime date) => date.day.isEven;
    });

357 358 359 360
    tearDown(() {
      feedback?.dispose();
    });

361 362 363 364
    testWidgets('tap-select date vibrates', (WidgetTester tester) async {
      await preparePicker(tester, (Future<DateTime> date) async {
        await tester.tap(find.text('10'));
        await tester.pump(kHapticFeedbackInterval);
365
        expect(feedback.hapticCount, 1);
366 367
        await tester.tap(find.text('12'));
        await tester.pump(kHapticFeedbackInterval);
368
        expect(feedback.hapticCount, 2);
369 370
        await tester.tap(find.text('14'));
        await tester.pump(kHapticFeedbackInterval);
371
        expect(feedback.hapticCount, 3);
372 373 374 375 376 377 378
      });
    });

    testWidgets('tap-select unselectable date does not vibrate', (WidgetTester tester) async {
      await preparePicker(tester, (Future<DateTime> date) async {
        await tester.tap(find.text('11'));
        await tester.pump(kHapticFeedbackInterval);
379
        expect(feedback.hapticCount, 0);
380 381
        await tester.tap(find.text('13'));
        await tester.pump(kHapticFeedbackInterval);
382
        expect(feedback.hapticCount, 0);
383 384
        await tester.tap(find.text('15'));
        await tester.pump(kHapticFeedbackInterval);
385
        expect(feedback.hapticCount, 0);
386 387 388 389 390 391 392
      });
    });

    testWidgets('mode, year change vibrates', (WidgetTester tester) async {
      await preparePicker(tester, (Future<DateTime> date) async {
        await tester.tap(find.text('2017'));
        await tester.pump(kHapticFeedbackInterval);
393
        expect(feedback.hapticCount, 1);
394 395
        await tester.tap(find.text('2018'));
        await tester.pump(kHapticFeedbackInterval);
396
        expect(feedback.hapticCount, 2);
397 398
      });
    });
399

400
  });
401 402 403 404 405 406 407 408 409

  test('days in month', () {
    expect(DayPicker.getDaysInMonth(2017, 10), 31);
    expect(DayPicker.getDaysInMonth(2017, 6), 30);
    expect(DayPicker.getDaysInMonth(2017, 2), 28);
    expect(DayPicker.getDaysInMonth(2016, 2), 29);
    expect(DayPicker.getDaysInMonth(2000, 2), 29);
    expect(DayPicker.getDaysInMonth(1900, 2), 28);
  });
410 411 412 413 414 415 416 417 418 419 420 421 422

  testWidgets('month header tap', (WidgetTester tester) async {
    selectableDayPredicate = null;
    await preparePicker(tester, (Future<DateTime> date) async {
      // Switch into the year selector.
      await tester.tap(find.text('January 2016'));
      await tester.pump();
      expect(find.text('2020'), isNotNull);

      await tester.tap(find.text('CANCEL'));
      expect(await date, isNull);
    });
  });
423 424

  testWidgets('exports semantics', (WidgetTester tester) async {
425
    final SemanticsTester semantics = SemanticsTester(tester);
426
    await preparePicker(tester, (Future<DateTime> date) async {
427
      final TestSemantics expected = TestSemantics(
428
        flags: <SemanticsFlag>[SemanticsFlag.scopesRoute],
429
        children: <TestSemantics>[
430
          TestSemantics(
431 432
            elevation: 24.0,
            thickness: 0.0,
433
            children: <TestSemantics>[
434 435 436 437 438 439 440 441 442 443 444
              TestSemantics(
                actions: <SemanticsAction>[SemanticsAction.tap],
                label: '2016',
                textDirection: TextDirection.ltr,
              ),
              TestSemantics(
                flags: <SemanticsFlag>[SemanticsFlag.isSelected],
                actions: <SemanticsAction>[SemanticsAction.tap],
                label: 'Fri, Jan 15',
                textDirection: TextDirection.ltr,
              ),
445
              TestSemantics(
446
                children: <TestSemantics>[
447
                  TestSemantics(
448
                    actions: <SemanticsAction>[SemanticsAction.scrollLeft, SemanticsAction.scrollRight],
449
                    children: <TestSemantics>[
450
                      TestSemantics(
451
                        children: <TestSemantics>[
452
                          TestSemantics(
453
                            children: <TestSemantics>[
454
                              TestSemantics(
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
                                children: <TestSemantics>[
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '1, Friday, January 1, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '2, Saturday, January 2, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '3, Sunday, January 3, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '4, Monday, January 4, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '5, Tuesday, January 5, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '6, Wednesday, January 6, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '7, Thursday, January 7, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '8, Friday, January 8, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '9, Saturday, January 9, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '10, Sunday, January 10, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '11, Monday, January 11, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '12, Tuesday, January 12, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '13, Wednesday, January 13, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '14, Thursday, January 14, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    flags: <SemanticsFlag>[SemanticsFlag.isSelected],
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '15, Friday, January 15, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '16, Saturday, January 16, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '17, Sunday, January 17, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '18, Monday, January 18, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '19, Tuesday, January 19, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '20, Wednesday, January 20, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '21, Thursday, January 21, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '22, Friday, January 22, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '23, Saturday, January 23, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '24, Sunday, January 24, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '25, Monday, January 25, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '26, Tuesday, January 26, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '27, Wednesday, January 27, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '28, Thursday, January 28, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '29, Friday, January 29, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '30, Saturday, January 30, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                  TestSemantics(
                                    actions: <SemanticsAction>[SemanticsAction.tap],
                                    label: '31, Sunday, January 31, 2016',
                                    textDirection: TextDirection.ltr,
                                  ),
                                ],
613 614
                              ),
                            ],
615 616 617 618 619 620 621
                          ),
                        ],
                      ),
                    ],
                  ),
                ],
              ),
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
              TestSemantics(
                flags: <SemanticsFlag>[SemanticsFlag.isButton, SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled],
                actions: <SemanticsAction>[SemanticsAction.tap],
                label: 'Previous month December 2015',
                textDirection: TextDirection.ltr,
              ),
              TestSemantics(
                flags: <SemanticsFlag>[SemanticsFlag.isButton, SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled],
                actions: <SemanticsAction>[SemanticsAction.tap],
                label: 'Next month February 2016',
                textDirection: TextDirection.ltr,
              ),
              TestSemantics(
                flags: <SemanticsFlag>[SemanticsFlag.isButton, SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled],
                actions: <SemanticsAction>[SemanticsAction.tap],
                label: 'CANCEL',
                textDirection: TextDirection.ltr,
              ),
              TestSemantics(
                flags: <SemanticsFlag>[SemanticsFlag.isButton, SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled],
                actions: <SemanticsAction>[SemanticsAction.tap],
                label: 'OK',
                textDirection: TextDirection.ltr,
              ),
646 647 648 649 650 651
            ],
          ),
        ],
      );

      expect(semantics, hasSemantics(
652 653
        TestSemantics.root(children: <TestSemantics>[
          TestSemantics(
654 655 656
            children: <TestSemantics>[expected],
          ),
        ]),
657 658 659 660 661
        ignoreId: true,
        ignoreTransform: true,
        ignoreRect: true,
      ));
    });
662 663

    semantics.dispose();
664
  });
665 666

  testWidgets('chervons animate when scrolling month picker', (WidgetTester tester) async {
667 668
    final Key _datePickerKey = UniqueKey();
    DateTime _selectedDate = DateTime(2016, DateTime.july, 26);
669 670

    await tester.pumpWidget(
671 672
      MaterialApp(
        home: StatefulBuilder(
673
          builder: (BuildContext context, StateSetter setState) {
674
            return Container(
675
              width: 400.0,
676 677 678 679 680
              child: SingleChildScrollView(
                child: Material(
                  child: MonthPicker(
                    firstDate: DateTime(0),
                    lastDate: DateTime(9999),
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
                    key: _datePickerKey,
                    selectedDate: _selectedDate,
                    onChanged: (DateTime value) {
                      setState(() {
                        _selectedDate = value;
                      });
                    },
                  ),
                ),
              ),
            );
          },
        ),
      )
    );

    final Finder chevronFinder = find.byType(IconButton);
    final List<RenderAnimatedOpacity> chevronRenderers = chevronFinder.evaluate().map(
      (Element element) => element.ancestorRenderObjectOfType(
        const TypeMatcher<RenderAnimatedOpacity>())).cast<RenderAnimatedOpacity>().toList();

    // Initial chevron animation state should be dismissed
    // An AlwaysStoppedAnimation is also found and is ignored
    for(RenderAnimatedOpacity renderer in chevronRenderers) {
      expect(renderer.opacity.value, equals(1.0));
      expect(renderer.opacity.status, equals(AnimationStatus.dismissed));
    }

    // Drag and hold the picker to test for the opacity change
    final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
    await gesture.moveBy(const Offset(50.0, 100.0));
    await tester.pumpAndSettle();
    for(RenderAnimatedOpacity renderer in chevronRenderers) {
714
      expect(renderer.opacity.value, equals(0.0));
715 716 717 718 719 720 721 722 723 724 725
      expect(renderer.opacity.status, equals(AnimationStatus.completed));
    }

    // Release the drag and test for the opacity to return to original value
    await gesture.up();
    await tester.pumpAndSettle();
    for(RenderAnimatedOpacity renderer in chevronRenderers) {
      expect(renderer.opacity.value, equals(1.0));
      expect(renderer.opacity.status, equals(AnimationStatus.dismissed));
    }
  });
Ian Hickson's avatar
Ian Hickson committed
726
}