// 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/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; void main() { test('TimePickerThemeData copyWith, ==, hashCode basics', () { expect(const TimePickerThemeData(), const TimePickerThemeData().copyWith()); expect(const TimePickerThemeData().hashCode, const TimePickerThemeData().copyWith().hashCode); }); test('TimePickerThemeData lerp special cases', () { const TimePickerThemeData data = TimePickerThemeData(); expect(identical(TimePickerThemeData.lerp(data, data, 0.5), data), true); }); test('TimePickerThemeData null fields by default', () { const TimePickerThemeData timePickerTheme = TimePickerThemeData(); expect(timePickerTheme.backgroundColor, null); expect(timePickerTheme.hourMinuteTextColor, null); expect(timePickerTheme.hourMinuteColor, null); expect(timePickerTheme.dayPeriodTextColor, null); expect(timePickerTheme.dayPeriodColor, null); expect(timePickerTheme.dialHandColor, null); expect(timePickerTheme.dialBackgroundColor, null); expect(timePickerTheme.dialTextColor, null); expect(timePickerTheme.entryModeIconColor, null); expect(timePickerTheme.hourMinuteTextStyle, null); expect(timePickerTheme.dayPeriodTextStyle, null); expect(timePickerTheme.helpTextStyle, null); expect(timePickerTheme.shape, null); expect(timePickerTheme.hourMinuteShape, null); expect(timePickerTheme.dayPeriodShape, null); expect(timePickerTheme.dayPeriodBorderSide, null); expect(timePickerTheme.inputDecorationTheme, null); }); testWidgets('Default TimePickerThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TimePickerThemeData().debugFillProperties(builder); final List description = builder.properties .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) .map((DiagnosticsNode node) => node.toString()) .toList(); expect(description, []); }); testWidgets('TimePickerThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TimePickerThemeData( backgroundColor: Color(0xFFFFFFFF), hourMinuteTextColor: Color(0xFFFFFFFF), hourMinuteColor: Color(0xFFFFFFFF), dayPeriodTextColor: Color(0xFFFFFFFF), dayPeriodColor: Color(0xFFFFFFFF), dialHandColor: Color(0xFFFFFFFF), dialBackgroundColor: Color(0xFFFFFFFF), dialTextColor: Color(0xFFFFFFFF), entryModeIconColor: Color(0xFFFFFFFF), hourMinuteTextStyle: TextStyle(), dayPeriodTextStyle: TextStyle(), helpTextStyle: TextStyle(), shape: RoundedRectangleBorder(), hourMinuteShape: RoundedRectangleBorder(), dayPeriodShape: RoundedRectangleBorder(), dayPeriodBorderSide: BorderSide(), ).debugFillProperties(builder); final List description = builder.properties .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) .map((DiagnosticsNode node) => node.toString()) .toList(); expect(description, [ 'backgroundColor: Color(0xffffffff)', 'dayPeriodBorderSide: BorderSide', 'dayPeriodColor: Color(0xffffffff)', 'dayPeriodShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'dayPeriodTextColor: Color(0xffffffff)', 'dayPeriodTextStyle: TextStyle()', 'dialBackgroundColor: Color(0xffffffff)', 'dialHandColor: Color(0xffffffff)', 'dialTextColor: Color(0xffffffff)', 'entryModeIconColor: Color(0xffffffff)', 'helpTextStyle: TextStyle()', 'hourMinuteColor: Color(0xffffffff)', 'hourMinuteShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', 'hourMinuteTextColor: Color(0xffffffff)', 'hourMinuteTextStyle: TextStyle()', 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)' ]); }); testWidgets('Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { final ThemeData defaultTheme = ThemeData(); final bool material3 = defaultTheme.useMaterial3; await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final Material dialogMaterial = _dialogMaterial(tester); expect(dialogMaterial.color, defaultTheme.colorScheme.surface); expect(dialogMaterial.shape, material3 ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))) : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) ); final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); expect( dial, material3 ? (paints ..circle(color: defaultTheme.colorScheme.surfaceVariant.withOpacity(0.08)) // Dial background color. ..circle(color: Color(defaultTheme.colorScheme.primary.value))) : (paints ..circle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.08)) // Dial background color. ..circle(color: Color(defaultTheme.colorScheme.primary.value))), // Dial hand color. ); final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, material3 ? (Typography.material2021().englishLike.displayLarge! .merge(Typography.material2021().black.displayLarge) .copyWith(color: defaultTheme.colorScheme.onPrimaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) : (Typography.material2014().englishLike.displayMedium! .merge(Typography.material2014().black.displayMedium) .copyWith(color: defaultTheme.colorScheme.primary)), ); final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, material3 ? (Typography.material2021().englishLike.displayLarge! .merge(Typography.material2021().black.displayLarge) .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) : (Typography.material2014().englishLike.displayMedium! .merge(Typography.material2014().black.displayMedium) .copyWith(color: defaultTheme.colorScheme.onSurface)), ); final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, material3 ? (Typography.material2021().englishLike.titleMedium! .merge(Typography.material2021().black.titleMedium) .copyWith(color: defaultTheme.colorScheme.onTertiaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) : (Typography.material2014().englishLike.titleMedium! .merge(Typography.material2014().black.titleMedium) .copyWith(color: defaultTheme.colorScheme.primary)), ); final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, material3 ? (Typography.material2021().englishLike.titleMedium! .merge(Typography.material2021().black.titleMedium) .copyWith(color: defaultTheme.colorScheme.onTertiaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) : (Typography.material2014().englishLike.titleMedium! .merge(Typography.material2014().black.titleMedium) .copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.6))), ); final RenderParagraph helperText = _textRenderParagraph(tester, material3 ? 'Select time' : 'SELECT TIME'); expect( helperText.text.style, material3 ? (Typography.material2021().englishLike.bodyMedium! .merge(Typography.material2021().black.bodyMedium) .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) : (Typography.material2014().englishLike.labelSmall! .merge(Typography.material2014().black.labelSmall)), ); final CustomPaint dialPaint = tester.widget(findDialPaint); final dynamic dialPainter = dialPaint.painter; // ignore: avoid_dynamic_calls final List primaryLabels = dialPainter.primaryLabels as List; expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, material3 ? (Typography.material2021().englishLike.bodyLarge! .merge(Typography.material2021().black.bodyLarge) .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) : (Typography.material2014().englishLike.bodyLarge! .merge(Typography.material2014().black.bodyLarge) .copyWith(color: defaultTheme.colorScheme.onSurface)), ); // ignore: avoid_dynamic_calls final List selectedLabels = dialPainter.selectedLabels as List; expect( // ignore: avoid_dynamic_calls selectedLabels.first.painter.text.style, material3 ? (Typography.material2021().englishLike.bodyLarge! .merge(Typography.material2021().black.bodyLarge) .copyWith(color: defaultTheme.colorScheme.onPrimary, decorationColor: defaultTheme.colorScheme.onSurface)) : (Typography.material2014().englishLike.bodyLarge! .merge(Typography.material2014().white.bodyLarge) .copyWith(color: defaultTheme.colorScheme.onPrimary)), ); final Material hourMaterial = _textMaterial(tester, '7'); expect(hourMaterial.color, material3 ? defaultTheme.colorScheme.primaryContainer : defaultTheme.colorScheme.primary.withOpacity(0.12)); expect(hourMaterial.shape, material3 ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) ); final Material minuteMaterial = _textMaterial(tester, '15'); expect(minuteMaterial.color, material3 ? defaultTheme.colorScheme.surfaceVariant : defaultTheme.colorScheme.onSurface.withOpacity(0.12)); expect(minuteMaterial.shape, material3 ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) ); final Material amMaterial = _textMaterial(tester, 'AM'); expect(amMaterial.color, material3 ? defaultTheme.colorScheme.tertiaryContainer : defaultTheme.colorScheme.primary.withOpacity(0.12)); final Material pmMaterial = _textMaterial(tester, 'PM'); expect(pmMaterial.color, Colors.transparent); final Color expectedBorderColor = Color.alphaBlend( defaultTheme.colorScheme.onSurface.withOpacity(0.38), defaultTheme.colorScheme.surface, ); final Material dayPeriodMaterial = _dayPeriodMaterial(tester); expect( dayPeriodMaterial.shape, material3 ? RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(8.0)), side: BorderSide(color: defaultTheme.colorScheme.outline), ) : RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(4.0)), side: BorderSide(color: expectedBorderColor), ), ); final Container dayPeriodDivider = _dayPeriodDivider(tester); expect( dayPeriodDivider.decoration, material3 ? BoxDecoration(border: Border(left: BorderSide(color: defaultTheme.colorScheme.outline))) : BoxDecoration(border: Border(left: BorderSide(color: expectedBorderColor))), ); final IconButton entryModeIconButton = _entryModeIconButton(tester); expect( entryModeIconButton.color, material3 ? null : defaultTheme.colorScheme.onSurface.withOpacity(0.6), ); }); testWidgets('Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { final ThemeData defaultTheme = ThemeData(); final bool material3 = defaultTheme.useMaterial3; await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme, entryMode: TimePickerEntryMode.input)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final InputDecoration hourDecoration = _textField(tester, '7').decoration!; expect(hourDecoration.filled, true); expect(hourDecoration.fillColor, material3 ? defaultTheme.colorScheme.surfaceVariant : MaterialStateColor.resolveWith((Set states) => defaultTheme.colorScheme.onSurface.withOpacity(0.12))); expect(hourDecoration.enabledBorder, material3 ? const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: Colors.transparent)) : const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent))); expect(hourDecoration.errorBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2))); expect(hourDecoration.focusedBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2))); expect(hourDecoration.focusedErrorBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2))); expect( hourDecoration.hintStyle, material3 ? TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)) : (Typography.material2014().englishLike.displayMedium! .merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)))), ); }); testWidgets('Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(); final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme); final bool material3 = theme.useMaterial3; await tester.pumpWidget(_TimePickerLauncher(themeData: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final Material dialogMaterial = _dialogMaterial(tester); expect(dialogMaterial.color, timePickerTheme.backgroundColor); expect(dialogMaterial.shape, timePickerTheme.shape); final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); expect( dial, paints ..circle(color: Color(timePickerTheme.dialBackgroundColor!.value)) // Dial background color. ..circle(color: Color(timePickerTheme.dialHandColor!.value)), // Dial hand color. ); final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, material3 ? (Typography.material2021().englishLike.bodyMedium! .merge(Typography.material2021().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f))) : (Typography.material2014().englishLike.bodyMedium! .merge(Typography.material2014().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _selectedColor)), ); final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, material3 ? (Typography.material2021().englishLike.bodyMedium! .merge(Typography.material2021().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f))) : (Typography.material2014().englishLike.bodyMedium! .merge(Typography.material2014().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _unselectedColor)), ); final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, material3 ? (Typography.material2021().englishLike.bodyMedium! .merge(Typography.material2021().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f))) : (Typography.material2014().englishLike.titleMedium! .merge(Typography.material2014().black.titleMedium) .merge(timePickerTheme.dayPeriodTextStyle) .copyWith(color: _selectedColor)), ); final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, material3 ? (Typography.material2021().englishLike.bodyMedium! .merge(Typography.material2021().black.bodyMedium) .merge(timePickerTheme.hourMinuteTextStyle) .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f))) : (Typography.material2014().englishLike.titleMedium! .merge(Typography.material2014().black.titleMedium) .merge(timePickerTheme.dayPeriodTextStyle) .copyWith(color: _unselectedColor)), ); final RenderParagraph helperText = _textRenderParagraph(tester, material3 ? 'Select time' : 'SELECT TIME'); expect( helperText.text.style, material3 ? (Typography.material2021().englishLike.bodyMedium! .merge(Typography.material2021().black.bodyMedium) .merge(timePickerTheme.helpTextStyle).copyWith(color: theme.colorScheme.onSurface, decorationColor: theme.colorScheme.onSurface)) : (Typography.material2014().englishLike.bodyMedium! .merge(Typography.material2014().black.bodyMedium) .merge(timePickerTheme.helpTextStyle)), ); final CustomPaint dialPaint = tester.widget(findDialPaint); final dynamic dialPainter = dialPaint.painter; // ignore: avoid_dynamic_calls final List primaryLabels = dialPainter.primaryLabels as List; expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, material3 ? (Typography.material2021().englishLike.bodyLarge! .merge(Typography.material2021().black.bodyLarge) .copyWith(color: _unselectedColor, decorationColor: theme.colorScheme.onSurface)) : (Typography.material2014().englishLike.bodyLarge! .merge(Typography.material2014().black.bodyLarge) .copyWith(color: _unselectedColor)), ); // ignore: avoid_dynamic_calls final List selectedLabels = dialPainter.selectedLabels as List; expect( // ignore: avoid_dynamic_calls selectedLabels.first.painter.text.style, material3 ? (Typography.material2021().englishLike.bodyLarge! .merge(Typography.material2021().black.bodyLarge) .copyWith(color: _selectedColor, decorationColor: theme.colorScheme.onSurface)) : (Typography.material2014().englishLike.bodyLarge! .merge(Typography.material2014().white.bodyLarge) .copyWith(color: _selectedColor)), ); final Material hourMaterial = _textMaterial(tester, '7'); expect(hourMaterial.color, _selectedColor); expect(hourMaterial.shape, timePickerTheme.hourMinuteShape); final Material minuteMaterial = _textMaterial(tester, '15'); expect(minuteMaterial.color, _unselectedColor); expect(minuteMaterial.shape, timePickerTheme.hourMinuteShape); final Material amMaterial = _textMaterial(tester, 'AM'); expect(amMaterial.color, _selectedColor); final Material pmMaterial = _textMaterial(tester, 'PM'); expect(pmMaterial.color, _unselectedColor); final Material dayPeriodMaterial = _dayPeriodMaterial(tester); expect( dayPeriodMaterial.shape, timePickerTheme.dayPeriodShape!.copyWith(side: timePickerTheme.dayPeriodBorderSide), ); final Container dayPeriodDivider = _dayPeriodDivider(tester); expect( dayPeriodDivider.decoration, BoxDecoration(border: Border(left: timePickerTheme.dayPeriodBorderSide!)), ); final IconButton entryModeIconButton = _entryModeIconButton(tester); expect( entryModeIconButton.color, material3 ? null : timePickerTheme.entryModeIconColor, ); }); testWidgets('Time picker uses values from TimePickerThemeData with InputDecorationTheme - input mode', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(includeInputDecoration: true); final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme); await tester.pumpWidget(_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final InputDecoration hourDecoration = _textField(tester, '7').decoration!; expect(hourDecoration.filled, timePickerTheme.inputDecorationTheme!.filled); expect(hourDecoration.fillColor, timePickerTheme.inputDecorationTheme!.fillColor); expect(hourDecoration.enabledBorder, timePickerTheme.inputDecorationTheme!.enabledBorder); expect(hourDecoration.errorBorder, timePickerTheme.inputDecorationTheme!.errorBorder); expect(hourDecoration.focusedBorder, timePickerTheme.inputDecorationTheme!.focusedBorder); expect(hourDecoration.focusedErrorBorder, timePickerTheme.inputDecorationTheme!.focusedErrorBorder); expect(hourDecoration.hintStyle, timePickerTheme.inputDecorationTheme!.hintStyle); }); testWidgets('Time picker uses values from TimePickerThemeData without InputDecorationTheme - input mode', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(); final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme); await tester.pumpWidget(_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final InputDecoration hourDecoration = _textField(tester, '7').decoration!; expect(hourDecoration.fillColor?.value, timePickerTheme.hourMinuteColor?.value); }); } final Color _selectedColor = Colors.green[100]!; final Color _unselectedColor = Colors.green[200]!; TimePickerThemeData _timePickerTheme({bool includeInputDecoration = false}) { Color getColor(Set states) { return states.contains(MaterialState.selected) ? _selectedColor : _unselectedColor; } final MaterialStateColor materialStateColor = MaterialStateColor.resolveWith(getColor); return TimePickerThemeData( backgroundColor: Colors.orange, hourMinuteTextColor: materialStateColor, hourMinuteColor: materialStateColor, dayPeriodTextColor: materialStateColor, dayPeriodColor: materialStateColor, dialHandColor: Colors.brown, dialBackgroundColor: Colors.pinkAccent, dialTextColor: materialStateColor, entryModeIconColor: Colors.red, hourMinuteTextStyle: const TextStyle(fontSize: 8.0), dayPeriodTextStyle: const TextStyle(fontSize: 8.0), helpTextStyle: const TextStyle(fontSize: 8.0), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))), hourMinuteShape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))), dayPeriodShape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))), dayPeriodBorderSide: const BorderSide(color: Colors.blueAccent), inputDecorationTheme: includeInputDecoration ? const InputDecorationTheme( filled: true, fillColor: Colors.purple, enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.blue)), errorBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.green)), focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.yellow)), focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.red)), hintStyle: TextStyle(fontSize: 8), ) : null, ); } class _TimePickerLauncher extends StatelessWidget { const _TimePickerLauncher({ this.themeData, this.entryMode = TimePickerEntryMode.dial, }); final ThemeData? themeData; final TimePickerEntryMode entryMode; @override Widget build(BuildContext context) { return MaterialApp( theme: themeData, home: Material( child: Center( child: Builder( builder: (BuildContext context) { return ElevatedButton( child: const Text('X'), onPressed: () async { await showTimePicker( context: context, initialEntryMode: entryMode, initialTime: const TimeOfDay(hour: 7, minute: 15), ); }, ); }, ), ), ), ); } } Material _dialogMaterial(WidgetTester tester) { return tester.widget(find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first); } Material _textMaterial(WidgetTester tester, String text) { return tester.widget(find.ancestor(of: find.text(text), matching: find.byType(Material)).first); } TextField _textField(WidgetTester tester, String text) { return tester.widget(find.ancestor(of: find.text(text), matching: find.byType(TextField)).first); } Material _dayPeriodMaterial(WidgetTester tester) { return tester.widget(find.descendant(of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'), matching: find.byType(Material)).first); } Container _dayPeriodDivider(WidgetTester tester) { return tester.widget(find.descendant(of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'), matching: find.byType(Container)).at(0)); } IconButton _entryModeIconButton(WidgetTester tester) { return tester.widget(find.descendant(of: find.byType(Dialog), matching: find.byType(IconButton)).first); } RenderParagraph _textRenderParagraph(WidgetTester tester, String text) { return tester.element(find.text(text).first).renderObject! as RenderParagraph; } final Finder findDialPaint = find.descendant( of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_Dial'), matching: find.byWidgetPredicate((Widget w) => w is CustomPaint), );