From 348e63e27680f360067a6069c0cbd5e9579382f6 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Mon, 29 Jun 2026 09:49:18 -0700 Subject: [PATCH 1/4] Inital port of time_picker_test --- packages/material_ui/pubspec.yaml | 2 ++ .../time_picker_test.dart | 9 +++------ 2 files changed, 5 insertions(+), 6 deletions(-) rename packages/material_ui/{temporarily_disabled_tests => test}/time_picker_test.dart (99%) diff --git a/packages/material_ui/pubspec.yaml b/packages/material_ui/pubspec.yaml index 24800d39eff9..003f0b5b0eb9 100644 --- a/packages/material_ui/pubspec.yaml +++ b/packages/material_ui/pubspec.yaml @@ -28,6 +28,8 @@ dev_dependencies: file: ^7.0.1 flutter_goldens: path: ../../script/flutter_goldens + flutter_localizations: + sdk: flutter flutter_test: sdk: flutter # To track memory leaks. diff --git a/packages/material_ui/temporarily_disabled_tests/time_picker_test.dart b/packages/material_ui/test/time_picker_test.dart similarity index 99% rename from packages/material_ui/temporarily_disabled_tests/time_picker_test.dart rename to packages/material_ui/test/time_picker_test.dart index 5a3ecf6e3c45..d9cb7b3435e6 100644 --- a/packages/material_ui/temporarily_disabled_tests/time_picker_test.dart +++ b/packages/material_ui/test/time_picker_test.dart @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@Skip( - 'This file is skipped due to a cross-import that needs to be fixed. Tracked in https://github.com/flutter/flutter/issues/177028.', -) // This file is run as part of a reduced test set in CI on Mac and Windows // machines. @Tags(['reduced-test-set']) @@ -15,14 +12,14 @@ import 'dart:math' as math; import 'dart:ui'; import 'package:flutter/foundation.dart'; -import 'package:material_ui/material_ui.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:material_ui/material_ui.dart'; -import '../widgets/feedback_tester.dart'; -import '../widgets/semantics_tester.dart'; +import 'feedback_tester.dart'; +import 'semantics_tester.dart'; void main() { const okString = 'OK'; From ae414d3cb820b9cf233476f45dc63bc6e519a2a5 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Mon, 29 Jun 2026 15:08:41 -0700 Subject: [PATCH 2/4] Remove localization tests --- packages/material_ui/pubspec.yaml | 2 - .../material_ui/test/time_picker_test.dart | 214 +++--------------- 2 files changed, 26 insertions(+), 190 deletions(-) diff --git a/packages/material_ui/pubspec.yaml b/packages/material_ui/pubspec.yaml index 003f0b5b0eb9..24800d39eff9 100644 --- a/packages/material_ui/pubspec.yaml +++ b/packages/material_ui/pubspec.yaml @@ -28,8 +28,6 @@ dev_dependencies: file: ^7.0.1 flutter_goldens: path: ../../script/flutter_goldens - flutter_localizations: - sdk: flutter flutter_test: sdk: flutter # To track memory leaks. diff --git a/packages/material_ui/test/time_picker_test.dart b/packages/material_ui/test/time_picker_test.dart index d9cb7b3435e6..8dff8059bed2 100644 --- a/packages/material_ui/test/time_picker_test.dart +++ b/packages/material_ui/test/time_picker_test.dart @@ -14,7 +14,6 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_ui/material_ui.dart'; @@ -235,64 +234,6 @@ void main() { expect(selectedLabels.map((dynamic tp) => tp.inner as bool), inner0To23); }); - // Regression test for https://github.com/flutter/flutter/issues/164860 - testWidgets('Material3 - formats 24-hour numbers correctly in Farsi', ( - WidgetTester tester, - ) async { - await mediaQueryBoilerplate( - tester, - locale: const Locale('fa', 'IR'), - materialType: MaterialType.material3, - ); - - final labels00To23 = [ - '۰', - '۱', - '۲', - '۳', - '۴', - '۵', - '۶', - '۷', - '۸', - '۹', - '۱۰', - '۱۱', - '۱۲', - '۱۳', - '۱۴', - '۱۵', - '۱۶', - '۱۷', - '۱۸', - '۱۹', - '۲۰', - '۲۱', - '۲۲', - '۲۳', - ]; - final inner0To23 = List.generate(24, (int index) => index >= 12); - - final CustomPaint dialPaint = tester.widget(findDialPaint); - final dynamic dialPainter = dialPaint.painter; - // ignore: avoid_dynamic_calls - final primaryLabels = dialPainter.primaryLabels as List; - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.inner as bool), inner0To23); - - // ignore: avoid_dynamic_calls - final selectedLabels = dialPainter.selectedLabels as List; - expect( - // ignore: avoid_dynamic_calls - selectedLabels.map((dynamic tp) => tp.painter.text.text as String), - labels00To23, - ); - // ignore: avoid_dynamic_calls - expect(selectedLabels.map((dynamic tp) => tp.inner as bool), inner0To23); - }); - testWidgets('Material3 - Dial background uses correct default color', ( WidgetTester tester, ) async { @@ -1532,39 +1473,6 @@ void main() { }, ); - testWidgets( - 'TimePicker dialog displays centered separator between hour and minute inputs for non-english locale', - (WidgetTester tester) async { - tester.view.physicalSize = const Size(400, 800); - tester.view.devicePixelRatio = 1.0; - addTearDown(tester.view.reset); - - await tester.pumpWidget( - const MaterialApp( - localizationsDelegates: >[ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: [Locale('en'), Locale('es')], - locale: Locale('es'), - home: Material( - child: TimePickerDialog( - initialTime: TimeOfDay(hour: 12, minute: 0), - initialEntryMode: TimePickerEntryMode.input, - ), - ), - ), - ); - await tester.pumpAndSettle(); - - await expectLater( - find.byType(Dialog), - matchesGoldenFile('time_picker.dialog.separator.alignment.non_english_locale.png'), - ); - }, - ); - testWidgets('provides semantics information for text fields', (WidgetTester tester) async { final semantics = SemanticsTester(tester); await mediaQueryBoilerplate( @@ -2538,59 +2446,6 @@ void main() { expect(tester.getSize(findBorderPainter().first), const Size(96.0, 70.0)); }); - // Regression test for https://github.com/flutter/flutter/issues/162229. - testWidgets( - 'Time picker spacing between time control and day period control for locales using "a h:mm" pattern', - (WidgetTester tester) async { - addTearDown(tester.view.reset); - - final Finder amMaterialFinder = find.descendant( - of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_AmPmButton').first, - matching: find.byType(Material), - ); - final Finder timeControlFinder = find - .ancestor(of: find.text('7'), matching: find.byType(Row)) - .first; - - // Render in portrait mode. - tester.view.physicalSize = const Size(800, 800.5); - tester.view.devicePixelRatio = 1; - await mediaQueryBoilerplate( - tester, - materialType: MaterialType.material3, - locale: const Locale('ko', 'KR'), - ); - - const dayPeriodPortraitGap = 12.0; // From Material spec. - expect( - tester.getBottomLeft(timeControlFinder).dx - tester.getBottomRight(amMaterialFinder).dx, - dayPeriodPortraitGap, - ); - - // Dismiss the dialog. - final MaterialLocalizations materialLocalizations = MaterialLocalizations.of( - tester.element(find.byType(TextButton).first), - ); - await tester.tap(find.text(materialLocalizations.okButtonLabel)); - await tester.pumpAndSettle(); - - // Render in landscape mode. - tester.view.physicalSize = const Size(800.5, 800); - tester.view.devicePixelRatio = 1; - await mediaQueryBoilerplate( - tester, - materialType: MaterialType.material3, - locale: const Locale('ko', 'KR'), - ); - - const dayPeriodLandscapeGap = 16.0; // From Material spec. - expect( - tester.getTopLeft(timeControlFinder).dy - tester.getBottomLeft(amMaterialFinder).dy, - dayPeriodLandscapeGap, - ); - }, - ); - testWidgets('AM/PM buttons have correct selected/checked semantics for platform variant', ( WidgetTester tester, ) async { @@ -2692,56 +2547,40 @@ Future mediaQueryBoilerplate( bool tapButton = true, required MaterialType materialType, Orientation? orientation, - Locale locale = const Locale('en', 'US'), }) async { await tester.pumpWidget( - Theme( - data: ThemeData(useMaterial3: materialType == MaterialType.material3), - child: Localizations( - locale: locale, - delegates: const >[ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - child: MediaQuery( + MaterialApp( + theme: ThemeData(useMaterial3: materialType == MaterialType.material3), + builder: (BuildContext context, Widget? child) { + return MediaQuery( data: MediaQueryData( alwaysUse24HourFormat: alwaysUse24HourFormat, textScaler: textScaler, accessibleNavigation: accessibleNavigation, size: tester.view.physicalSize / tester.view.devicePixelRatio, ), - child: Material( - child: Center( - child: Directionality( - textDirection: TextDirection.ltr, - child: Navigator( - onGenerateRoute: (RouteSettings settings) { - return MaterialPageRoute( - builder: (BuildContext context) { - return TextButton( - onPressed: () { - showTimePicker( - context: context, - initialTime: initialTime, - initialEntryMode: entryMode, - helpText: helpText, - hourLabelText: hourLabelText, - minuteLabelText: minuteLabelText, - errorInvalidText: errorInvalidText, - onEntryModeChanged: onEntryModeChange, - orientation: orientation, - ); - }, - child: const Text('X'), - ); - }, - ); - }, - ), - ), - ), - ), - ), + child: child!, + ); + }, + home: Builder( + builder: (BuildContext context) { + return TextButton( + onPressed: () { + showTimePicker( + context: context, + initialTime: initialTime, + initialEntryMode: entryMode, + helpText: helpText, + hourLabelText: hourLabelText, + minuteLabelText: minuteLabelText, + errorInvalidText: errorInvalidText, + onEntryModeChanged: onEntryModeChange, + orientation: orientation, + ); + }, + child: const Text('X'), + ); + }, ), ), ); @@ -2890,7 +2729,6 @@ Future startPicker( MaterialApp( theme: theme ?? ThemeData(useMaterial3: materialType == MaterialType.material3), restorationScopeId: 'app', - locale: const Locale('en', 'US'), home: _TimePickerLauncher( onChanged: onChanged, entryMode: entryMode, From 0c254b175909fb53e18f968fb57994d66f0ccf49 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Mon, 29 Jun 2026 16:32:45 -0700 Subject: [PATCH 3/4] Add unawaited --- packages/material_ui/test/time_picker_test.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/material_ui/test/time_picker_test.dart b/packages/material_ui/test/time_picker_test.dart index 8dff8059bed2..108a4a1d05db 100644 --- a/packages/material_ui/test/time_picker_test.dart +++ b/packages/material_ui/test/time_picker_test.dart @@ -8,6 +8,7 @@ @TestOn('!chrome') library; +import 'dart:async'; import 'dart:math' as math; import 'dart:ui'; @@ -1224,11 +1225,11 @@ void main() { ); final BuildContext context = tester.element(find.text('Test')); - showTimePicker( + unawaited(showTimePicker( context: context, initialTime: const TimeOfDay(hour: 7, minute: 0), anchorPoint: const Offset(1000, 0), - ); + )); await tester.pumpAndSettle(); // Should take the right side of the screen @@ -1261,7 +1262,7 @@ void main() { final BuildContext context = tester.element(find.text('Test')); // By default it should place the dialog on the right screen - showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0)); + unawaited(showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0))); await tester.pumpAndSettle(); expect(tester.getTopLeft(find.byType(TimePickerDialog)), const Offset(410, 0)); @@ -1293,7 +1294,7 @@ void main() { final BuildContext context = tester.element(find.text('Test')); // By default it should place the dialog on the left screen - showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0)); + unawaited(showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0))); await tester.pumpAndSettle(); expect(tester.getTopLeft(find.byType(TimePickerDialog)), Offset.zero); @@ -1449,7 +1450,7 @@ void main() { find.byType(Dialog), matchesGoldenFile('m2_time_picker.dialog.separator.alignment.png'), ); - }, + } ); testWidgets( From e06eb2fc66d4d202b62e273832535d0d95130193 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Tue, 30 Jun 2026 10:24:13 -0700 Subject: [PATCH 4/4] Format --- .../material_ui/test/time_picker_test.dart | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/material_ui/test/time_picker_test.dart b/packages/material_ui/test/time_picker_test.dart index 108a4a1d05db..d541f99525ab 100644 --- a/packages/material_ui/test/time_picker_test.dart +++ b/packages/material_ui/test/time_picker_test.dart @@ -1225,11 +1225,13 @@ void main() { ); final BuildContext context = tester.element(find.text('Test')); - unawaited(showTimePicker( - context: context, - initialTime: const TimeOfDay(hour: 7, minute: 0), - anchorPoint: const Offset(1000, 0), - )); + unawaited( + showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + anchorPoint: const Offset(1000, 0), + ), + ); await tester.pumpAndSettle(); // Should take the right side of the screen @@ -1262,7 +1264,9 @@ void main() { final BuildContext context = tester.element(find.text('Test')); // By default it should place the dialog on the right screen - unawaited(showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0))); + unawaited( + showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0)), + ); await tester.pumpAndSettle(); expect(tester.getTopLeft(find.byType(TimePickerDialog)), const Offset(410, 0)); @@ -1294,7 +1298,9 @@ void main() { final BuildContext context = tester.element(find.text('Test')); // By default it should place the dialog on the left screen - unawaited(showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0))); + unawaited( + showTimePicker(context: context, initialTime: const TimeOfDay(hour: 7, minute: 0)), + ); await tester.pumpAndSettle(); expect(tester.getTopLeft(find.byType(TimePickerDialog)), Offset.zero); @@ -1450,7 +1456,7 @@ void main() { find.byType(Dialog), matchesGoldenFile('m2_time_picker.dialog.separator.alignment.png'), ); - } + }, ); testWidgets(