blob: 8d1bb8a3c98653c8c16c2295aecbab66dffc44dd [file] [log] [blame]
// Copyright 2014 The Flutter 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/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'feedback_tester.dart';
void main() {
late DateTime firstDate;
late DateTime lastDate;
late DateTime? currentDate;
late DateTimeRange? initialDateRange;
late DatePickerEntryMode initialEntryMode = DatePickerEntryMode.calendar;
String? cancelText;
String? confirmText;
String? errorInvalidRangeText;
String? errorFormatText;
String? errorInvalidText;
String? fieldStartHintText;
String? fieldEndHintText;
String? fieldStartLabelText;
String? fieldEndLabelText;
String? helpText;
String? saveText;
setUp(() {
firstDate = DateTime(2015, DateTime.january, 1);
lastDate = DateTime(2016, DateTime.december, 31);
currentDate = null;
initialDateRange = DateTimeRange(
start: DateTime(2016, DateTime.january, 15),
end: DateTime(2016, DateTime.january, 25),
);
initialEntryMode = DatePickerEntryMode.calendar;
cancelText = null;
confirmText = null;
errorInvalidRangeText = null;
errorFormatText = null;
errorInvalidText = null;
fieldStartHintText = null;
fieldEndHintText = null;
fieldStartLabelText = null;
fieldEndLabelText = null;
helpText = null;
saveText = null;
});
Future<void> preparePicker(
WidgetTester tester,
Future<void> callback(Future<DateTimeRange> date),
{ TextDirection textDirection = TextDirection.ltr }
) async {
late BuildContext buttonContext;
await tester.pumpWidget(MaterialApp(
home: Material(
child: Builder(
builder: (BuildContext context) {
return ElevatedButton(
onPressed: () {
buttonContext = context;
},
child: const Text('Go'),
);
},
),
),
));
await tester.tap(find.text('Go'));
expect(buttonContext, isNotNull);
final Future<DateTimeRange> range = showDateRangePicker(
context: buttonContext,
initialDateRange: initialDateRange,
firstDate: firstDate,
lastDate: lastDate,
currentDate: currentDate,
initialEntryMode: initialEntryMode,
cancelText: cancelText,
confirmText: confirmText,
errorInvalidRangeText: errorInvalidRangeText,
errorFormatText: errorFormatText,
errorInvalidText: errorInvalidText,
fieldStartHintText: fieldStartHintText,
fieldEndHintText: fieldEndHintText,
fieldStartLabelText: fieldStartLabelText,
fieldEndLabelText: fieldEndLabelText,
helpText: helpText,
saveText: saveText,
builder: (BuildContext context, Widget? child) {
return Directionality(
textDirection: textDirection,
child: child ?? const SizedBox(),
);
},
);
await tester.pumpAndSettle(const Duration(seconds: 1));
await callback(range);
}
testWidgets('Save and help text is used', (WidgetTester tester) async {
helpText = 'help';
saveText = 'make it so';
await preparePicker(tester, (Future<DateTimeRange> range) async {
expect(find.text(helpText!), findsOneWidget);
expect(find.text(saveText!), findsOneWidget);
});
});
testWidgets('Initial date is the default', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('SAVE'));
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 15),
end: DateTime(2016, DateTime.january, 25)
));
});
});
testWidgets('Last month header should be visible if last date is selected',
(WidgetTester tester) async {
firstDate = DateTime(2015, DateTime.january, 1);
lastDate = DateTime(2016, DateTime.december, 31);
initialDateRange = DateTimeRange(
start: lastDate,
end: lastDate,
);
await preparePicker(tester, (Future<DateTimeRange> range) async {
// December header should be showing, but no November
expect(find.text('December 2016'), findsOneWidget);
expect(find.text('November 2016'), findsNothing);
});
});
testWidgets('First month header should be visible if first date is selected',
(WidgetTester tester) async {
firstDate = DateTime(2015, DateTime.january, 1);
lastDate = DateTime(2016, DateTime.december, 31);
initialDateRange = DateTimeRange(
start: firstDate,
end: firstDate,
);
await preparePicker(tester, (Future<DateTimeRange> range) async {
// January and February headers should be showing, but no March
expect(find.text('January 2015'), findsOneWidget);
expect(find.text('February 2015'), findsOneWidget);
expect(find.text('March 2015'), findsNothing);
});
});
testWidgets('Current month header should be visible if no date is selected',
(WidgetTester tester) async {
firstDate = DateTime(2015, DateTime.january, 1);
lastDate = DateTime(2016, DateTime.december, 31);
currentDate = DateTime(2016, DateTime.september, 1);
initialDateRange = null;
await preparePicker(tester, (Future<DateTimeRange> range) async {
// September and October headers should be showing, but no August
expect(find.text('September 2016'), findsOneWidget);
expect(find.text('October 2016'), findsOneWidget);
expect(find.text('August 2016'), findsNothing);
});
});
testWidgets('Can cancel', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.byIcon(Icons.close));
expect(await range, isNull);
});
});
testWidgets('Can select a range', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('12').first);
await tester.tap(find.text('14').first);
await tester.tap(find.text('SAVE'));
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 12),
end: DateTime(2016, DateTime.january, 14),
));
});
});
testWidgets('Tapping earlier date resets selected range', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('12').first);
await tester.tap(find.text('11').first);
await tester.tap(find.text('15').first);
await tester.tap(find.text('SAVE'));
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 11),
end: DateTime(2016, DateTime.january, 15),
));
});
});
testWidgets('Can select single day range', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('12').first);
await tester.tap(find.text('12').first);
await tester.tap(find.text('SAVE'));
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 12),
end: DateTime(2016, DateTime.january, 12),
));
});
});
testWidgets('Cannot select a day outside bounds', (WidgetTester tester) async {
initialDateRange = DateTimeRange(
start: DateTime(2017, DateTime.january, 13),
end: DateTime(2017, DateTime.january, 15),
);
firstDate = DateTime(2017, DateTime.january, 12);
lastDate = DateTime(2017, DateTime.january, 16);
await preparePicker(tester, (Future<DateTimeRange> range) async {
// Earlier than firstDate. Should be ignored.
await tester.tap(find.text('10'));
// Later than lastDate. Should be ignored.
await tester.tap(find.text('20'));
await tester.tap(find.text('SAVE'));
// We should still be on the initial date.
expect(await range, initialDateRange);
});
});
testWidgets('Can toggle to input entry mode', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
expect(find.byType(TextField), findsNothing);
await tester.tap(find.byIcon(Icons.edit));
await tester.pumpAndSettle();
expect(find.byType(TextField), findsNWidgets(2));
});
});
testWidgets('Toggle to input mode keeps selected date', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('12').first);
await tester.tap(find.text('14').first);
await tester.tap(find.byIcon(Icons.edit));
await tester.pumpAndSettle();
await tester.tap(find.text('OK'));
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 12),
end: DateTime(2016, DateTime.january, 14),
));
});
});
group('Toggle from input entry mode validates dates', () {
setUp(() {
initialEntryMode = DatePickerEntryMode.input;
});
testWidgets('Invalid start date', (WidgetTester tester) async {
// Invalid start date should have neither a start nor end date selected in
// calendar mode
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/27/1918');
await tester.enterText(find.byType(TextField).at(1), '12/25/2016');
await tester.tap(find.byIcon(Icons.calendar_today));
await tester.pumpAndSettle();
expect(find.text('Start Date'), findsOneWidget);
expect(find.text('End Date'), findsOneWidget);
});
});
testWidgets('Invalid end date', (WidgetTester tester) async {
// Invalid end date should only have a start date selected
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/24/2016');
await tester.enterText(find.byType(TextField).at(1), '12/25/2050');
await tester.tap(find.byIcon(Icons.calendar_today));
await tester.pumpAndSettle();
expect(find.text('Dec 24'), findsOneWidget);
expect(find.text('End Date'), findsOneWidget);
});
});
testWidgets('Invalid range', (WidgetTester tester) async {
// Start date after end date should just use the start date
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
await tester.enterText(find.byType(TextField).at(1), '12/24/2016');
await tester.tap(find.byIcon(Icons.calendar_today));
await tester.pumpAndSettle();
expect(find.text('Dec 25'), findsOneWidget);
expect(find.text('End Date'), findsOneWidget);
});
});
});
testWidgets('OK Cancel button layout', (WidgetTester tester) async {
Widget buildFrame(TextDirection textDirection) {
return MaterialApp(
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return ElevatedButton(
child: const Text('X'),
onPressed: () {
showDateRangePicker(
context: context,
firstDate:DateTime(2001, DateTime.january, 1),
lastDate: DateTime(2031, DateTime.december, 31),
builder: (BuildContext context, Widget? child) {
return Directionality(
textDirection: textDirection,
child: child ?? const SizedBox(),
);
},
);
},
);
},
),
),
),
);
}
Future<void> showOkCancelDialog(TextDirection textDirection) async {
await tester.pumpWidget(buildFrame(textDirection));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.edit));
await tester.pumpAndSettle();
}
Future<void> dismissOkCancelDialog() async {
await tester.tap(find.text('CANCEL'));
await tester.pumpAndSettle();
}
await showOkCancelDialog(TextDirection.ltr);
expect(tester.getBottomRight(find.text('OK')).dx, 622);
expect(tester.getBottomLeft(find.text('OK')).dx, 594);
expect(tester.getBottomRight(find.text('CANCEL')).dx, 560);
await dismissOkCancelDialog();
await showOkCancelDialog(TextDirection.rtl);
expect(tester.getBottomRight(find.text('OK')).dx, 206);
expect(tester.getBottomLeft(find.text('OK')).dx, 178);
expect(tester.getBottomRight(find.text('CANCEL')).dx, 324);
await dismissOkCancelDialog();
});
group('Haptic feedback', () {
const Duration hapticFeedbackInterval = Duration(milliseconds: 10);
late FeedbackTester feedback;
setUp(() {
feedback = FeedbackTester();
initialDateRange = DateTimeRange(
start: DateTime(2017, DateTime.january, 15),
end: DateTime(2017, DateTime.january, 17),
);
firstDate = DateTime(2017, DateTime.january, 10);
lastDate = DateTime(2018, DateTime.january, 20);
});
tearDown(() {
feedback.dispose();
});
testWidgets('Selecting dates vibrates', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('10').first);
await tester.pump(hapticFeedbackInterval);
expect(feedback.hapticCount, 1);
await tester.tap(find.text('12').first);
await tester.pump(hapticFeedbackInterval);
expect(feedback.hapticCount, 2);
await tester.tap(find.text('14').first);
await tester.pump(hapticFeedbackInterval);
expect(feedback.hapticCount, 3);
});
});
testWidgets('Tapping unselectable date does not vibrate', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('8').first);
await tester.pump(hapticFeedbackInterval);
expect(feedback.hapticCount, 0);
});
});
});
group('Keyboard navigation', () {
testWidgets('Can toggle to calendar entry mode', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
expect(find.byType(TextField), findsNothing);
// Navigate to the entry toggle button and activate it
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should be in the input mode
expect(find.byType(TextField), findsNWidgets(2));
});
});
testWidgets('Can navigate date grid with arrow keys', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
// Navigate to the grid
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.pumpAndSettle();
// Navigate from Jan 15 to Jan 18 with arrow keys
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pumpAndSettle();
// Activate it to select the beginning of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate to Jan 29
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.pumpAndSettle();
// Activate it to select the end of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate out of the grid and to the OK button
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Activate OK
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should have selected Jan 18 - Jan 29
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 18),
end: DateTime(2016, DateTime.january, 29),
));
});
});
testWidgets('Navigating with arrow keys scrolls as needed', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
// Jan and Feb headers should be showing, but no March
expect(find.text('January 2016'), findsOneWidget);
expect(find.text('February 2016'), findsOneWidget);
expect(find.text('March 2016'), findsNothing);
// Navigate to the grid
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Navigate from Jan 15 to Jan 18 with arrow keys
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.pumpAndSettle();
// Activate it to select the beginning of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate to Mar 17
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.pumpAndSettle();
// Jan should have scrolled off, Mar should be visible
expect(find.text('January 2016'), findsNothing);
expect(find.text('February 2016'), findsOneWidget);
expect(find.text('March 2016'), findsOneWidget);
// Activate it to select the end of the range
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate out of the grid and to the OK button
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Activate OK
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should have selected Jan 18 - Mar 17
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 18),
end: DateTime(2016, DateTime.march, 17),
));
});
});
testWidgets('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
// Navigate to the grid
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Navigate from Jan 15 to 19 with arrow keys
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pumpAndSettle();
// Activate it
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate to Jan 21
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
await tester.pumpAndSettle();
// Activate it
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Navigate out of the grid and to the OK button
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
// Activate OK
await tester.sendKeyEvent(LogicalKeyboardKey.space);
await tester.pumpAndSettle();
// Should have selected Jan 19 - Mar 21
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.january, 19),
end: DateTime(2016, DateTime.january, 21),
));
},
textDirection: TextDirection.rtl);
});
});
group('Input mode', () {
setUp(() {
firstDate = DateTime(2015, DateTime.january, 1);
lastDate = DateTime(2017, DateTime.december, 31);
initialDateRange = DateTimeRange(
start: DateTime(2017, DateTime.january, 15),
end: DateTime(2017, DateTime.january, 17),
);
initialEntryMode = DatePickerEntryMode.input;
});
testWidgets('Initial entry mode is used', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
expect(find.byType(TextField), findsNWidgets(2));
});
});
testWidgets('All custom strings are used', (WidgetTester tester) async {
initialDateRange = null;
cancelText = 'nope';
confirmText = 'yep';
fieldStartHintText = 'hint1';
fieldEndHintText = 'hint2';
fieldStartLabelText = 'label1';
fieldEndLabelText = 'label2';
helpText = 'help';
await preparePicker(tester, (Future<DateTimeRange> range) async {
expect(find.text(cancelText!), findsOneWidget);
expect(find.text(confirmText!), findsOneWidget);
expect(find.text(fieldStartHintText!), findsOneWidget);
expect(find.text(fieldEndHintText!), findsOneWidget);
expect(find.text(fieldStartLabelText!), findsOneWidget);
expect(find.text(fieldEndLabelText!), findsOneWidget);
expect(find.text(helpText!), findsOneWidget);
});
});
testWidgets('Initial date is the default', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.tap(find.text('OK'));
expect(await range, DateTimeRange(
start: DateTime(2017, DateTime.january, 15),
end: DateTime(2017, DateTime.january, 17),
));
});
});
testWidgets('Can toggle to calendar entry mode', (WidgetTester tester) async {
await preparePicker(tester, (Future<DateTimeRange> range) async {
expect(find.byType(TextField), findsNWidgets(2));
await tester.tap(find.byIcon(Icons.calendar_today));
await tester.pumpAndSettle();
expect(find.byType(TextField), findsNothing);
});
});
testWidgets('Toggle to calendar mode keeps selected date', (WidgetTester tester) async {
initialDateRange = null;
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
await tester.enterText(find.byType(TextField).at(1), '12/27/2016');
await tester.tap(find.byIcon(Icons.calendar_today));
await tester.pumpAndSettle();
await tester.tap(find.text('SAVE'));
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.december, 25),
end: DateTime(2016, DateTime.december, 27),
));
});
});
testWidgets('Entered text returns range', (WidgetTester tester) async {
initialDateRange = null;
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/25/2016');
await tester.enterText(find.byType(TextField).at(1), '12/27/2016');
await tester.tap(find.text('OK'));
expect(await range, DateTimeRange(
start: DateTime(2016, DateTime.december, 25),
end: DateTime(2016, DateTime.december, 27),
));
});
});
testWidgets('Too short entered text shows error', (WidgetTester tester) async {
initialDateRange = null;
errorFormatText = 'oops';
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/25');
await tester.enterText(find.byType(TextField).at(1), '12/25');
expect(find.text(errorFormatText!), findsNothing);
await tester.tap(find.text('OK'));
await tester.pumpAndSettle();
expect(find.text(errorFormatText!), findsNWidgets(2));
});
});
testWidgets('Bad format entered text shows error', (WidgetTester tester) async {
initialDateRange = null;
errorFormatText = 'oops';
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '20202014');
await tester.enterText(find.byType(TextField).at(1), '20212014');
expect(find.text(errorFormatText!), findsNothing);
await tester.tap(find.text('OK'));
await tester.pumpAndSettle();
expect(find.text(errorFormatText!), findsNWidgets(2));
});
});
testWidgets('Invalid entered text shows error', (WidgetTester tester) async {
initialDateRange = null;
errorInvalidText = 'oops';
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '08/08/2014');
await tester.enterText(find.byType(TextField).at(1), '08/08/2014');
expect(find.text(errorInvalidText!), findsNothing);
await tester.tap(find.text('OK'));
await tester.pumpAndSettle();
expect(find.text(errorInvalidText!), findsNWidgets(2));
});
});
testWidgets('End before start date shows error', (WidgetTester tester) async {
initialDateRange = null;
errorInvalidRangeText = 'oops';
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/27/2016');
await tester.enterText(find.byType(TextField).at(1), '12/25/2016');
expect(find.text(errorInvalidRangeText!), findsNothing);
await tester.tap(find.text('OK'));
await tester.pumpAndSettle();
expect(find.text(errorInvalidRangeText!), findsOneWidget);
});
});
testWidgets('Error text only displayed for invalid date', (WidgetTester tester) async {
initialDateRange = null;
errorInvalidText = 'oops';
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/27/2016');
await tester.enterText(find.byType(TextField).at(1), '01/01/2018');
expect(find.text(errorInvalidText!), findsNothing);
await tester.tap(find.text('OK'));
await tester.pumpAndSettle();
expect(find.text(errorInvalidText!), findsOneWidget);
});
});
testWidgets('End before start date does not get passed to calendar mode', (WidgetTester tester) async {
initialDateRange = null;
await preparePicker(tester, (Future<DateTimeRange> range) async {
await tester.enterText(find.byType(TextField).at(0), '12/27/2016');
await tester.enterText(find.byType(TextField).at(1), '12/25/2016');
await tester.tap(find.byIcon(Icons.calendar_today));
await tester.pumpAndSettle();
await tester.tap(find.text('SAVE'));
await tester.pumpAndSettle();
// Save button should be disabled, so dialog should still be up
// with the first date selected, but no end date
expect(find.text('Dec 27'), findsOneWidget);
expect(find.text('End Date'), findsOneWidget);
});
});
testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async {
// Given a custom paint for an input decoration, extract the border and
// fill color and test them against the expected values.
void _testInputDecorator(CustomPaint decoratorPaint, InputBorder expectedBorder, Color expectedContainerColor) {
final dynamic/*_InputBorderPainter*/ inputBorderPainter = decoratorPaint.foregroundPainter;
final dynamic/*_InputBorderTween*/ inputBorderTween = inputBorderPainter.border;
final Animation<double> animation = inputBorderPainter.borderAnimation as Animation<double>;
final InputBorder actualBorder = inputBorderTween.evaluate(animation) as InputBorder;
final Color containerColor = inputBorderPainter.blendedColor as Color;
expect(actualBorder, equals(expectedBorder));
expect(containerColor, equals(expectedContainerColor));
}
late BuildContext buttonContext;
const InputBorder border = InputBorder.none;
await tester.pumpWidget(MaterialApp(
theme: ThemeData.light().copyWith(
inputDecorationTheme: const InputDecorationTheme(
filled: false,
border: border,
),
),
home: Material(
child: Builder(
builder: (BuildContext context) {
return ElevatedButton(
onPressed: () {
buttonContext = context;
},
child: const Text('Go'),
);
},
),
),
));
await tester.tap(find.text('Go'));
expect(buttonContext, isNotNull);
showDateRangePicker(
context: buttonContext,
initialDateRange: initialDateRange,
firstDate: firstDate,
lastDate: lastDate,
initialEntryMode: DatePickerEntryMode.input,
);
await tester.pumpAndSettle();
final Finder borderContainers = find.descendant(
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_BorderContainer'),
matching: find.byWidgetPredicate((Widget w) => w is CustomPaint),
);
// Test the start date text field
_testInputDecorator(tester.widget(borderContainers.first), border, Colors.transparent);
// Test the end date text field
_testInputDecorator(tester.widget(borderContainers.last), border, Colors.transparent);
});
});
}