From 3cf206ba2cfec7d4d29438b9baa7bfb0acf0f722 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:24:48 -0700 Subject: [PATCH] Update `CheckboxListTile` and `CalendarDatePicker` tests for M2/M3 (#131363) --- .../material/calendar_date_picker_test.dart | 99 ++++++++++- .../material/checkbox_list_tile_test.dart | 162 +++++++++++++++++- 2 files changed, 254 insertions(+), 7 deletions(-) diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index a678bb40183..c4d356a04ae 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -26,9 +26,10 @@ void main() { DatePickerMode initialCalendarMode = DatePickerMode.day, SelectableDayPredicate? selectableDayPredicate, TextDirection textDirection = TextDirection.ltr, + bool? useMaterial3, }) { return MaterialApp( - theme: ThemeData(useMaterial3: false), + theme: ThemeData(useMaterial3: useMaterial3), home: Material( child: Directionality( textDirection: textDirection, @@ -347,8 +348,9 @@ void main() { expect(find.text('January 2018'), findsOneWidget); }); - testWidgets('currentDate is highlighted', (WidgetTester tester) async { + testWidgets('Material2 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( + useMaterial3: false, currentDate: DateTime(2016, 1, 2), )); const Color todayColor = Color(0xff2196f3); // default primary color @@ -363,8 +365,26 @@ void main() { ); }); - testWidgets('currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + testWidgets('Material3 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( + useMaterial3: true, + currentDate: DateTime(2016, 1, 2), + )); + const Color todayColor = Color(0xff6750a4); // default primary color + expect( + Material.of(tester.element(find.text('2'))), + // The current day should be painted with a circle outline. + paints..circle( + color: todayColor, + style: PaintingStyle.stroke, + strokeWidth: 1.0, + ), + ); + }); + + testWidgets('Material2 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + await tester.pumpWidget(calendarDatePicker( + useMaterial3: false, firstDate: DateTime(2016, 1, 3), lastDate: DateTime(2016, 1, 31), currentDate: DateTime(2016, 1, 2), // not between first and last @@ -383,6 +403,27 @@ void main() { ); }); + testWidgets('Material3 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + await tester.pumpWidget(calendarDatePicker( + useMaterial3: true, + firstDate: DateTime(2016, 1, 3), + lastDate: DateTime(2016, 1, 31), + currentDate: DateTime(2016, 1, 2), // not between first and last + initialDate: DateTime(2016, 1, 5), + )); + const Color disabledColor = Color(0x616750a4); // default disabled color + expect( + Material.of(tester.element(find.text('2'))), + // The current day should be painted with a circle outline. + paints + ..circle( + color: disabledColor, + style: PaintingStyle.stroke, + strokeWidth: 1.0, + ), + ); + }); + testWidgets('Selecting date does not switch picker to year selection', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2020, DateTime.may, 10), @@ -397,7 +438,7 @@ void main() { expect(find.text('2017'), findsNothing); }); - testWidgets('Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { + testWidgets('Material2 - Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { final Key pickerKey = UniqueKey(); final DateTime initialDate = DateTime(2020, 1, 21); final DateTime updatedDate = DateTime(1976, 2, 23); @@ -407,6 +448,7 @@ void main() { await tester.pumpWidget(calendarDatePicker( key: pickerKey, + useMaterial3: false, initialDate: initialDate, firstDate: firstDate, lastDate: lastDate, @@ -425,6 +467,55 @@ void main() { // Change to the updated initialDate await tester.pumpWidget(calendarDatePicker( key: pickerKey, + useMaterial3: false, + initialDate: updatedDate, + firstDate: firstDate, + lastDate: lastDate, + onDateChanged: (DateTime value) {}, + )); + // Wait for the page scroll animation to finish. + await tester.pumpAndSettle(const Duration(milliseconds: 200)); + + // Month should show as February 1976 + expect(find.text('January 2020'), findsNothing); + expect(find.text('February 1976'), findsOneWidget); + // Selected date should be painted with a colored circle. + expect( + Material.of(tester.element(find.text('23'))), + paints..circle(color: selectedColor, style: PaintingStyle.fill), + ); + }); + + testWidgets('Material3 - Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { + final Key pickerKey = UniqueKey(); + final DateTime initialDate = DateTime(2020, 1, 21); + final DateTime updatedDate = DateTime(1976, 2, 23); + final DateTime firstDate = DateTime(1970); + final DateTime lastDate = DateTime(2099, 31, 12); + const Color selectedColor = Color(0xff6750a4); // default primary color + + await tester.pumpWidget(calendarDatePicker( + key: pickerKey, + useMaterial3: true, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate, + onDateChanged: (DateTime value) {}, + )); + await tester.pumpAndSettle(); + + // Month should show as January 2020 + expect(find.text('January 2020'), findsOneWidget); + // Selected date should be painted with a colored circle. + expect( + Material.of(tester.element(find.text('21'))), + paints..circle(color: selectedColor, style: PaintingStyle.fill), + ); + + // Change to the updated initialDate + await tester.pumpWidget(calendarDatePicker( + key: pickerKey, + useMaterial3: true, initialDate: updatedDate, firstDate: firstDate, lastDate: lastDate, diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 24f9cfb554d..3ae0bf9ffa2 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -38,7 +39,7 @@ void main() { expect(log, equals([false, '-', false])); }); - testWidgetsWithLeakTracking('CheckboxListTile checkColor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - CheckboxListTile checkColor test', (WidgetTester tester) async { const Color checkBoxBorderColor = Color(0xff2196f3); Color checkBoxCheckColor = const Color(0xffFFFFFF); @@ -70,6 +71,38 @@ void main() { expect(getCheckboxListTileRenderer(), paints..path(color: checkBoxBorderColor)..path(color: checkBoxCheckColor)); }); + testWidgetsWithLeakTracking('Material3 - CheckboxListTile checkColor test', (WidgetTester tester) async { + const Color checkBoxBorderColor = Color(0xff6750a4); + Color checkBoxCheckColor = const Color(0xffFFFFFF); + + Widget buildFrame(Color? color) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: CheckboxListTile( + value: true, + checkColor: color, + onChanged: (bool? value) {}, + ), + ), + ); + } + + RenderBox getCheckboxListTileRenderer() { + return tester.renderObject(find.byType(CheckboxListTile)); + } + + await tester.pumpWidget(buildFrame(null)); + await tester.pumpAndSettle(); + expect(getCheckboxListTileRenderer(), paints..path(color: checkBoxBorderColor)..path(color: checkBoxCheckColor)); + + checkBoxCheckColor = const Color(0xFF000000); + + await tester.pumpWidget(buildFrame(checkBoxCheckColor)); + await tester.pumpAndSettle(); + expect(getCheckboxListTileRenderer(), paints..path(color: checkBoxBorderColor)..path(color: checkBoxCheckColor)); + }); + testWidgetsWithLeakTracking('CheckboxListTile activeColor test', (WidgetTester tester) async { Widget buildFrame(Color? themeColor, Color? activeColor) { return wrap( @@ -710,7 +743,7 @@ void main() { ); }); - testWidgets('CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgets('Material2 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -826,6 +859,129 @@ void main() { ); }); + testWidgets('Material3 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + + const Color fillColor = Color(0xFF000000); + const Color activePressedOverlayColor = Color(0xFF000001); + const Color inactivePressedOverlayColor = Color(0xFF000002); + const Color hoverOverlayColor = Color(0xFF000003); + const Color hoverColor = Color(0xFF000005); + + Color? getOverlayColor(Set states) { + if (states.contains(MaterialState.pressed)) { + if (states.contains(MaterialState.selected)) { + return activePressedOverlayColor; + } + return inactivePressedOverlayColor; + } + if (states.contains(MaterialState.hovered)) { + return hoverOverlayColor; + } + return null; + } + const double splashRadius = 24.0; + + Widget buildCheckbox({bool active = false, bool useOverlay = true}) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: CheckboxListTile( + value: active, + onChanged: (_) { }, + fillColor: const MaterialStatePropertyAll(fillColor), + overlayColor: useOverlay ? MaterialStateProperty.resolveWith(getOverlayColor) : null, + hoverColor: hoverColor, + splashRadius: splashRadius, + ), + ), + ); + } + + await tester.pumpWidget(buildCheckbox(useOverlay: false)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )) : (paints..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )), + reason: 'Default inactive pressed Checkbox should have overlay color from fillColor', + ); + + await tester.pumpWidget(buildCheckbox(active: true, useOverlay: false)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )) : (paints..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )), + reason: 'Default active pressed Checkbox should have overlay color from fillColor', + ); + + await tester.pumpWidget(buildCheckbox()); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: inactivePressedOverlayColor, + radius: splashRadius, + )) : (paints..circle( + color: inactivePressedOverlayColor, + radius: splashRadius, + )), + reason: 'Inactive pressed Checkbox should have overlay color: $inactivePressedOverlayColor', + ); + + await tester.pumpWidget(buildCheckbox(active: true)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: activePressedOverlayColor, + radius: splashRadius, + )) : (paints..circle( + color: activePressedOverlayColor, + radius: splashRadius, + )), + reason: 'Active pressed Checkbox should have overlay color: $activePressedOverlayColor', + ); + + // Start hovering + await tester.pumpWidget(Container()); + await tester.pumpWidget(buildCheckbox()); + await tester.pumpAndSettle(); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints..circle( + color: hoverOverlayColor, + radius: splashRadius, + ), + reason: 'Hovered Checkbox should use overlay color $hoverOverlayColor over $hoverColor', + ); + }); + testWidgetsWithLeakTracking('CheckboxListTile respects splashRadius', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 30; @@ -881,7 +1037,7 @@ void main() { expect(tester.getSize(find.byType(Checkbox)), const Size(48.0, 48.0)); }); - testWidgetsWithLeakTracking('CheckboxListTile respects isError - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - CheckboxListTile respects isError', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true;