blob: bfd0aecd9b379cea01f13b36a0a275bf53eb0d8d [file] [log] [blame]
// 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.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:intl/intl.dart';
import 'feedback_tester.dart';
void main() {
DateTime firstDate;
DateTime lastDate;
DateTime initialDate;
SelectableDayPredicate selectableDayPredicate;
setUp(() {
firstDate = new DateTime(2001, DateTime.JANUARY, 1);
lastDate = new DateTime(2031, DateTime.DECEMBER, 31);
initialDate = new DateTime(2016, DateTime.JANUARY, 15);
});
testWidgets('tap-select a day', (WidgetTester tester) async {
final Key _datePickerKey = new UniqueKey();
DateTime _selectedDate = new DateTime(2016, DateTime.JULY, 26);
await tester.pumpWidget(
new Overlay(
initialEntries: <OverlayEntry>[
new OverlayEntry(
builder: (BuildContext context) => new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Positioned(
width: 400.0,
child: new SingleChildScrollView(
child: new Material(
child: new MonthPicker(
firstDate: new DateTime(0),
lastDate: new DateTime(9999),
key: _datePickerKey,
selectedDate: _selectedDate,
onChanged: (DateTime value) {
setState(() {
_selectedDate = value;
});
},
),
),
),
);
},
),
),
],
),
);
expect(_selectedDate, equals(new DateTime(2016, DateTime.JULY, 26)));
await tester.tapAt(const Offset(50.0, 100.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.JULY, 26)));
await tester.pump(const Duration(seconds: 2));
await tester.tapAt(const Offset(300.0, 100.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.JULY, 1)));
await tester.pump(const Duration(seconds: 2));
await tester.tapAt(const Offset(380.0, 20.0));
await tester.pumpAndSettle(const Duration(milliseconds: 100));
expect(_selectedDate, equals(new DateTime(2016, DateTime.JULY, 1)));
await tester.tapAt(const Offset(300.0, 100.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.AUGUST, 5)));
await tester.pump(const Duration(seconds: 2));
await tester.drag(find.byKey(_datePickerKey), const Offset(-300.0, 0.0));
await tester.pumpAndSettle(const Duration(milliseconds: 100));
expect(_selectedDate, equals(new DateTime(2016, DateTime.AUGUST, 5)));
await tester.tapAt(const Offset(45.0, 270.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.SEPTEMBER, 25)));
await tester.pump(const Duration(seconds: 2));
await tester.drag(find.byKey(_datePickerKey), const Offset(300.0, 0.0));
await tester.pumpAndSettle(const Duration(milliseconds: 100));
expect(_selectedDate, equals(new DateTime(2016, DateTime.SEPTEMBER, 25)));
await tester.tapAt(const Offset(210.0, 180.0));
expect(_selectedDate, equals(new DateTime(2016, DateTime.AUGUST, 17)));
});
testWidgets('render picker with intrinsic dimensions', (WidgetTester tester) async {
await tester.pumpWidget(
new Overlay(
initialEntries: <OverlayEntry>[
new OverlayEntry(
builder: (BuildContext context) => new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new IntrinsicWidth(
child: new IntrinsicHeight(
child: new Material(
child: new SingleChildScrollView(
child: new MonthPicker(
firstDate: new DateTime(0),
lastDate: new DateTime(9999),
onChanged: (DateTime value) { },
selectedDate: new DateTime(2000, DateTime.JANUARY, 1),
),
),
),
),
);
},
),
),
],
),
);
await tester.pump(const Duration(seconds: 5));
});
Future<Null> preparePicker(WidgetTester tester, Future<Null> callback(Future<DateTime> date)) async {
BuildContext buttonContext;
await tester.pumpWidget(new MaterialApp(
home: new Material(
child: new Builder(
builder: (BuildContext context) {
return new RaisedButton(
onPressed: () {
buttonContext = context;
},
child: const Text('Go'),
);
},
),
),
));
await tester.tap(find.text('Go'));
expect(buttonContext, isNotNull);
final Future<DateTime> date = showDatePicker(
context: buttonContext,
initialDate: initialDate,
firstDate: firstDate,
lastDate: lastDate,
selectableDayPredicate: selectableDayPredicate
);
await tester.pumpAndSettle(const Duration(seconds: 1));
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'));
expect(await date, equals(new DateTime(2016, DateTime.JANUARY, 15)));
});
});
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'));
expect(await date, equals(new DateTime(2016, DateTime.JANUARY, 12)));
});
});
testWidgets('Can select a month', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTime> date) async {
await tester.tap(find.byTooltip('Previous month'));
await tester.pumpAndSettle(const Duration(seconds: 1));
await tester.tap(find.text('25'));
await tester.tap(find.text('OK'));
expect(await date, equals(new DateTime(2015, DateTime.DECEMBER, 25)));
});
});
testWidgets('Can select a year', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTime> date) async {
await tester.tap(find.text('2016'));
await tester.pump();
await tester.tap(find.text('2018'));
await tester.tap(find.text('OK'));
expect(await date, equals(new DateTime(2018, DateTime.JANUARY, 15)));
});
});
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();
await tester.tap(find.text('2017'));
await tester.pump();
final String dayLabel = new DateFormat('E, MMM\u00a0d').format(new DateTime(2017, DateTime.JANUARY, 15));
await tester.tap(find.text(dayLabel));
await tester.pump();
await tester.tap(find.text('19'));
await tester.tap(find.text('OK'));
expect(await date, equals(new DateTime(2017, DateTime.JANUARY, 19)));
});
});
testWidgets('Current year is initially visible in year picker', (WidgetTester tester) async {
initialDate = new DateTime(2000);
firstDate = new DateTime(1900);
lastDate = new DateTime(2100);
await preparePicker(tester, (Future<DateTime> date) async {
await tester.tap(find.text('2000'));
await tester.pump();
expect(find.text('2000'), findsNWidgets(2));
});
});
testWidgets('Cannot select a day outside bounds', (WidgetTester tester) async {
initialDate = new DateTime(2017, DateTime.JANUARY, 15);
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'));
// We should still be on the initial date.
expect(await date, equals(initialDate));
});
});
testWidgets('Cannot select a month past last date', (WidgetTester tester) async {
initialDate = new DateTime(2017, DateTime.JANUARY, 15);
firstDate = initialDate;
lastDate = new DateTime(2017, DateTime.FEBRUARY, 20);
await preparePicker(tester, (Future<DateTime> date) async {
await tester.tap(find.byTooltip('Next month'));
await tester.pumpAndSettle(const Duration(seconds: 1));
// Shouldn't be possible to keep going into March.
await tester.tap(find.byTooltip('Next month'));
await tester.pumpAndSettle(const Duration(seconds: 1));
// We're still in February
await tester.tap(find.text('20'));
// Days outside bound for new month pages also disabled.
await tester.tap(find.text('25'));
await tester.tap(find.text('OK'));
expect(await date, equals(new DateTime(2017, DateTime.FEBRUARY, 20)));
});
});
testWidgets('Cannot select a month before first date', (WidgetTester tester) async {
initialDate = new DateTime(2017, DateTime.JANUARY, 15);
firstDate = new DateTime(2016, DateTime.DECEMBER, 10);
lastDate = initialDate;
await preparePicker(tester, (Future<DateTime> date) async {
await tester.tap(find.byTooltip('Previous month'));
await tester.pumpAndSettle(const Duration(seconds: 1));
// Shouldn't be possible to keep going into November.
await tester.tap(find.byTooltip('Previous month'));
await tester.pumpAndSettle(const Duration(seconds: 1));
// We're still in December
await tester.tap(find.text('10'));
// Days outside bound for new month pages also disabled.
await tester.tap(find.text('5'));
await tester.tap(find.text('OK'));
expect(await date, equals(new DateTime(2016, DateTime.DECEMBER, 10)));
});
});
testWidgets('Only predicate days are selectable', (WidgetTester tester) async {
initialDate = new DateTime(2017, DateTime.JANUARY, 16);
firstDate = new DateTime(2017, DateTime.JANUARY, 10);
lastDate = new DateTime(2017, DateTime.JANUARY, 20);
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'));
expect(await date, equals(new DateTime(2017, DateTime.JANUARY, 10)));
});
});
group('haptic feedback', () {
const Duration kHapticFeedbackInterval = const Duration(milliseconds: 10);
FeedbackTester feedback;
setUp(() {
feedback = new FeedbackTester();
initialDate = new DateTime(2017, DateTime.JANUARY, 16);
firstDate = new DateTime(2017, DateTime.JANUARY, 10);
lastDate = new DateTime(2018, DateTime.JANUARY, 20);
selectableDayPredicate = (DateTime date) => date.day.isEven;
});
tearDown(() {
feedback?.dispose();
});
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);
expect(feedback.hapticCount, 1);
await tester.tap(find.text('12'));
await tester.pump(kHapticFeedbackInterval);
expect(feedback.hapticCount, 2);
await tester.tap(find.text('14'));
await tester.pump(kHapticFeedbackInterval);
expect(feedback.hapticCount, 3);
});
});
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);
expect(feedback.hapticCount, 0);
await tester.tap(find.text('13'));
await tester.pump(kHapticFeedbackInterval);
expect(feedback.hapticCount, 0);
await tester.tap(find.text('15'));
await tester.pump(kHapticFeedbackInterval);
expect(feedback.hapticCount, 0);
});
});
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);
expect(feedback.hapticCount, 1);
await tester.tap(find.text('2018'));
await tester.pump(kHapticFeedbackInterval);
expect(feedback.hapticCount, 2);
});
});
});
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);
});
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);
});
});
}