mirror of
https://github.com/flutter/flutter
synced 2024-09-12 21:01:59 +00:00
Seperate localization tests for Material2 and Material3 (#135779)
Seperates tests for the localizations package into Material2 and Material3 versions and removes dependency on theme. More info in #127064
This commit is contained in:
parent
0fa01b2156
commit
daa52b2501
|
@ -7,7 +7,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Nested Localizations', (WidgetTester tester) async {
|
||||
testWidgets('Material3 - Nested Localizations', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(MaterialApp( // Creates the outer Localizations widget.
|
||||
theme: ThemeData(useMaterial3: true),
|
||||
home: ListView(
|
||||
|
@ -29,6 +29,28 @@ void main() {
|
|||
expect(innerTracker.textBaseline, TextBaseline.ideographic);
|
||||
});
|
||||
|
||||
testWidgets('Material2 - Nested Localizations', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(MaterialApp( // Creates the outer Localizations widget.
|
||||
theme: ThemeData(useMaterial3: false),
|
||||
home: ListView(
|
||||
children: <Widget>[
|
||||
const LocalizationTracker(key: ValueKey<String>('outer')),
|
||||
Localizations(
|
||||
locale: const Locale('zh', 'CN'),
|
||||
delegates: GlobalMaterialLocalizations.delegates,
|
||||
child: const LocalizationTracker(key: ValueKey<String>('inner')),
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
// Most localized aspects of the TextTheme text styles are the same for the default US local and
|
||||
// for Chinese for Material2. The baselines for all text styles differ.
|
||||
final LocalizationTrackerState outerTracker = tester.state(find.byKey(const ValueKey<String>('outer'), skipOffstage: false));
|
||||
expect(outerTracker.textBaseline, TextBaseline.alphabetic);
|
||||
final LocalizationTrackerState innerTracker = tester.state(find.byKey(const ValueKey<String>('inner'), skipOffstage: false));
|
||||
expect(innerTracker.textBaseline, TextBaseline.ideographic);
|
||||
});
|
||||
|
||||
testWidgets('Localizations is compatible with ChangeNotifier.dispose() called during didChangeDependencies', (WidgetTester tester) async {
|
||||
// PageView calls ScrollPosition.dispose() during didChangeDependencies.
|
||||
await tester.pumpWidget(
|
||||
|
|
|
@ -92,10 +92,10 @@ void main() {
|
|||
}
|
||||
});
|
||||
|
||||
testWidgets('locale parameter overrides ambient locale', (WidgetTester tester) async {
|
||||
Widget buildFrame(bool useMaterial3) {
|
||||
testWidgets('Material2 - locale parameter overrides ambient locale', (WidgetTester tester) async {
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(useMaterial3: useMaterial3),
|
||||
theme: ThemeData(useMaterial3: false),
|
||||
locale: const Locale('en', 'US'),
|
||||
supportedLocales: const <Locale>[
|
||||
Locale('en', 'US'),
|
||||
|
@ -125,26 +125,7 @@ void main() {
|
|||
|
||||
Element getPicker() => tester.element(find.byType(CalendarDatePicker));
|
||||
|
||||
await tester.pumpWidget(buildFrame(true));
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Localizations.localeOf(getPicker()),
|
||||
const Locale('fr', 'CA'),
|
||||
);
|
||||
expect(
|
||||
Directionality.of(getPicker()),
|
||||
TextDirection.ltr,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Annuler'));
|
||||
|
||||
// The tests below are only relevant for Material 2. Once Material 2
|
||||
// support is deprecated and the APIs are removed, these tests
|
||||
// can be deleted.
|
||||
|
||||
await tester.pumpWidget(buildFrame(false));
|
||||
await tester.pumpWidget(buildFrame());
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
@ -158,13 +139,61 @@ void main() {
|
|||
);
|
||||
|
||||
await tester.tap(find.text('ANNULER'));
|
||||
|
||||
});
|
||||
|
||||
testWidgets('textDirection parameter overrides ambient textDirection', (WidgetTester tester) async {
|
||||
Widget buildFrame(bool useMaterial3) {
|
||||
testWidgets('Material3 - locale parameter overrides ambient locale', (WidgetTester tester) async {
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(useMaterial3: useMaterial3),
|
||||
theme: ThemeData(useMaterial3: true),
|
||||
locale: const Locale('en', 'US'),
|
||||
supportedLocales: const <Locale>[
|
||||
Locale('en', 'US'),
|
||||
Locale('fr', 'CA'),
|
||||
],
|
||||
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||
home: Material(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
await showDatePicker(
|
||||
context: context,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
locale: const Locale('fr', 'CA'),
|
||||
);
|
||||
},
|
||||
child: const Text('X'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Element getPicker() => tester.element(find.byType(CalendarDatePicker));
|
||||
|
||||
await tester.pumpWidget(buildFrame());
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Localizations.localeOf(getPicker()),
|
||||
const Locale('fr', 'CA'),
|
||||
);
|
||||
expect(
|
||||
Directionality.of(getPicker()),
|
||||
TextDirection.ltr,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Annuler'));
|
||||
});
|
||||
|
||||
testWidgets('Material2 - textDirection parameter overrides ambient textDirection', (WidgetTester tester) async {
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(useMaterial3: false),
|
||||
locale: const Locale('en', 'US'),
|
||||
home: Material(
|
||||
child: Builder(
|
||||
|
@ -189,22 +218,7 @@ void main() {
|
|||
|
||||
Element getPicker() => tester.element(find.byType(CalendarDatePicker));
|
||||
|
||||
await tester.pumpWidget(buildFrame(true));
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Directionality.of(getPicker()),
|
||||
TextDirection.rtl,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Cancel'));
|
||||
|
||||
// The tests below are only relevant for Material 2. Once Material 2
|
||||
// support is deprecated and the APIs are removed, these tests
|
||||
// can be deleted.
|
||||
|
||||
await tester.pumpWidget(buildFrame(false));
|
||||
await tester.pumpWidget(buildFrame());
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
@ -216,10 +230,50 @@ void main() {
|
|||
await tester.tap(find.text('CANCEL'));
|
||||
});
|
||||
|
||||
testWidgets('textDirection parameter takes precedence over locale parameter', (WidgetTester tester) async {
|
||||
Widget buildFrame(bool useMaterial3) {
|
||||
testWidgets('Material3 - textDirection parameter overrides ambient textDirection', (WidgetTester tester) async {
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(useMaterial3: useMaterial3),
|
||||
theme: ThemeData(useMaterial3: true),
|
||||
locale: const Locale('en', 'US'),
|
||||
home: Material(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
await showDatePicker(
|
||||
context: context,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
textDirection: TextDirection.rtl,
|
||||
);
|
||||
},
|
||||
child: const Text('X'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Element getPicker() => tester.element(find.byType(CalendarDatePicker));
|
||||
|
||||
await tester.pumpWidget(buildFrame());
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Directionality.of(getPicker()),
|
||||
TextDirection.rtl,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Cancel'));
|
||||
});
|
||||
|
||||
testWidgets('Material2 - textDirection parameter takes precedence over locale parameter', (WidgetTester tester) async {
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(useMaterial3: false),
|
||||
locale: const Locale('en', 'US'),
|
||||
supportedLocales: const <Locale>[
|
||||
Locale('en', 'US'),
|
||||
|
@ -250,7 +304,58 @@ void main() {
|
|||
|
||||
Element getPicker() => tester.element(find.byType(CalendarDatePicker));
|
||||
|
||||
await tester.pumpWidget(buildFrame(true));
|
||||
await tester.pumpWidget(buildFrame());
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Localizations.localeOf(getPicker()),
|
||||
const Locale('fr', 'CA'),
|
||||
);
|
||||
|
||||
expect(
|
||||
Directionality.of(getPicker()),
|
||||
TextDirection.rtl,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('ANNULER'));
|
||||
});
|
||||
|
||||
testWidgets('Material3 - textDirection parameter takes precedence over locale parameter', (WidgetTester tester) async {
|
||||
Widget buildFrame() {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(useMaterial3: true),
|
||||
locale: const Locale('en', 'US'),
|
||||
supportedLocales: const <Locale>[
|
||||
Locale('en', 'US'),
|
||||
Locale('fr', 'CA'),
|
||||
],
|
||||
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||
home: Material(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return TextButton(
|
||||
onPressed: () async {
|
||||
await showDatePicker(
|
||||
context: context,
|
||||
initialDate: initialDate,
|
||||
firstDate: firstDate,
|
||||
lastDate: lastDate,
|
||||
locale: const Locale('fr', 'CA'),
|
||||
textDirection: TextDirection.rtl,
|
||||
);
|
||||
},
|
||||
child: const Text('X'),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Element getPicker() => tester.element(find.byType(CalendarDatePicker));
|
||||
|
||||
await tester.pumpWidget(buildFrame());
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||
|
||||
|
@ -265,26 +370,6 @@ void main() {
|
|||
);
|
||||
|
||||
await tester.tap(find.text('Annuler'));
|
||||
|
||||
// The tests below are only relevant for Material 2. Once Material 2
|
||||
// support is deprecated and the APIs are removed, these tests
|
||||
// can be deleted.
|
||||
|
||||
await tester.pumpWidget(buildFrame(false));
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
Localizations.localeOf(getPicker()),
|
||||
const Locale('fr', 'CA'),
|
||||
);
|
||||
|
||||
expect(
|
||||
Directionality.of(getPicker()),
|
||||
TextDirection.rtl,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('ANNULER'));
|
||||
});
|
||||
|
||||
group("locale fonts don't overflow layout", () {
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('can localize the header in all known formats - portrait', (WidgetTester tester) async {
|
||||
testWidgets('Material2 - can localize the header in all known formats - portrait', (WidgetTester tester) async {
|
||||
// Ensure picker is displayed in portrait mode.
|
||||
tester.view.physicalSize = const Size(400, 800);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
|
@ -32,7 +32,7 @@ void main() {
|
|||
];
|
||||
|
||||
for (final Locale locale in locales) {
|
||||
final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale);
|
||||
final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: false);
|
||||
final Text stringFragmentText = tester.widget(stringFragmentTextFinder);
|
||||
final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx;
|
||||
final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx;
|
||||
|
@ -77,7 +77,77 @@ void main() {
|
|||
}
|
||||
});
|
||||
|
||||
testWidgets('can localize the header in all known formats - landscape', (WidgetTester tester) async {
|
||||
testWidgets('Material3 - can localize the header in all known formats - portrait', (WidgetTester tester) async {
|
||||
// Ensure picker is displayed in portrait mode.
|
||||
tester.view.physicalSize = const Size(400, 800);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
|
||||
final Finder stringFragmentTextFinder = find.descendant(
|
||||
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'),
|
||||
matching: find.byType(Text),
|
||||
).first;
|
||||
final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourControl');
|
||||
final Finder minuteControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_MinuteControl');
|
||||
final Finder dayPeriodControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl');
|
||||
|
||||
// TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them
|
||||
final List<Locale> locales = <Locale>[
|
||||
const Locale('en', 'US'), //'h:mm a'
|
||||
const Locale('en', 'GB'), //'HH:mm'
|
||||
const Locale('es', 'ES'), //'H:mm'
|
||||
const Locale('fr', 'CA'), //'HH \'h\' mm'
|
||||
const Locale('zh', 'ZH'), //'ah:mm'
|
||||
const Locale('fa', 'IR'), //'H:mm' but RTL
|
||||
];
|
||||
|
||||
for (final Locale locale in locales) {
|
||||
final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: true);
|
||||
final Text stringFragmentText = tester.widget(stringFragmentTextFinder);
|
||||
final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx;
|
||||
final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx;
|
||||
final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx;
|
||||
|
||||
if (locale == const Locale('en', 'US')) {
|
||||
final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx;
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(minuteLeftOffset, lessThan(dayPeriodLeftOffset));
|
||||
} else if (locale == const Locale('en', 'GB')) {
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('es', 'ES')) {
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('fr', 'CA')) {
|
||||
expect(stringFragmentText.data, 'h');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('zh', 'ZH')) {
|
||||
final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx;
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(dayPeriodLeftOffset, lessThan(hourLeftOffset));
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
} else if (locale == const Locale('fa', 'IR')) {
|
||||
// Even though this is an RTL locale, the hours and minutes positions should remain the same.
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
}
|
||||
await tester.tapAt(Offset(center.dx, center.dy - 50.0));
|
||||
await finishPicker(tester);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('Material2 - can localize the header in all known formats - landscape', (WidgetTester tester) async {
|
||||
// Ensure picker is displayed in landscape mode.
|
||||
tester.view.physicalSize = const Size(800, 400);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
|
@ -102,7 +172,7 @@ void main() {
|
|||
];
|
||||
|
||||
for (final Locale locale in locales) {
|
||||
final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale);
|
||||
final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: false);
|
||||
final Text stringFragmentText = tester.widget(stringFragmentTextFinder);
|
||||
final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx;
|
||||
final double hourTopOffset = tester.getTopLeft(hourControlFinder).dy;
|
||||
|
@ -152,7 +222,82 @@ void main() {
|
|||
}
|
||||
});
|
||||
|
||||
testWidgets('can localize input mode in all known formats', (WidgetTester tester) async {
|
||||
testWidgets('Material3 - can localize the header in all known formats - landscape', (WidgetTester tester) async {
|
||||
// Ensure picker is displayed in landscape mode.
|
||||
tester.view.physicalSize = const Size(800, 400);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
addTearDown(tester.view.reset);
|
||||
|
||||
final Finder stringFragmentTextFinder = find.descendant(
|
||||
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'),
|
||||
matching: find.byType(Text),
|
||||
).first;
|
||||
final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourControl');
|
||||
final Finder minuteControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_MinuteControl');
|
||||
final Finder dayPeriodControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl');
|
||||
|
||||
// TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them
|
||||
final List<Locale> locales = <Locale>[
|
||||
const Locale('en', 'US'), //'h:mm a'
|
||||
const Locale('en', 'GB'), //'HH:mm'
|
||||
const Locale('es', 'ES'), //'H:mm'
|
||||
const Locale('fr', 'CA'), //'HH \'h\' mm'
|
||||
const Locale('zh', 'ZH'), //'ah:mm'
|
||||
const Locale('fa', 'IR'), //'H:mm' but RTL
|
||||
];
|
||||
|
||||
for (final Locale locale in locales) {
|
||||
final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: true);
|
||||
final Text stringFragmentText = tester.widget(stringFragmentTextFinder);
|
||||
final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx;
|
||||
final double hourTopOffset = tester.getTopLeft(hourControlFinder).dy;
|
||||
final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx;
|
||||
final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx;
|
||||
|
||||
if (locale == const Locale('en', 'US')) {
|
||||
final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx;
|
||||
final double dayPeriodTopOffset = tester.getTopLeft(dayPeriodControlFinder).dy;
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(hourLeftOffset, dayPeriodLeftOffset);
|
||||
expect(hourTopOffset, lessThan(dayPeriodTopOffset));
|
||||
} else if (locale == const Locale('en', 'GB')) {
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('es', 'ES')) {
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('fr', 'CA')) {
|
||||
expect(stringFragmentText.data, 'h');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('zh', 'ZH')) {
|
||||
final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx;
|
||||
final double dayPeriodTopOffset = tester.getTopLeft(dayPeriodControlFinder).dy;
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(hourLeftOffset, dayPeriodLeftOffset);
|
||||
expect(hourTopOffset, greaterThan(dayPeriodTopOffset));
|
||||
} else if (locale == const Locale('fa', 'IR')) {
|
||||
// Even though this is an RTL locale, the hours and minutes positions should remain the same.
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
}
|
||||
await tester.tapAt(Offset(center.dx, center.dy - 50.0));
|
||||
await finishPicker(tester);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('Material2 - can localize input mode in all known formats', (WidgetTester tester) async {
|
||||
final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourTextField');
|
||||
final Finder minuteControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_MinuteTextField');
|
||||
final Finder dayPeriodControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl');
|
||||
|
@ -172,7 +317,75 @@ void main() {
|
|||
];
|
||||
|
||||
for (final Locale locale in locales) {
|
||||
await tester.pumpWidget(_TimePickerLauncher(onChanged: (TimeOfDay? time) { }, locale: locale, entryMode: TimePickerEntryMode.input));
|
||||
await tester.pumpWidget(_TimePickerLauncher(onChanged: (TimeOfDay? time) { }, locale: locale, entryMode: TimePickerEntryMode.input, useMaterial3 : false));
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||
|
||||
final Text stringFragmentText = tester.widget(stringFragmentTextFinder);
|
||||
final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx;
|
||||
final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx;
|
||||
final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx;
|
||||
|
||||
if (locale == const Locale('en', 'US')) {
|
||||
final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx;
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(minuteLeftOffset, lessThan(dayPeriodLeftOffset));
|
||||
} else if (locale == const Locale('en', 'GB')) {
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('es', 'ES')) {
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('fr', 'CA')) {
|
||||
expect(stringFragmentText.data, 'h');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
} else if (locale == const Locale('zh', 'ZH')) {
|
||||
final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx;
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(dayPeriodLeftOffset, lessThan(hourLeftOffset));
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
} else if (locale == const Locale('fa', 'IR')) {
|
||||
// Even though this is an RTL locale, the hours and minutes positions should remain the same.
|
||||
expect(stringFragmentText.data, ':');
|
||||
expect(hourLeftOffset, lessThan(stringFragmentLeftOffset));
|
||||
expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset));
|
||||
expect(dayPeriodControlFinder, findsNothing);
|
||||
}
|
||||
await finishPicker(tester);
|
||||
expect(tester.takeException(), isNot(throwsFlutterError));
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('Material3 - can localize input mode in all known formats', (WidgetTester tester) async {
|
||||
final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourTextField');
|
||||
final Finder minuteControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_MinuteTextField');
|
||||
final Finder dayPeriodControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl');
|
||||
final Finder stringFragmentTextFinder = find.descendant(
|
||||
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'),
|
||||
matching: find.byType(Text),
|
||||
).first;
|
||||
|
||||
// TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them
|
||||
final List<Locale> locales = <Locale>[
|
||||
const Locale('en', 'US'), //'h:mm a'
|
||||
const Locale('en', 'GB'), //'HH:mm'
|
||||
const Locale('es', 'ES'), //'H:mm'
|
||||
const Locale('fr', 'CA'), //'HH \'h\' mm'
|
||||
const Locale('zh', 'ZH'), //'ah:mm'
|
||||
const Locale('fa', 'IR'), //'H:mm' but RTL
|
||||
];
|
||||
|
||||
for (final Locale locale in locales) {
|
||||
await tester.pumpWidget(_TimePickerLauncher(onChanged: (TimeOfDay? time) { }, locale: locale, entryMode: TimePickerEntryMode.input, useMaterial3 : true));
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||
|
||||
|
@ -269,7 +482,7 @@ void main() {
|
|||
const List<String> labels00To23TwoDigit = <String>[ // Material 3
|
||||
'00', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'];
|
||||
|
||||
Future<void> mediaQueryBoilerplate(WidgetTester tester, {required bool alwaysUse24HourFormat, bool? useMaterial3}) async {
|
||||
Future<void> mediaQueryBoilerplate(WidgetTester tester, {required bool alwaysUse24HourFormat, required bool useMaterial3}) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(useMaterial3: useMaterial3),
|
||||
|
@ -303,8 +516,30 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
testWidgets('respects MediaQueryData.alwaysUse24HourFormat == false', (WidgetTester tester) async {
|
||||
await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: false);
|
||||
testWidgets('Material2 respects MediaQueryData.alwaysUse24HourFormat == false', (WidgetTester tester) async {
|
||||
await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: false, useMaterial3: false);
|
||||
|
||||
final CustomPaint dialPaint = tester.widget(find.byKey(const ValueKey<String>('time-picker-dial')));
|
||||
final dynamic dialPainter = dialPaint.painter;
|
||||
// ignore: avoid_dynamic_calls
|
||||
final List<dynamic> primaryLabels = dialPainter.primaryLabels as List<dynamic>;
|
||||
expect(
|
||||
// ignore: avoid_dynamic_calls
|
||||
primaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!),
|
||||
labels12To11,
|
||||
);
|
||||
|
||||
// ignore: avoid_dynamic_calls
|
||||
final List<dynamic> selectedLabels = dialPainter.selectedLabels as List<dynamic>;
|
||||
expect(
|
||||
// ignore: avoid_dynamic_calls
|
||||
selectedLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!),
|
||||
labels12To11,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Material3 respects MediaQueryData.alwaysUse24HourFormat == false', (WidgetTester tester) async {
|
||||
await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: false, useMaterial3: true);
|
||||
|
||||
final CustomPaint dialPaint = tester.widget(find.byKey(const ValueKey<String>('time-picker-dial')));
|
||||
final dynamic dialPainter = dialPaint.painter;
|
||||
|
|
|
@ -7,7 +7,78 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Text baseline with CJK locale', (WidgetTester tester) async {
|
||||
testWidgets('Material2 - Text baseline with CJK locale', (WidgetTester tester) async {
|
||||
// This test in combination with 'Text baseline with EN locale' verify the baselines
|
||||
// used to align text with ideographic baselines are reasonable. We are currently
|
||||
// using the alphabetic baseline to lay out as the ideographic baseline is not yet
|
||||
// properly implemented. When the ideographic baseline is better defined and implemented,
|
||||
// the values of this test should change very slightly. See the issue this is based off
|
||||
// of: https://github.com/flutter/flutter/issues/25782.
|
||||
final Key targetKey = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(useMaterial3: false),
|
||||
routes: <String, WidgetBuilder>{
|
||||
'/next': (BuildContext context) {
|
||||
return const Text('Next');
|
||||
},
|
||||
},
|
||||
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||
supportedLocales: const <Locale>[
|
||||
Locale('en', 'US'),
|
||||
Locale('es', 'ES'),
|
||||
Locale('zh', 'CN'),
|
||||
],
|
||||
locale: const Locale('zh', 'CN'),
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: Builder(
|
||||
key: targetKey,
|
||||
builder: (BuildContext context) {
|
||||
return PopupMenuButton<int>(
|
||||
onSelected: (int value) {
|
||||
Navigator.pushNamed(context, '/next');
|
||||
},
|
||||
itemBuilder: (BuildContext context) {
|
||||
return <PopupMenuItem<int>>[
|
||||
const PopupMenuItem<int>(
|
||||
value: 1,
|
||||
child: Text(
|
||||
'hello, world',
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
),
|
||||
const PopupMenuItem<int>(
|
||||
value: 2,
|
||||
child: Text(
|
||||
'你好,世界',
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byKey(targetKey));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('hello, world'), findsOneWidget);
|
||||
expect(find.text('你好,世界'), findsOneWidget);
|
||||
|
||||
expect(tester.getTopLeft(find.text('hello, world')).dy, 299.5);
|
||||
expect(tester.getBottomLeft(find.text('hello, world')).dy, 316.5);
|
||||
|
||||
expect(tester.getTopLeft(find.text('你好,世界')).dy, 347.5);
|
||||
expect(tester.getBottomLeft(find.text('你好,世界')).dy, 364.5);
|
||||
});
|
||||
|
||||
testWidgets('Material3 - Text baseline with CJK locale', (WidgetTester tester) async {
|
||||
// This test in combination with 'Text baseline with EN locale' verify the baselines
|
||||
// used to align text with ideographic baselines are reasonable. We are currently
|
||||
// using the alphabetic baseline to lay out as the ideographic baseline is not yet
|
||||
|
@ -78,7 +149,78 @@ void main() {
|
|||
expect(tester.getBottomLeft(find.text('你好,世界')).dy, 366.0);
|
||||
});
|
||||
|
||||
testWidgets('Text baseline with EN locale', (WidgetTester tester) async {
|
||||
testWidgets('Material2 - Text baseline with EN locale', (WidgetTester tester) async {
|
||||
// This test in combination with 'Text baseline with CJK locale' verify the baselines
|
||||
// used to align text with ideographic baselines are reasonable. We are currently
|
||||
// using the alphabetic baseline to lay out as the ideographic baseline is not yet
|
||||
// properly implemented. When the ideographic baseline is better defined and implemented,
|
||||
// the values of this test should change very slightly. See the issue this is based off
|
||||
// of: https://github.com/flutter/flutter/issues/25782.
|
||||
final Key targetKey = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(useMaterial3: false),
|
||||
routes: <String, WidgetBuilder>{
|
||||
'/next': (BuildContext context) {
|
||||
return const Text('Next');
|
||||
},
|
||||
},
|
||||
localizationsDelegates: GlobalMaterialLocalizations.delegates,
|
||||
supportedLocales: const <Locale>[
|
||||
Locale('en', 'US'),
|
||||
Locale('es', 'ES'),
|
||||
Locale('zh', 'CN'),
|
||||
],
|
||||
locale: const Locale('en', 'US'),
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: Builder(
|
||||
key: targetKey,
|
||||
builder: (BuildContext context) {
|
||||
return PopupMenuButton<int>(
|
||||
onSelected: (int value) {
|
||||
Navigator.pushNamed(context, '/next');
|
||||
},
|
||||
itemBuilder: (BuildContext context) {
|
||||
return <PopupMenuItem<int>>[
|
||||
const PopupMenuItem<int>(
|
||||
value: 1,
|
||||
child: Text(
|
||||
'hello, world',
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
),
|
||||
const PopupMenuItem<int>(
|
||||
value: 2,
|
||||
child: Text(
|
||||
'你好,世界',
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byKey(targetKey));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('hello, world'), findsOneWidget);
|
||||
expect(find.text('你好,世界'), findsOneWidget);
|
||||
|
||||
expect(tester.getTopLeft(find.text('hello, world')).dy, 300.0);
|
||||
expect(tester.getBottomLeft(find.text('hello, world')).dy, 316.0);
|
||||
|
||||
expect(tester.getTopLeft(find.text('你好,世界')).dy, 348.0);
|
||||
expect(tester.getBottomLeft(find.text('你好,世界')).dy, 364.0);
|
||||
});
|
||||
|
||||
testWidgets('Material3 - Text baseline with EN locale', (WidgetTester tester) async {
|
||||
// This test in combination with 'Text baseline with CJK locale' verify the baselines
|
||||
// used to align text with ideographic baselines are reasonable. We are currently
|
||||
// using the alphabetic baseline to lay out as the ideographic baseline is not yet
|
||||
|
|
Loading…
Reference in a new issue