[a11y] Make sure RenderFractionalTranslation updates its semantics after the translation field is set (#48985)

This commit is contained in:
Anthony 2020-01-17 18:13:01 -05:00 committed by Flutter GitHub Bot
parent fcf341e4f3
commit b67d5ec6e9
196 changed files with 1686 additions and 1607 deletions

View File

@ -13,7 +13,7 @@ export 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
// TODO(ianh): Remove this file once https://github.com/dart-lang/matcher/issues/98 is fixed // TODO(ianh): Remove this file once https://github.com/dart-lang/matcher/issues/98 is fixed
/// A matcher that compares the type of the actual value to the type argument T. /// A matcher that compares the type of the actual value to the type argument T.
test_package.TypeMatcher<T> isInstanceOf<T>() => isA<T>(); Matcher isInstanceOf<T>() => test_package.TypeMatcher<T>();
void tryToDelete(Directory directory) { void tryToDelete(Directory directory) {
// This should not be necessary, but it turns out that // This should not be necessary, but it turns out that

View File

@ -25,7 +25,7 @@ void main() {
expectAsync1((List<String> commandLine) async { expectAsync1((List<String> commandLine) async {
return processRunner.runProcess(commandLine); return processRunner.runProcess(commandLine);
})(<String>['this_executable_better_not_exist_2857632534321']), })(<String>['this_executable_better_not_exist_2857632534321']),
throwsA(isA<PreparePackageException>())); throwsA(isInstanceOf<PreparePackageException>()));
try { try {
await processRunner.runProcess(<String>['this_executable_better_not_exist_2857632534321']); await processRunner.runProcess(<String>['this_executable_better_not_exist_2857632534321']);
} on PreparePackageException catch (e) { } on PreparePackageException catch (e) {
@ -64,7 +64,7 @@ void main() {
expectAsync1((List<String> commandLine) async { expectAsync1((List<String> commandLine) async {
return processRunner.runProcess(commandLine); return processRunner.runProcess(commandLine);
})(<String>['echo', 'test']), })(<String>['echo', 'test']),
throwsA(isA<PreparePackageException>())); throwsA(isInstanceOf<PreparePackageException>()));
}); });
}); });
group('ArchiveCreator for $platformName', () { group('ArchiveCreator for $platformName', () {
@ -185,7 +185,8 @@ void main() {
'git reset --hard $testRef': <ProcessResult>[ProcessResult(0, -1, 'output2', '')], 'git reset --hard $testRef': <ProcessResult>[ProcessResult(0, -1, 'output2', '')],
}; };
processManager.fakeResults = calls; processManager.fakeResults = calls;
expect(expectAsync0(creator.initializeRepo), throwsA(isA<PreparePackageException>())); expect(expectAsync0(creator.initializeRepo),
throwsA(isInstanceOf<PreparePackageException>()));
}); });
test('non-strict mode calls the right commands', () async { test('non-strict mode calls the right commands', () async {

View File

@ -11,4 +11,4 @@ export 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
// TODO(ianh): Remove this file once https://github.com/dart-lang/matcher/issues/98 is fixed // TODO(ianh): Remove this file once https://github.com/dart-lang/matcher/issues/98 is fixed
/// A matcher that compares the type of the actual value to the type argument T. /// A matcher that compares the type of the actual value to the type argument T.
test_package.TypeMatcher<T> isInstanceOf<T>() => isA<T>(); Matcher isInstanceOf<T>() => test_package.TypeMatcher<T>();

View File

@ -11,4 +11,4 @@ import 'package:test/test.dart' as test_package show TypeMatcher;
export 'package:test/test.dart' hide TypeMatcher, isInstanceOf; export 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
/// A matcher that compares the type of the actual value to the type argument T. /// A matcher that compares the type of the actual value to the type argument T.
test_package.TypeMatcher<T> isInstanceOf<T>() => isA<T>(); Matcher isInstanceOf<T>() => test_package.TypeMatcher<T>();

View File

@ -13,7 +13,7 @@ export 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
// TODO(ianh): Remove this file once https://github.com/dart-lang/matcher/issues/98 is fixed // TODO(ianh): Remove this file once https://github.com/dart-lang/matcher/issues/98 is fixed
/// A matcher that compares the type of the actual value to the type argument T. /// A matcher that compares the type of the actual value to the type argument T.
test_package.TypeMatcher<T> isInstanceOf<T>() => isA<T>(); Matcher isInstanceOf<T>() => test_package.TypeMatcher<T>();
void tryToDelete(Directory directory) { void tryToDelete(Directory directory) {
// This should not be necessary, but it turns out that // This should not be necessary, but it turns out that

View File

@ -17,7 +17,7 @@ void main() {
test('parsePixels', () { test('parsePixels', () {
expect(parsePixels('23px'), 23); expect(parsePixels('23px'), 23);
expect(parsePixels('9px'), 9); expect(parsePixels('9px'), 9);
expect(() { parsePixels('9pt'); }, throwsArgumentError); expect(() { parsePixels('9pt'); }, throwsA(isInstanceOf<ArgumentError>()));
}); });
test('parsePoints', () { test('parsePoints', () {

View File

@ -108,7 +108,6 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () async { onTap: () async {
await showCupertinoModalPopup<void>( await showCupertinoModalPopup<void>(
context: context, context: context,
semanticsDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return _BottomPicker( return _BottomPicker(
child: CupertinoPicker( child: CupertinoPicker(
@ -145,7 +144,6 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () { onTap: () {
showCupertinoModalPopup<void>( showCupertinoModalPopup<void>(
context: context, context: context,
semanticsDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return _BottomPicker( return _BottomPicker(
child: CupertinoTimerPicker( child: CupertinoTimerPicker(
@ -178,7 +176,6 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () { onTap: () {
showCupertinoModalPopup<void>( showCupertinoModalPopup<void>(
context: context, context: context,
semanticsDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return _BottomPicker( return _BottomPicker(
child: CupertinoDatePicker( child: CupertinoDatePicker(
@ -210,7 +207,6 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () { onTap: () {
showCupertinoModalPopup<void>( showCupertinoModalPopup<void>(
context: context, context: context,
semanticsDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return _BottomPicker( return _BottomPicker(
child: CupertinoDatePicker( child: CupertinoDatePicker(
@ -242,7 +238,6 @@ class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> {
onTap: () { onTap: () {
showCupertinoModalPopup<void>( showCupertinoModalPopup<void>(
context: context, context: context,
semanticsDismissible: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return _BottomPicker( return _BottomPicker(
child: CupertinoDatePicker( child: CupertinoDatePicker(

View File

@ -35,8 +35,7 @@ const double _kOverAndUnderCenterOpacity = 0.447;
/// that child the initially selected child. /// that child the initially selected child.
/// ///
/// Can be used with [showCupertinoModalPopup] to display the picker modally at the /// Can be used with [showCupertinoModalPopup] to display the picker modally at the
/// bottom of the screen. When calling [showCupertinoModalPopup], be sure to set /// bottom of the screen.
/// `semanticsDismissible` to true to enable dismissing the modal via semantics.
/// ///
/// Sizes itself to its parent. All children are sized to the same size based /// Sizes itself to its parent. All children are sized to the same size based
/// on [itemExtent]. /// on [itemExtent].

View File

@ -792,18 +792,14 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
this.barrierColor, this.barrierColor,
this.barrierLabel, this.barrierLabel,
this.builder, this.builder,
bool semanticsDismissible,
ImageFilter filter, ImageFilter filter,
RouteSettings settings, RouteSettings settings,
}) : super( }) : super(
filter: filter, filter: filter,
settings: settings, settings: settings,
) { );
_semanticsDismissible = semanticsDismissible;
}
final WidgetBuilder builder; final WidgetBuilder builder;
bool _semanticsDismissible;
@override @override
final String barrierLabel; final String barrierLabel;
@ -815,7 +811,7 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
bool get barrierDismissible => true; bool get barrierDismissible => true;
@override @override
bool get semanticsDismissible => _semanticsDismissible ?? false; bool get semanticsDismissible => false;
@override @override
Duration get transitionDuration => _kModalPopupTransitionDuration; Duration get transitionDuration => _kModalPopupTransitionDuration;
@ -875,9 +871,6 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
/// popup to the [Navigator] furthest from or nearest to the given `context`. It /// popup to the [Navigator] furthest from or nearest to the given `context`. It
/// is `false` by default. /// is `false` by default.
/// ///
/// The `semanticsDismissble` argument is used to determine whether the
/// semantics of the modal barrier are included in the semantics tree.
///
/// The `builder` argument typically builds a [CupertinoActionSheet] widget. /// The `builder` argument typically builds a [CupertinoActionSheet] widget.
/// Content below the widget is dimmed with a [ModalBarrier]. The widget built /// Content below the widget is dimmed with a [ModalBarrier]. The widget built
/// by the `builder` does not share a context with the location that /// by the `builder` does not share a context with the location that
@ -898,7 +891,6 @@ Future<T> showCupertinoModalPopup<T>({
@required WidgetBuilder builder, @required WidgetBuilder builder,
ImageFilter filter, ImageFilter filter,
bool useRootNavigator = true, bool useRootNavigator = true,
bool semanticsDismissible,
}) { }) {
assert(useRootNavigator != null); assert(useRootNavigator != null);
return Navigator.of(context, rootNavigator: useRootNavigator).push( return Navigator.of(context, rootNavigator: useRootNavigator).push(
@ -907,7 +899,6 @@ Future<T> showCupertinoModalPopup<T>({
barrierLabel: 'Dismiss', barrierLabel: 'Dismiss',
builder: builder, builder: builder,
filter: filter, filter: filter,
semanticsDismissible: semanticsDismissible,
), ),
); );
} }

View File

@ -61,8 +61,6 @@ const Duration _kFadeDuration = Duration(milliseconds: 165);
/// ///
/// See also: /// See also:
/// ///
/// * [CupertinoSegmentedControl], a segmented control widget in the style used
/// up until iOS 13.
/// * <https://developer.apple.com/design/human-interface-guidelines/ios/controls/segmented-controls/> /// * <https://developer.apple.com/design/human-interface-guidelines/ios/controls/segmented-controls/>
class CupertinoSegmentedControl<T> extends StatefulWidget { class CupertinoSegmentedControl<T> extends StatefulWidget {
/// Creates an iOS-style segmented control bar. /// Creates an iOS-style segmented control bar.

View File

@ -118,8 +118,6 @@ class _FontWeightTween extends Tween<FontWeight> {
/// ///
/// See also: /// See also:
/// ///
/// * [CupertinoSlidingSegmentedControl], a segmented control widget in the
/// style introduced in iOS 13.
/// * <https://developer.apple.com/design/human-interface-guidelines/ios/controls/segmented-controls/> /// * <https://developer.apple.com/design/human-interface-guidelines/ios/controls/segmented-controls/>
class CupertinoSlidingSegmentedControl<T> extends StatefulWidget { class CupertinoSlidingSegmentedControl<T> extends StatefulWidget {
/// Creates an iOS-style segmented control bar. /// Creates an iOS-style segmented control bar.

View File

@ -32,7 +32,7 @@ const int _kDefaultSizeBytes = 100 << 20; // 100 MiB
/// {@tool snippet} /// {@tool snippet}
/// ///
/// This sample shows how to supply your own caching logic and replace the /// This sample shows how to supply your own caching logic and replace the
/// global [imageCache] variable. /// global [imageCache] varible.
/// ///
/// ```dart /// ```dart
/// /// This is the custom implementation of [ImageCache] where we can override /// /// This is the custom implementation of [ImageCache] where we can override
@ -64,6 +64,7 @@ const int _kDefaultSizeBytes = 100 << 20; // 100 MiB
/// } /// }
/// ``` /// ```
/// {@end-tool} /// {@end-tool}
class ImageCache { class ImageCache {
final Map<Object, _PendingImage> _pendingImages = <Object, _PendingImage>{}; final Map<Object, _PendingImage> _pendingImages = <Object, _PendingImage>{};
final Map<Object, _CachedImage> _cache = <Object, _CachedImage>{}; final Map<Object, _CachedImage> _cache = <Object, _CachedImage>{};
@ -140,13 +141,12 @@ class ImageCache {
} }
/// Evicts a single entry from the cache, returning true if successful. /// Evicts a single entry from the cache, returning true if successful.
/// Pending images waiting for completion are removed as well, returning true /// Pending images waiting for completion are removed as well, returning true if successful.
/// if successful.
/// ///
/// When a pending image is removed the listener on it is removed as well to /// When a pending image is removed the listener on it is removed as well to prevent
/// prevent it from adding itself to the cache if it eventually completes. /// it from adding itself to the cache if it eventually completes.
/// ///
/// The `key` must be equal to an object used to cache an image in /// The [key] must be equal to an object used to cache an image in
/// [ImageCache.putIfAbsent]. /// [ImageCache.putIfAbsent].
/// ///
/// If the key is not immediately available, as is common, consider using /// If the key is not immediately available, as is common, consider using

View File

@ -15,7 +15,7 @@ import 'package:flutter/scheduler.dart';
/// actual data of the image once it has been obtained. /// actual data of the image once it has been obtained.
@immutable @immutable
class ImageInfo { class ImageInfo {
/// Creates an [ImageInfo] object for the given [image] and [scale]. /// Creates an [ImageInfo] object for the given image and scale.
/// ///
/// Both the image and the scale must not be null. /// Both the image and the scale must not be null.
const ImageInfo({ @required this.image, this.scale = 1.0 }) const ImageInfo({ @required this.image, this.scale = 1.0 })
@ -35,9 +35,9 @@ class ImageInfo {
/// ///
/// For example, if this is 2.0 it means that there are four image pixels for /// For example, if this is 2.0 it means that there are four image pixels for
/// every one logical pixel, and the image's actual width and height (as given /// every one logical pixel, and the image's actual width and height (as given
/// by the [dart:ui.Image.width] and [dart:ui.Image.height] properties) are /// by the [dart:ui.Image.width] and [dart:ui.Image.height] properties) are double the
/// double the height and width that should be used when painting the image /// height and width that should be used when painting the image (e.g. in the
/// (e.g. in the arguments given to [Canvas.drawImage]). /// arguments given to [Canvas.drawImage]).
final double scale; final double scale;
@override @override
@ -58,11 +58,11 @@ class ImageInfo {
/// Interface for receiving notifications about the loading of an image. /// Interface for receiving notifications about the loading of an image.
/// ///
/// This class overrides [operator ==] and [hashCode] to compare the individual /// This class overrides `operator ==` and `hashCode` to compare the individual
/// callbacks in the listener, meaning that if you add an instance of this class /// callbacks in the listener, meaning that if you add an instance of this class
/// as a listener (e.g. via [ImageStream.addListener]), you can instantiate a /// as a listener (e.g. via [ImageStream.addListener]), you can instantiate a
/// _different_ instance of this class when you remove the listener, and the /// _different_ instance of this class when you remove the listener, and the
/// listener will be properly removed as long as all associated callbacks are /// listener will be properly removed as long all associated callbacks are
/// equal. /// equal.
/// ///
/// Used by [ImageStream] and [ImageStreamCompleter]. /// Used by [ImageStream] and [ImageStreamCompleter].

View File

@ -409,14 +409,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
) { ) {
// Changes made by the keyboard can sometimes be "out of band" for listening // Changes made by the keyboard can sometimes be "out of band" for listening
// components, so always send those events, even if we didn't think it // components, so always send those events, even if we didn't think it
// changed. Also, focusing an empty field is sent as a selection change even // changed.
// if the selection offset didn't change. if (nextSelection == selection && cause != SelectionChangedCause.keyboard) {
final bool focusingEmpty = nextSelection.baseOffset == 0
&& nextSelection.extentOffset == 0
&& !hasFocus;
if (nextSelection == selection
&& cause != SelectionChangedCause.keyboard
&& !focusingEmpty) {
return; return;
} }
if (onSelectionChanged != null) { if (onSelectionChanged != null) {

View File

@ -2472,6 +2472,7 @@ class RenderFractionalTranslation extends RenderProxyBox {
return; return;
_translation = value; _translation = value;
markNeedsPaint(); markNeedsPaint();
markNeedsSemanticsUpdate();
} }
@override @override

View File

@ -172,10 +172,10 @@ void main() {
final TickerFuture f = controller1.forward(); final TickerFuture f = controller1.forward();
await tester.pump(); // start ticker await tester.pump(); // start ticker
await tester.pump(const Duration(milliseconds: 200)); // end ticker await tester.pump(const Duration(milliseconds: 200)); // end ticker
expect(f.asStream().single, isA<Future<void>>()); expect(f.asStream().single, isInstanceOf<Future<void>>());
await f.catchError((dynamic e) { throw 'do not reach'; }); await f.catchError((dynamic e) { throw 'do not reach'; });
expect(await f.then<bool>((_) => true), isTrue); expect(await f.then<bool>((_) => true), isTrue);
expect(f.whenComplete(() => false), isA<Future<void>>()); expect(f.whenComplete(() => false), isInstanceOf<Future<void>>());
expect(f.timeout(const Duration(seconds: 5)), isA<Future<void>>()); expect(f.timeout(const Duration(seconds: 5)), isInstanceOf<Future<void>>());
}); });
} }

View File

@ -153,6 +153,7 @@ void main() {
testWidgets( testWidgets(
'scrolling calls onSelectedItemChanged and triggers haptic feedback', 'scrolling calls onSelectedItemChanged and triggers haptic feedback',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final List<int> selectedItems = <int>[]; final List<int> selectedItems = <int>[];
final List<MethodCall> systemCalls = <MethodCall>[]; final List<MethodCall> systemCalls = <MethodCall>[];
@ -199,11 +200,15 @@ void main() {
arguments: 'HapticFeedbackType.selectionClick', arguments: 'HapticFeedbackType.selectionClick',
), ),
); );
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'do not trigger haptic effects on non-iOS devices', 'do not trigger haptic effects on non-iOS devices',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.android;
final List<int> selectedItems = <int>[]; final List<int> selectedItems = <int>[];
final List<MethodCall> systemCalls = <MethodCall>[]; final List<MethodCall> systemCalls = <MethodCall>[];
@ -233,9 +238,13 @@ void main() {
await tester.drag(find.text('0'), const Offset(0.0, -100.0)); await tester.drag(find.text('0'), const Offset(0.0, -100.0));
expect(selectedItems, <int>[1]); expect(selectedItems, <int>[1]);
expect(systemCalls, isEmpty); expect(systemCalls, isEmpty);
}, variant: TargetPlatformVariant(TargetPlatform.values.where((TargetPlatform platform) => platform != TargetPlatform.iOS).toSet()));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets('a drag in between items settles back', (WidgetTester tester) async { testWidgets('a drag in between items settles back', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final FixedExtentScrollController controller = final FixedExtentScrollController controller =
FixedExtentScrollController(initialItem: 10); FixedExtentScrollController(initialItem: 10);
final List<int> selectedItems = <int>[]; final List<int> selectedItems = <int>[];
@ -288,9 +297,11 @@ void main() {
moreOrLessEquals(350.0, epsilon: 0.5), moreOrLessEquals(350.0, epsilon: 0.5),
); );
expect(selectedItems, <int>[9]); expect(selectedItems, <int>[9]);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
testWidgets('a big fling that overscrolls springs back', (WidgetTester tester) async { testWidgets('a big fling that overscrolls springs back', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final FixedExtentScrollController controller = final FixedExtentScrollController controller =
FixedExtentScrollController(initialItem: 10); FixedExtentScrollController(initialItem: 10);
final List<int> selectedItems = <int>[]; final List<int> selectedItems = <int>[];
@ -346,6 +357,8 @@ void main() {
// Falling back to 0 shouldn't produce more callbacks. // Falling back to 0 shouldn't produce more callbacks.
<int>[8, 6, 4, 2, 0], <int>[8, 6, 4, 2, 0],
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
}); });
} }

View File

@ -74,6 +74,8 @@ void main() {
final VoidCallback uiTestGroup = () { final VoidCallback uiTestGroup = () {
testWidgets("doesn't invoke anything without user interaction", (WidgetTester tester) async { testWidgets("doesn't invoke anything without user interaction", (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -94,9 +96,13 @@ void main() {
tester.getTopLeft(find.widgetWithText(Container, '0')), tester.getTopLeft(find.widgetWithText(Container, '0')),
const Offset(0.0, 0.0), const Offset(0.0, 0.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('calls the indicator builder when starting to overscroll', (WidgetTester tester) async { testWidgets('calls the indicator builder when starting to overscroll', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -130,11 +136,15 @@ void main() {
tester.getTopLeft(find.widgetWithText(Container, '0')), tester.getTopLeft(find.widgetWithText(Container, '0')),
const Offset(0.0, 50.0), const Offset(0.0, 50.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets( testWidgets(
"don't call the builder if overscroll doesn't move slivers like on Android", "don't call the builder if overscroll doesn't move slivers like on Android",
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.android;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -159,9 +169,14 @@ void main() {
tester.getTopLeft(find.widgetWithText(Container, '0')), tester.getTopLeft(find.widgetWithText(Container, '0')),
const Offset(0.0, 0.0), const Offset(0.0, 0.0),
); );
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets('let the builder update as canceled drag scrolls away', (WidgetTester tester) async { testWidgets('let the builder update as canceled drag scrolls away', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -213,9 +228,13 @@ void main() {
tester.getTopLeft(find.widgetWithText(Container, '0')), tester.getTopLeft(find.widgetWithText(Container, '0')),
const Offset(0.0, 0.0), const Offset(0.0, 0.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('drag past threshold triggers refresh task', (WidgetTester tester) async { testWidgets('drag past threshold triggers refresh task', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final List<MethodCall> platformCallLog = <MethodCall>[]; final List<MethodCall> platformCallLog = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async { SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
@ -276,11 +295,14 @@ void main() {
platformCallLog.last, platformCallLog.last,
isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.mediumImpact'), isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.mediumImpact'),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
testWidgets( testWidgets(
'refreshing task keeps the sliver expanded forever until done', 'refreshing task keeps the sliver expanded forever until done',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -348,11 +370,15 @@ void main() {
60.0, // Default value. 60.0, // Default value.
)); ));
verifyNoMoreInteractions(mockHelper); verifyNoMoreInteractions(mockHelper);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'refreshing task keeps the sliver expanded forever until completes with error', 'refreshing task keeps the sliver expanded forever until completes with error',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final FlutterError error = FlutterError('Oops'); final FlutterError error = FlutterError('Oops');
double errorCount = 0; double errorCount = 0;
@ -434,9 +460,14 @@ void main() {
errorCount++; errorCount++;
}, },
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets('expanded refreshing sliver scrolls normally', (WidgetTester tester) async { testWidgets('expanded refreshing sliver scrolls normally', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -510,9 +541,13 @@ void main() {
tester.getRect(find.widgetWithText(Center, '0')), tester.getRect(find.widgetWithText(Center, '0')),
const Rect.fromLTRB(0.0, 60.0, 800.0, 260.0), const Rect.fromLTRB(0.0, 60.0, 800.0, 260.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('expanded refreshing sliver goes away when done', (WidgetTester tester) async { testWidgets('expanded refreshing sliver goes away when done', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -581,9 +616,13 @@ void main() {
tester.getRect(find.widgetWithText(Center, '0')), tester.getRect(find.widgetWithText(Center, '0')),
const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0), const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('builder still called when sliver snapped back more than 90%', (WidgetTester tester) async { testWidgets('builder still called when sliver snapped back more than 90%', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -665,11 +704,15 @@ void main() {
60.0, // Default value. 60.0, // Default value.
)); ));
expect(find.text('-1'), findsOneWidget); expect(find.text('-1'), findsOneWidget);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets( testWidgets(
'retracting sliver during done cannot be pulled to refresh again until fully retracted', 'retracting sliver during done cannot be pulled to refresh again until fully retracted',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -748,12 +791,17 @@ void main() {
40.0, 40.0,
100.0, // Default value. 100.0, // Default value.
60.0, // Default value. 60.0, // Default value.
)); ));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'sliver held in overscroll when task finishes completes normally', 'sliver held in overscroll when task finishes completes normally',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -800,7 +848,10 @@ void main() {
tester.getRect(find.widgetWithText(Center, '0')), tester.getRect(find.widgetWithText(Center, '0')),
const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0), const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'sliver scrolled away when task completes properly removes itself', 'sliver scrolled away when task completes properly removes itself',
@ -810,6 +861,8 @@ void main() {
// the indicator can be scrolled away while refreshing. // the indicator can be scrolled away while refreshing.
return; return;
} }
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -887,11 +940,16 @@ void main() {
tester.getRect(find.widgetWithText(Center, '0')), tester.getRect(find.widgetWithText(Center, '0')),
const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0), const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
"don't do anything unless it can be overscrolled at the start of the list", "don't do anything unless it can be overscrolled at the start of the list",
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -915,11 +973,16 @@ void main() {
await tester.fling(find.byType(Container).first, const Offset(0.0, -200.0), 3000.0); await tester.fling(find.byType(Container).first, const Offset(0.0, -200.0), 3000.0);
verifyNoMoreInteractions(mockHelper); verifyNoMoreInteractions(mockHelper);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'without an onRefresh, builder is called with arm for one frame then sliver goes away', 'without an onRefresh, builder is called with arm for one frame then sliver goes away',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -961,7 +1024,10 @@ void main() {
tester.getRect(find.widgetWithText(Center, '0')), tester.getRect(find.widgetWithText(Center, '0')),
const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0), const Rect.fromLTRB(0.0, 0.0, 800.0, 200.0),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets('Should not crash when dragged', (WidgetTester tester) async { testWidgets('Should not crash when dragged', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
@ -985,11 +1051,13 @@ void main() {
await tester.pump(); await tester.pump();
expect(tester.takeException(), isNull); expect(tester.takeException(), isNull);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
}; };
final VoidCallback stateMachineTestGroup = () { final VoidCallback stateMachineTestGroup = () {
testWidgets('starts in inactive state', (WidgetTester tester) async { testWidgets('starts in inactive state', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1008,9 +1076,13 @@ void main() {
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder, skipOffstage: false))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder, skipOffstage: false))),
RefreshIndicatorMode.inactive, RefreshIndicatorMode.inactive,
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('goes to drag and returns to inactive in a small drag', (WidgetTester tester) async { testWidgets('goes to drag and returns to inactive in a small drag', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1039,9 +1111,13 @@ void main() {
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder, skipOffstage: false))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder, skipOffstage: false))),
RefreshIndicatorMode.inactive, RefreshIndicatorMode.inactive,
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('goes to armed the frame it passes the threshold', (WidgetTester tester) async { testWidgets('goes to armed the frame it passes the threshold', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1071,11 +1147,15 @@ void main() {
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))),
RefreshIndicatorMode.armed, RefreshIndicatorMode.armed,
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets( testWidgets(
'goes to refresh the frame it crossed back the refresh threshold', 'goes to refresh the frame it crossed back the refresh threshold',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1111,11 +1191,16 @@ void main() {
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))),
RefreshIndicatorMode.refresh, RefreshIndicatorMode.refresh,
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'goes to done internally as soon as the task finishes', 'goes to done internally as soon as the task finishes',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1158,11 +1243,16 @@ void main() {
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))),
RefreshIndicatorMode.done, RefreshIndicatorMode.done,
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'goes back to inactive when retracting back past 10% of arming distance', 'goes back to inactive when retracting back past 10% of arming distance',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1216,11 +1306,16 @@ void main() {
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))),
RefreshIndicatorMode.inactive, RefreshIndicatorMode.inactive,
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
'goes back to inactive if already scrolled away when task completes', 'goes back to inactive if already scrolled away when task completes',
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1275,11 +1370,16 @@ void main() {
tester.getTopLeft(find.widgetWithText(Container, '0')).dy, tester.getTopLeft(find.widgetWithText(Container, '0')).dy,
moreOrLessEquals(-145.0332383665717), moreOrLessEquals(-145.0332383665717),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets( testWidgets(
"don't have to build any indicators or occupy space during refresh", "don't have to build any indicators or occupy space during refresh",
(WidgetTester tester) async { (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshIndicator = const Center(child: Text('-1')); refreshIndicator = const Center(child: Text('-1'));
await tester.pumpWidget( await tester.pumpWidget(
@ -1325,7 +1425,10 @@ void main() {
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder, skipOffstage: false))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder, skipOffstage: false))),
RefreshIndicatorMode.inactive, RefreshIndicatorMode.inactive,
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
},
);
testWidgets('buildSimpleRefreshIndicator dark mode', (WidgetTester tester) async { testWidgets('buildSimpleRefreshIndicator dark mode', (WidgetTester tester) async {
const CupertinoDynamicColor color = CupertinoColors.inactiveGray; const CupertinoDynamicColor color = CupertinoColors.inactiveGray;

View File

@ -3,14 +3,11 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import '../widgets/semantics_tester.dart';
void main() { void main() {
MockNavigatorObserver navigatorObserver; MockNavigatorObserver navigatorObserver;
@ -1055,75 +1052,6 @@ void main() {
expect(rootObserver.dialogCount, 0); expect(rootObserver.dialogCount, 0);
expect(nestedObserver.dialogCount, 1); expect(nestedObserver.dialogCount, 1);
}); });
testWidgets('showCupertinoModalPopup does not allow for semantics dismiss by default', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(CupertinoApp(
home: Navigator(
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
return GestureDetector(
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) => const SizedBox(),
);
},
child: const Text('tap'),
);
},
);
},
),
));
// Push the route.
await tester.tap(find.text('tap'));
await tester.pumpAndSettle();
expect(semantics, isNot(includesNodeWith(
actions: <SemanticsAction>[SemanticsAction.tap],
label: 'Dismiss',
)));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('showCupertinoModalPopup allows for semantics dismiss when set', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(CupertinoApp(
home: Navigator(
onGenerateRoute: (RouteSettings settings) {
return PageRouteBuilder<dynamic>(
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
return GestureDetector(
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
semanticsDismissible: true,
builder: (BuildContext context) => const SizedBox(),
);
},
child: const Text('tap'),
);
},
);
},
),
));
// Push the route.
await tester.tap(find.text('tap'));
await tester.pumpAndSettle();
expect(semantics, includesNodeWith(
actions: <SemanticsAction>[SemanticsAction.tap],
label: 'Dismiss',
));
debugDefaultTargetPlatformOverride = null;
});
} }
class MockNavigatorObserver extends Mock implements NavigatorObserver {} class MockNavigatorObserver extends Mock implements NavigatorObserver {}

View File

@ -43,6 +43,7 @@ void main() {
}); });
testWidgets('Switch emits light haptic vibration on tap', (WidgetTester tester) async { testWidgets('Switch emits light haptic vibration on tap', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Key switchKey = UniqueKey(); final Key switchKey = UniqueKey();
bool value = false; bool value = false;
@ -79,9 +80,11 @@ void main() {
expect(log, hasLength(1)); expect(log, hasLength(1));
expect(log.single, isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.lightImpact')); expect(log.single, isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.lightImpact'));
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); debugDefaultTargetPlatformOverride = null;
});
testWidgets('Using other widgets that rebuild the switch will not cause vibrations', (WidgetTester tester) async { testWidgets('Using other widgets that rebuild the switch will not cause vibrations', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Key switchKey = UniqueKey(); final Key switchKey = UniqueKey();
final Key switchKey2 = UniqueKey(); final Key switchKey2 = UniqueKey();
bool value = false; bool value = false;
@ -149,9 +152,11 @@ void main() {
expect(log, hasLength(4)); expect(log, hasLength(4));
expect(log[3], isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.lightImpact')); expect(log[3], isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.lightImpact'));
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); debugDefaultTargetPlatformOverride = null;
});
testWidgets('Haptic vibration triggers on drag', (WidgetTester tester) async { testWidgets('Haptic vibration triggers on drag', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
bool value = false; bool value = false;
final List<MethodCall> log = <MethodCall>[]; final List<MethodCall> log = <MethodCall>[];
@ -186,9 +191,11 @@ void main() {
expect(log, hasLength(1)); expect(log, hasLength(1));
expect(log[0], isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.lightImpact')); expect(log[0], isMethodCall('HapticFeedback.vibrate', arguments: 'HapticFeedbackType.lightImpact'));
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); debugDefaultTargetPlatformOverride = null;
});
testWidgets('No haptic vibration triggers from a programmatic value change', (WidgetTester tester) async { testWidgets('No haptic vibration triggers from a programmatic value change', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Key switchKey = UniqueKey(); final Key switchKey = UniqueKey();
bool value = false; bool value = false;
@ -237,7 +244,8 @@ void main() {
await tester.pump(); await tester.pump();
expect(log, hasLength(0)); expect(log, hasLength(0));
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); debugDefaultTargetPlatformOverride = null;
});
testWidgets('Switch can drag (LTR)', (WidgetTester tester) async { testWidgets('Switch can drag (LTR)', (WidgetTester tester) async {
bool value = false; bool value = false;

View File

@ -425,7 +425,9 @@ void main() {
expect(editableText.cursorOffset, const Offset(-2.0 / 3.0, 0)); expect(editableText.cursorOffset, const Offset(-2.0 / 3.0, 0));
}); });
testWidgets('Cursor animates', (WidgetTester tester) async { testWidgets('Cursor animates on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
const CupertinoApp( const CupertinoApp(
home: CupertinoTextField(), home: CupertinoTextField(),
@ -457,9 +459,13 @@ void main() {
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
expect(renderEditable.cursorColor.alpha, 0); expect(renderEditable.cursorColor.alpha, 0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('Cursor radius is 2.0', (WidgetTester tester) async { debugDefaultTargetPlatformOverride = null;
});
testWidgets('Cursor radius is 2.0 on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
const CupertinoApp( const CupertinoApp(
home: CupertinoTextField(), home: CupertinoTextField(),
@ -470,7 +476,9 @@ void main() {
final RenderEditable renderEditable = editableTextState.renderEditable; final RenderEditable renderEditable = editableTextState.renderEditable;
expect(renderEditable.cursorRadius, const Radius.circular(2.0)); expect(renderEditable.cursorRadius, const Radius.circular(2.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('Cupertino cursor android golden', (WidgetTester tester) async { testWidgets('Cupertino cursor android golden', (WidgetTester tester) async {
final Widget widget = CupertinoApp( final Widget widget = CupertinoApp(
@ -499,7 +507,9 @@ void main() {
); );
}); });
testWidgets('Cupertino cursor golden', (WidgetTester tester) async { testWidgets('Cupertino cursor iOS golden', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Widget widget = CupertinoApp( final Widget widget = CupertinoApp(
home: Center( home: Center(
child: RepaintBoundary( child: RepaintBoundary(
@ -520,13 +530,12 @@ void main() {
await tester.tapAt(textOffsetToPosition(tester, testValue.length)); await tester.tapAt(textOffsetToPosition(tester, testValue.length));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
debugDefaultTargetPlatformOverride = null;
await expectLater( await expectLater(
find.byKey(const ValueKey<int>(1)), find.byKey(const ValueKey<int>(1)),
matchesGoldenFile( matchesGoldenFile('text_field_cursor_test.cupertino.1.png'),
'text_field_cursor_test.cupertino_${describeEnum(debugDefaultTargetPlatformOverride).toLowerCase()}.1.png',
),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets( testWidgets(
'can control text content via controller', 'can control text content via controller',
@ -2937,7 +2946,8 @@ void main() {
expect(editableText.cursorColor.value, 0x87654321); expect(editableText.cursorColor.value, 0x87654321);
}); });
testWidgets('shows selection handles', (WidgetTester tester) async { testWidgets('iOS shows selection handles', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
const String testText = 'lorem ipsum'; const String testText = 'lorem ipsum';
final TextEditingController controller = TextEditingController(text: testText); final TextEditingController controller = TextEditingController(text: testText);
@ -2967,7 +2977,9 @@ void main() {
expect(left.opacity.value, equals(1.0)); expect(left.opacity.value, equals(1.0));
expect(right.opacity.value, equals(1.0)); expect(right.opacity.value, equals(1.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('when CupertinoTextField would be blocked by keyboard, it is shown with enough space for the selection handle', (WidgetTester tester) async { testWidgets('when CupertinoTextField would be blocked by keyboard, it is shown with enough space for the selection handle', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();

View File

@ -11,7 +11,7 @@ import 'package:test_api/test_api.dart' as test_package show TypeMatcher; // ign
export 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf; // ignore: deprecated_member_use export 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf; // ignore: deprecated_member_use
/// A matcher that compares the type of the actual value to the type argument T. /// A matcher that compares the type of the actual value to the type argument T.
test_package.TypeMatcher<T> isInstanceOf<T>() => isA<T>(); Matcher isInstanceOf<T>() => test_package.TypeMatcher<T>();
/// Whether we are running in a web browser. /// Whether we are running in a web browser.
const bool isBrowser = identical(0, 0.0); const bool isBrowser = identical(0, 0.0);

View File

@ -110,7 +110,8 @@ void main() {
}); });
when(response.contentLength).thenReturn(-1); when(response.contentLength).thenReturn(-1);
expect(consolidateHttpClientResponseBytes(response), throwsException); expect(consolidateHttpClientResponseBytes(response),
throwsA(isInstanceOf<Exception>()));
}); });
test('Propagates error to Future return value if onBytesReceived throws', () async { test('Propagates error to Future return value if onBytesReceived throws', () async {

View File

@ -27,9 +27,9 @@ Future<int> test2Async(int value) async {
void main() { void main() {
test('compute()', () async { test('compute()', () async {
expect(await compute(test1, 0), 1); expect(await compute(test1, 0), 1);
expect(compute(test2, 0), throwsException); expect(compute(test2, 0), throwsA(isInstanceOf<Exception>()));
expect(await compute(test1Async, 0), 1); expect(await compute(test1Async, 0), 1);
expect(compute(test2Async, 0), throwsException); expect(compute(test2Async, 0), throwsA(isInstanceOf<Exception>()));
}); });
} }

View File

@ -489,51 +489,43 @@ void main() {
extensionChangedEvent = extensionChangedEvents.last; extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'iOS'); expect(extensionChangedEvent['value'], 'iOS');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'macOS'}));
expect(result, <String, String>{'value': 'macOS'});
expect(binding.reassembled, 2);
expect(defaultTargetPlatform, TargetPlatform.macOS);
expect(extensionChangedEvents.length, 2);
extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'macOS');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'android'})); result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'android'}));
expect(result, <String, String>{'value': 'android'}); expect(result, <String, String>{'value': 'android'});
expect(binding.reassembled, 3); expect(binding.reassembled, 2);
expect(defaultTargetPlatform, TargetPlatform.android); expect(defaultTargetPlatform, TargetPlatform.android);
expect(extensionChangedEvents.length, 3); expect(extensionChangedEvents.length, 2);
extensionChangedEvent = extensionChangedEvents.last; extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'android'); expect(extensionChangedEvent['value'], 'android');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'fuchsia'})); result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'fuchsia'}));
expect(result, <String, String>{'value': 'fuchsia'}); expect(result, <String, String>{'value': 'fuchsia'});
expect(binding.reassembled, 4); expect(binding.reassembled, 3);
expect(defaultTargetPlatform, TargetPlatform.fuchsia); expect(defaultTargetPlatform, TargetPlatform.fuchsia);
expect(extensionChangedEvents.length, 4); expect(extensionChangedEvents.length, 3);
extensionChangedEvent = extensionChangedEvents.last; extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'fuchsia'); expect(extensionChangedEvent['value'], 'fuchsia');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'default'})); result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'default'}));
expect(result, <String, String>{'value': 'android'}); expect(result, <String, String>{'value': 'android'});
expect(binding.reassembled, 5); expect(binding.reassembled, 4);
expect(defaultTargetPlatform, TargetPlatform.android); expect(defaultTargetPlatform, TargetPlatform.android);
expect(extensionChangedEvents.length, 5); expect(extensionChangedEvents.length, 4);
extensionChangedEvent = extensionChangedEvents.last; extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'android'); expect(extensionChangedEvent['value'], 'android');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'iOS'})); result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'iOS'}));
expect(result, <String, String>{'value': 'iOS'}); expect(result, <String, String>{'value': 'iOS'});
expect(binding.reassembled, 6); expect(binding.reassembled, 5);
expect(defaultTargetPlatform, TargetPlatform.iOS); expect(defaultTargetPlatform, TargetPlatform.iOS);
expect(extensionChangedEvents.length, 6); expect(extensionChangedEvents.length, 5);
extensionChangedEvent = extensionChangedEvents.last; extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'iOS'); expect(extensionChangedEvent['value'], 'iOS');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'bogus'})); result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'bogus'}));
expect(result, <String, String>{'value': 'android'}); expect(result, <String, String>{'value': 'android'});
expect(binding.reassembled, 7); expect(binding.reassembled, 6);
expect(defaultTargetPlatform, TargetPlatform.android); expect(defaultTargetPlatform, TargetPlatform.android);
expect(extensionChangedEvents.length, 7); expect(extensionChangedEvents.length, 6);
extensionChangedEvent = extensionChangedEvents.last; extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'android'); expect(extensionChangedEvent['value'], 'android');

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -84,68 +83,66 @@ void main() {
Size size = tester.getSize(title); Size size = tester.getSize(title);
expect(center.dx, lessThan(400 - size.width / 2.0)); expect(center.dx, lessThan(400 - size.width / 2.0));
for (final TargetPlatform platform in <TargetPlatform>[TargetPlatform.iOS, TargetPlatform.macOS]) { // Clear the widget tree to avoid animating between Android and iOS.
// Clear the widget tree to avoid animating between platforms. await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: platform), theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('X'), title: const Text('X'),
),
), ),
), ),
); ),
);
center = tester.getCenter(title); center = tester.getCenter(title);
size = tester.getSize(title); size = tester.getSize(title);
expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}'); expect(center.dx, greaterThan(400 - size.width / 2.0));
expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}'); expect(center.dx, lessThan(400 + size.width / 2.0));
// One action is still centered. // One action is still centered.
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: platform), theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('X'), title: const Text('X'),
actions: const <Widget>[ actions: const <Widget>[
Icon(Icons.thumb_up), Icon(Icons.thumb_up),
], ],
),
), ),
), ),
); ),
);
center = tester.getCenter(title); center = tester.getCenter(title);
size = tester.getSize(title); size = tester.getSize(title);
expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}'); expect(center.dx, greaterThan(400 - size.width / 2.0));
expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}'); expect(center.dx, lessThan(400 + size.width / 2.0));
// Two actions is left aligned again. // Two actions is left aligned again.
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: platform), theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('X'), title: const Text('X'),
actions: const <Widget>[ actions: const <Widget>[
Icon(Icons.thumb_up), Icon(Icons.thumb_up),
Icon(Icons.thumb_up), Icon(Icons.thumb_up),
], ],
),
), ),
), ),
); ),
);
center = tester.getCenter(title); center = tester.getCenter(title);
size = tester.getSize(title); size = tester.getSize(title);
expect(center.dx, lessThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}'); expect(center.dx, lessThan(400 - size.width / 2.0));
}
}); });
testWidgets('AppBar centerTitle:true centers on Android', (WidgetTester tester) async { testWidgets('AppBar centerTitle:true centers on Android', (WidgetTester tester) async {

View File

@ -17,7 +17,7 @@ void main() {
log.add('build'); log.add('build');
expect(Theme.of(context).primaryColor, Colors.green); expect(Theme.of(context).primaryColor, Colors.green);
expect(Directionality.of(context), TextDirection.ltr); expect(Directionality.of(context), TextDirection.ltr);
expect(child, isA<Navigator>()); expect(child, isInstanceOf<Navigator>());
return const Placeholder(); return const Placeholder();
}, },
); );

View File

@ -322,7 +322,7 @@ void main() {
), ),
); );
final dynamic exception = tester.takeException(); final dynamic exception = tester.takeException();
expect(exception, isA<String>()); expect(exception is String, isTrue);
expect(exception.startsWith('Could not navigate to initial route.'), isTrue); expect(exception.startsWith('Could not navigate to initial route.'), isTrue);
expect(find.text('route "/"'), findsOneWidget); expect(find.text('route "/"'), findsOneWidget);
expect(find.text('route "/a"'), findsNothing); expect(find.text('route "/a"'), findsNothing);
@ -474,7 +474,7 @@ void main() {
color: const Color(0xFF112233), color: const Color(0xFF112233),
home: const Placeholder(), home: const Placeholder(),
)); ));
expect(key.currentState, isA<NavigatorState>()); expect(key.currentState, isInstanceOf<NavigatorState>());
await tester.pumpWidget(const MaterialApp( await tester.pumpWidget(const MaterialApp(
color: Color(0xFF112233), color: Color(0xFF112233),
home: Placeholder(), home: Placeholder(),
@ -485,7 +485,7 @@ void main() {
color: const Color(0xFF112233), color: const Color(0xFF112233),
home: const Placeholder(), home: const Placeholder(),
)); ));
expect(key.currentState, isA<NavigatorState>()); expect(key.currentState, isInstanceOf<NavigatorState>());
}); });
testWidgets('Has default material and cupertino localizations', (WidgetTester tester) async { testWidgets('Has default material and cupertino localizations', (WidgetTester tester) async {

View File

@ -66,37 +66,30 @@ void main() {
}); });
testWidgets('BackButton icon', (WidgetTester tester) async { testWidgets('BackButton icon', (WidgetTester tester) async {
final Key androidKey = UniqueKey();
final Key iOSKey = UniqueKey(); final Key iOSKey = UniqueKey();
final Key macOSKey = UniqueKey(); final Key androidKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: Column( home: Column(
children: <Widget>[ children: <Widget>[
Theme(
data: ThemeData(platform: TargetPlatform.android),
child: BackButtonIcon(key: androidKey),
),
Theme( Theme(
data: ThemeData(platform: TargetPlatform.iOS), data: ThemeData(platform: TargetPlatform.iOS),
child: BackButtonIcon(key: iOSKey), child: BackButtonIcon(key: iOSKey),
), ),
Theme( Theme(
data: ThemeData(platform: TargetPlatform.macOS), data: ThemeData(platform: TargetPlatform.android),
child: BackButtonIcon(key: macOSKey), child: BackButtonIcon(key: androidKey),
), ),
], ],
), ),
), ),
); );
final Icon androidIcon = tester.widget(find.descendant(of: find.byKey(androidKey), matching: find.byType(Icon)));
final Icon iOSIcon = tester.widget(find.descendant(of: find.byKey(iOSKey), matching: find.byType(Icon))); final Icon iOSIcon = tester.widget(find.descendant(of: find.byKey(iOSKey), matching: find.byType(Icon)));
final Icon macOSIcon = tester.widget(find.descendant(of: find.byKey(macOSKey), matching: find.byType(Icon))); final Icon androidIcon = tester.widget(find.descendant(of: find.byKey(androidKey), matching: find.byType(Icon)));
expect(iOSIcon.icon == androidIcon.icon, isFalse); expect(iOSIcon == androidIcon, false);
expect(macOSIcon.icon == androidIcon.icon, isFalse);
expect(macOSIcon.icon == iOSIcon.icon, isTrue);
}); });
testWidgets('BackButton semantics', (WidgetTester tester) async { testWidgets('BackButton semantics', (WidgetTester tester) async {

View File

@ -1449,7 +1449,7 @@ void main() {
), ),
), ),
); );
}, throwsAssertionError); }, throwsA(isInstanceOf<AssertionError>()));
}); });
testWidgets( testWidgets(

View File

@ -184,7 +184,7 @@ void main() {
expect(lightTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d))); expect(lightTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d)));
expect(lightTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.0))); expect(lightTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.0)));
expect(lightTheme.padding, equals(const EdgeInsets.all(4.0))); expect(lightTheme.padding, equals(const EdgeInsets.all(4.0)));
expect(lightTheme.shape, isA<StadiumBorder>()); expect(lightTheme.shape, equals(isInstanceOf<StadiumBorder>()));
expect(lightTheme.labelStyle.color, equals(Colors.black.withAlpha(0xde))); expect(lightTheme.labelStyle.color, equals(Colors.black.withAlpha(0xde)));
expect(lightTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde))); expect(lightTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde)));
expect(lightTheme.brightness, equals(Brightness.light)); expect(lightTheme.brightness, equals(Brightness.light));
@ -202,7 +202,7 @@ void main() {
expect(darkTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d))); expect(darkTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d)));
expect(darkTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.0))); expect(darkTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.0)));
expect(darkTheme.padding, equals(const EdgeInsets.all(4.0))); expect(darkTheme.padding, equals(const EdgeInsets.all(4.0)));
expect(darkTheme.shape, isA<StadiumBorder>()); expect(darkTheme.shape, equals(isInstanceOf<StadiumBorder>()));
expect(darkTheme.labelStyle.color, equals(Colors.white.withAlpha(0xde))); expect(darkTheme.labelStyle.color, equals(Colors.white.withAlpha(0xde)));
expect(darkTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde))); expect(darkTheme.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde)));
expect(darkTheme.brightness, equals(Brightness.dark)); expect(darkTheme.brightness, equals(Brightness.dark));
@ -220,7 +220,7 @@ void main() {
expect(customTheme.secondarySelectedColor, equals(customColor2.withAlpha(0x3d))); expect(customTheme.secondarySelectedColor, equals(customColor2.withAlpha(0x3d)));
expect(customTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.0))); expect(customTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.0)));
expect(customTheme.padding, equals(const EdgeInsets.all(4.0))); expect(customTheme.padding, equals(const EdgeInsets.all(4.0)));
expect(customTheme.shape, isA<StadiumBorder>()); expect(customTheme.shape, equals(isInstanceOf<StadiumBorder>()));
expect(customTheme.labelStyle.color, equals(customColor1.withAlpha(0xde))); expect(customTheme.labelStyle.color, equals(customColor1.withAlpha(0xde)));
expect(customTheme.secondaryLabelStyle.color, equals(customColor2.withAlpha(0xde))); expect(customTheme.secondaryLabelStyle.color, equals(customColor2.withAlpha(0xde)));
expect(customTheme.brightness, equals(Brightness.light)); expect(customTheme.brightness, equals(Brightness.light));
@ -263,7 +263,7 @@ void main() {
expect(lerp.selectedShadowColor, equals(middleGrey)); expect(lerp.selectedShadowColor, equals(middleGrey));
expect(lerp.labelPadding, equals(const EdgeInsets.all(4.0))); expect(lerp.labelPadding, equals(const EdgeInsets.all(4.0)));
expect(lerp.padding, equals(const EdgeInsets.all(3.0))); expect(lerp.padding, equals(const EdgeInsets.all(3.0)));
expect(lerp.shape, isA<StadiumBorder>()); expect(lerp.shape, equals(isInstanceOf<StadiumBorder>()));
expect(lerp.labelStyle.color, equals(middleGrey.withAlpha(0xde))); expect(lerp.labelStyle.color, equals(middleGrey.withAlpha(0xde)));
expect(lerp.secondaryLabelStyle.color, equals(middleGrey.withAlpha(0xde))); expect(lerp.secondaryLabelStyle.color, equals(middleGrey.withAlpha(0xde)));
expect(lerp.brightness, equals(Brightness.light)); expect(lerp.brightness, equals(Brightness.light));
@ -283,7 +283,7 @@ void main() {
expect(lerpANull25.selectedShadowColor, equals(Colors.white.withAlpha(0x40))); expect(lerpANull25.selectedShadowColor, equals(Colors.white.withAlpha(0x40)));
expect(lerpANull25.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 2.0, right: 0.0, bottom: 2.0))); expect(lerpANull25.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 2.0, right: 0.0, bottom: 2.0)));
expect(lerpANull25.padding, equals(const EdgeInsets.all(0.5))); expect(lerpANull25.padding, equals(const EdgeInsets.all(0.5)));
expect(lerpANull25.shape, isA<StadiumBorder>()); expect(lerpANull25.shape, equals(isInstanceOf<StadiumBorder>()));
expect(lerpANull25.labelStyle.color, equals(Colors.black.withAlpha(0x38))); expect(lerpANull25.labelStyle.color, equals(Colors.black.withAlpha(0x38)));
expect(lerpANull25.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0x38))); expect(lerpANull25.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0x38)));
expect(lerpANull25.brightness, equals(Brightness.light)); expect(lerpANull25.brightness, equals(Brightness.light));
@ -301,7 +301,7 @@ void main() {
expect(lerpANull75.selectedShadowColor, equals(Colors.white.withAlpha(0xbf))); expect(lerpANull75.selectedShadowColor, equals(Colors.white.withAlpha(0xbf)));
expect(lerpANull75.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 6.0, right: 0.0, bottom: 6.0))); expect(lerpANull75.labelPadding, equals(const EdgeInsets.only(left: 0.0, top: 6.0, right: 0.0, bottom: 6.0)));
expect(lerpANull75.padding, equals(const EdgeInsets.all(1.5))); expect(lerpANull75.padding, equals(const EdgeInsets.all(1.5)));
expect(lerpANull75.shape, isA<StadiumBorder>()); expect(lerpANull75.shape, equals(isInstanceOf<StadiumBorder>()));
expect(lerpANull75.labelStyle.color, equals(Colors.black.withAlpha(0xa7))); expect(lerpANull75.labelStyle.color, equals(Colors.black.withAlpha(0xa7)));
expect(lerpANull75.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0xa7))); expect(lerpANull75.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0xa7)));
expect(lerpANull75.brightness, equals(Brightness.light)); expect(lerpANull75.brightness, equals(Brightness.light));
@ -319,7 +319,7 @@ void main() {
expect(lerpBNull25.selectedShadowColor, equals(Colors.black.withAlpha(0xbf))); expect(lerpBNull25.selectedShadowColor, equals(Colors.black.withAlpha(0xbf)));
expect(lerpBNull25.labelPadding, equals(const EdgeInsets.only(left: 6.0, top: 0.0, right: 6.0, bottom: 0.0))); expect(lerpBNull25.labelPadding, equals(const EdgeInsets.only(left: 6.0, top: 0.0, right: 6.0, bottom: 0.0)));
expect(lerpBNull25.padding, equals(const EdgeInsets.all(3.0))); expect(lerpBNull25.padding, equals(const EdgeInsets.all(3.0)));
expect(lerpBNull25.shape, isA<StadiumBorder>()); expect(lerpBNull25.shape, equals(isInstanceOf<StadiumBorder>()));
expect(lerpBNull25.labelStyle.color, equals(Colors.white.withAlpha(0xa7))); expect(lerpBNull25.labelStyle.color, equals(Colors.white.withAlpha(0xa7)));
expect(lerpBNull25.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0xa7))); expect(lerpBNull25.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0xa7)));
expect(lerpBNull25.brightness, equals(Brightness.dark)); expect(lerpBNull25.brightness, equals(Brightness.dark));
@ -337,7 +337,7 @@ void main() {
expect(lerpBNull75.selectedShadowColor, equals(Colors.black.withAlpha(0x40))); expect(lerpBNull75.selectedShadowColor, equals(Colors.black.withAlpha(0x40)));
expect(lerpBNull75.labelPadding, equals(const EdgeInsets.only(left: 2.0, top: 0.0, right: 2.0, bottom: 0.0))); expect(lerpBNull75.labelPadding, equals(const EdgeInsets.only(left: 2.0, top: 0.0, right: 2.0, bottom: 0.0)));
expect(lerpBNull75.padding, equals(const EdgeInsets.all(1.0))); expect(lerpBNull75.padding, equals(const EdgeInsets.all(1.0)));
expect(lerpBNull75.shape, isA<StadiumBorder>()); expect(lerpBNull75.shape, equals(isInstanceOf<StadiumBorder>()));
expect(lerpBNull75.labelStyle.color, equals(Colors.white.withAlpha(0x38))); expect(lerpBNull75.labelStyle.color, equals(Colors.white.withAlpha(0x38)));
expect(lerpBNull75.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0x38))); expect(lerpBNull75.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0x38)));
expect(lerpBNull75.brightness, equals(Brightness.light)); expect(lerpBNull75.brightness, equals(Brightness.light));

View File

@ -22,8 +22,8 @@ void main() {
'Card, Dialog, Drawer, or Scaffold.\n', 'Card, Dialog, Drawer, or Scaffold.\n',
), ),
); );
expect(error.diagnostics[3], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[3], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.diagnostics[4], isA<DiagnosticsBlock>()); expect(error.diagnostics[4], isInstanceOf<DiagnosticsBlock>());
expect(error.toStringDeep(), expect(error.toStringDeep(),
'FlutterError\n' 'FlutterError\n'
' No Material widget found.\n' ' No Material widget found.\n'
@ -60,8 +60,8 @@ void main() {
'add a Localization widget with a MaterialLocalizations delegate.\n', 'add a Localization widget with a MaterialLocalizations delegate.\n',
), ),
); );
expect(error.diagnostics[4], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[4], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.diagnostics[5], isA<DiagnosticsBlock>()); expect(error.diagnostics[5], isInstanceOf<DiagnosticsBlock>());
expect(error.toStringDeep(), expect(error.toStringDeep(),
'FlutterError\n' 'FlutterError\n'
' No MaterialLocalizations found.\n' ' No MaterialLocalizations found.\n'
@ -97,8 +97,8 @@ void main() {
expect(exception, isFlutterError); expect(exception, isFlutterError);
final FlutterError error = exception as FlutterError; final FlutterError error = exception as FlutterError;
expect(error.diagnostics.length, 5); expect(error.diagnostics.length, 5);
expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[2], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.diagnostics[3], isA<DiagnosticsBlock>()); expect(error.diagnostics[3], isInstanceOf<DiagnosticsBlock>());
expect(error.diagnostics[4].level, DiagnosticLevel.hint); expect(error.diagnostics[4].level, DiagnosticLevel.hint);
expect( expect(
error.diagnostics[4].toStringDeep(), error.diagnostics[4].toStringDeep(),

View File

@ -57,8 +57,9 @@ void main() {
expect(find.text('header'), findsOneWidget); expect(find.text('header'), findsOneWidget);
}); });
testWidgets('Drawer dismiss barrier has label', (WidgetTester tester) async { testWidgets('Drawer dismiss barrier has label on iOS', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
home: Scaffold( home: Scaffold(
@ -79,9 +80,10 @@ void main() {
)); ));
semantics.dispose(); semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
testWidgets('Drawer dismiss barrier has no label', (WidgetTester tester) async { testWidgets('Drawer dismiss barrier has no label on Android', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
@ -103,7 +105,7 @@ void main() {
))); )));
semantics.dispose(); semantics.dispose();
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); });
testWidgets('Scaffold drawerScrimColor', (WidgetTester tester) async { testWidgets('Scaffold drawerScrimColor', (WidgetTester tester) async {
// The scrim is a Container within a Semantics node labeled "Dismiss", // The scrim is a Container within a Semantics node labeled "Dismiss",

View File

@ -58,6 +58,7 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData( theme: ThemeData(
platform: TargetPlatform.iOS,
dividerColor: _dividerColor, dividerColor: _dividerColor,
), ),
home: Material( home: Material(
@ -153,7 +154,7 @@ void main() {
expect(collapsedContainerDecoration.color, Colors.transparent); expect(collapsedContainerDecoration.color, Colors.transparent);
expect(collapsedContainerDecoration.border.top.color, _dividerColor); expect(collapsedContainerDecoration.border.top.color, _dividerColor);
expect(collapsedContainerDecoration.border.bottom.color, _dividerColor); expect(collapsedContainerDecoration.border.bottom.color, _dividerColor);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('ListTileTheme', (WidgetTester tester) async { testWidgets('ListTileTheme', (WidgetTester tester) async {
final Key expandedTitleKey = UniqueKey(); final Key expandedTitleKey = UniqueKey();
@ -164,6 +165,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData( theme: ThemeData(
platform: TargetPlatform.iOS,
accentColor: _accentColor, accentColor: _accentColor,
unselectedWidgetColor: _unselectedWidgetColor, unselectedWidgetColor: _unselectedWidgetColor,
textTheme: const TextTheme(subhead: TextStyle(color: _headerColor)), textTheme: const TextTheme(subhead: TextStyle(color: _headerColor)),
@ -212,7 +214,7 @@ void main() {
expect(textColor(collapsedTitleKey), _accentColor); expect(textColor(collapsedTitleKey), _accentColor);
expect(iconColor(expandedIconKey), _unselectedWidgetColor); expect(iconColor(expandedIconKey), _unselectedWidgetColor);
expect(iconColor(collapsedIconKey), _accentColor); expect(iconColor(collapsedIconKey), _accentColor);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('ExpansionTile subtitle', (WidgetTester tester) async { testWidgets('ExpansionTile subtitle', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -11,10 +10,10 @@ const double expandedAppbarHeight = 250.0;
final Key appbarContainerKey = UniqueKey(); final Key appbarContainerKey = UniqueKey();
void main() { void main() {
testWidgets('FlexibleSpaceBar collapse mode none', (WidgetTester tester) async { testWidgets('FlexibleSpaceBar collapse mode none on Android', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: debugDefaultTargetPlatformOverride), theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold( home: Scaffold(
body: CustomScrollView( body: CustomScrollView(
key: blockKey, key: blockKey,
@ -47,12 +46,50 @@ void main() {
expect(topBeforeScroll.dy, equals(0.0)); expect(topBeforeScroll.dy, equals(0.0));
expect(topAfterScroll.dy, equals(0.0)); expect(topAfterScroll.dy, equals(0.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { testWidgets('FlexibleSpaceBar collapse mode none on IOS', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: debugDefaultTargetPlatformOverride), theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
body: CustomScrollView(
key: blockKey,
slivers: <Widget>[
SliverAppBar(
expandedHeight: expandedAppbarHeight,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
background: Container(
key: appbarContainerKey,
),
collapseMode: CollapseMode.none,
),
),
SliverToBoxAdapter(
child: Container(
height: 10000.0,
),
),
],
),
),
),
);
final Finder appbarContainer = find.byKey(appbarContainerKey);
final Offset topBeforeScroll = tester.getTopLeft(appbarContainer);
await slowDrag(tester, blockKey, const Offset(0.0, -100.0));
final Offset topAfterScroll = tester.getTopLeft(appbarContainer);
expect(topBeforeScroll.dy, equals(0.0));
expect(topAfterScroll.dy, equals(0.0));
});
testWidgets('FlexibleSpaceBar collapse mode pin on Android', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold( home: Scaffold(
body: CustomScrollView( body: CustomScrollView(
key: blockKey, key: blockKey,
@ -85,12 +122,52 @@ void main() {
expect(topBeforeScroll.dy, equals(0.0)); expect(topBeforeScroll.dy, equals(0.0));
expect(topAfterScroll.dy, equals(-100.0)); expect(topAfterScroll.dy, equals(-100.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { testWidgets('FlexibleSpaceBar collapse mode pin on IOS', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: debugDefaultTargetPlatformOverride), theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
body: CustomScrollView(
key: blockKey,
slivers: <Widget>[
SliverAppBar(
expandedHeight: expandedAppbarHeight,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
background: Container(
key: appbarContainerKey,
),
collapseMode: CollapseMode.pin,
),
),
SliverToBoxAdapter(
child: Container(
height: 10000.0,
),
),
],
),
),
),
);
final Finder appbarContainer = find.byKey(appbarContainerKey);
final Offset topBeforeScroll = tester.getTopLeft(appbarContainer);
await slowDrag(tester, blockKey, const Offset(0.0, -100.0));
final Offset topAfterScroll = tester.getTopLeft(appbarContainer);
expect(topBeforeScroll.dy, equals(0.0));
expect(topAfterScroll.dy, equals(-100.0));
});
testWidgets('FlexibleSpaceBar collapse mode parallax on Android', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold( home: Scaffold(
body: CustomScrollView( body: CustomScrollView(
key: blockKey, key: blockKey,
@ -124,7 +201,46 @@ void main() {
expect(topBeforeScroll.dy, equals(0.0)); expect(topBeforeScroll.dy, equals(0.0));
expect(topAfterScroll.dy, lessThan(10.0)); expect(topAfterScroll.dy, lessThan(10.0));
expect(topAfterScroll.dy, greaterThan(-50.0)); expect(topAfterScroll.dy, greaterThan(-50.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('FlexibleSpaceBar collapse mode parallax on IOS', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
body: CustomScrollView(
key: blockKey,
slivers: <Widget>[
SliverAppBar(
expandedHeight: expandedAppbarHeight,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
background: Container(
key: appbarContainerKey,
),
collapseMode: CollapseMode.parallax,
),
),
SliverToBoxAdapter(
child: Container(
height: 10000.0,
),
),
],
),
),
),
);
final Finder appbarContainer = find.byKey(appbarContainerKey);
final Offset topBeforeScroll = tester.getTopLeft(appbarContainer);
await slowDrag(tester, blockKey, const Offset(0.0, -100.0));
final Offset topAfterScroll = tester.getTopLeft(appbarContainer);
expect(topBeforeScroll.dy, equals(0.0));
expect(topAfterScroll.dy, lessThan(10.0));
expect(topAfterScroll.dy, greaterThan(-50.0));
});
} }
Future<void> slowDrag(WidgetTester tester, Key widget, Offset offset) async { Future<void> slowDrag(WidgetTester tester, Key widget, Offset offset) async {

View File

@ -25,28 +25,26 @@ void main() {
Size size = tester.getSize(title); Size size = tester.getSize(title);
expect(center.dx, lessThan(400.0 - size.width / 2.0)); expect(center.dx, lessThan(400.0 - size.width / 2.0));
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.iOS, TargetPlatform.macOS ]) { // Clear the widget tree to avoid animating between Android and iOS.
// Clear the widget tree to avoid animating between platforms. await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: platform), theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
flexibleSpace: const FlexibleSpaceBar( flexibleSpace: const FlexibleSpaceBar(
title: Text('X'), title: Text('X'),
),
), ),
), ),
), ),
); ),
);
center = tester.getCenter(title); center = tester.getCenter(title);
size = tester.getSize(title); size = tester.getSize(title);
expect(center.dx, greaterThan(400.0 - size.width / 2.0)); expect(center.dx, greaterThan(400.0 - size.width / 2.0));
expect(center.dx, lessThan(400.0 + size.width / 2.0)); expect(center.dx, lessThan(400.0 + size.width / 2.0));
}
}); });
testWidgets('FlexibleSpaceBarSettings provides settings to a FlexibleSpaceBar', (WidgetTester tester) async { testWidgets('FlexibleSpaceBarSettings provides settings to a FlexibleSpaceBar', (WidgetTester tester) async {
@ -156,15 +154,6 @@ void main() {
await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false)); await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false));
expect(getTitleBottomLeft(), const Offset(72.0, 16.0)); expect(getTitleBottomLeft(), const Offset(72.0, 16.0));
// Clear the widget tree to avoid animating between iOS and macOS.
await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget(buildFrame(TargetPlatform.macOS, null));
expect(getTitleBottomLeft(), const Offset(390.0, 16.0));
await tester.pumpWidget(buildFrame(TargetPlatform.macOS, false));
expect(getTitleBottomLeft(), const Offset(72.0, 16.0));
}, skip: isBrowser); }, skip: isBrowser);
testWidgets('FlexibleSpaceBar test titlePadding override', (WidgetTester tester) async { testWidgets('FlexibleSpaceBar test titlePadding override', (WidgetTester tester) async {
@ -206,15 +195,6 @@ void main() {
await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false)); await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false));
expect(getTitleBottomLeft(), Offset.zero); expect(getTitleBottomLeft(), Offset.zero);
// Clear the widget tree to avoid animating between iOS and macOS.
await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget(buildFrame(TargetPlatform.macOS, null));
expect(getTitleBottomLeft(), const Offset(390.0, 0.0));
await tester.pumpWidget(buildFrame(TargetPlatform.macOS, false));
expect(getTitleBottomLeft(), Offset.zero);
}, skip: isBrowser); }, skip: isBrowser);
} }

View File

@ -1047,7 +1047,7 @@ PhysicalModelLayer _findPhysicalLayer(Element element) {
object = object.parent as RenderObject; object = object.parent as RenderObject;
} }
expect(object.debugLayer, isNotNull); expect(object.debugLayer, isNotNull);
expect(object.debugLayer.firstChild, isA<PhysicalModelLayer>()); expect(object.debugLayer.firstChild, isInstanceOf<PhysicalModelLayer>());
final PhysicalModelLayer layer = object.debugLayer.firstChild as PhysicalModelLayer; final PhysicalModelLayer layer = object.debugLayer.firstChild as PhysicalModelLayer;
final Layer child = layer.firstChild; final Layer child = layer.firstChild;
return child is PhysicalModelLayer ? child : layer; return child is PhysicalModelLayer ? child : layer;

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart' show CupertinoPageRoute; import 'package:flutter/cupertino.dart' show CupertinoPageRoute;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
@ -11,9 +10,10 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
void main() { void main() {
testWidgets('test page transition', (WidgetTester tester) async { testWidgets('test Android page transition', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
home: const Material(child: Text('Page 1')), home: const Material(child: Text('Page 1')),
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'/next': (BuildContext context) { '/next': (BuildContext context) {
@ -66,12 +66,13 @@ void main() {
expect(find.text('Page 1'), isOnstage); expect(find.text('Page 1'), isOnstage);
expect(find.text('Page 2'), findsNothing); expect(find.text('Page 2'), findsNothing);
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); });
testWidgets('test page transition', (WidgetTester tester) async { testWidgets('test iOS page transition', (WidgetTester tester) async {
final Key page2Key = UniqueKey(); final Key page2Key = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(child: Text('Page 1')), home: const Material(child: Text('Page 1')),
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'/next': (BuildContext context) { '/next': (BuildContext context) {
@ -144,12 +145,13 @@ void main() {
// Page 1 is back where it started. // Page 1 is back where it started.
expect(widget1InitialTopLeft == widget1TransientTopLeft, true); expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('test fullscreen dialog transition', (WidgetTester tester) async { testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( MaterialApp(
home: Material(child: Text('Page 1')), theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(child: Text('Page 1')),
), ),
); );
@ -204,11 +206,12 @@ void main() {
// Page 1 is back where it started. // Page 1 is back where it started.
expect(widget1InitialTopLeft == widget1TransientTopLeft, true); expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('test no back gesture on Android', (WidgetTester tester) async { testWidgets('test no back gesture on Android', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
home: const Scaffold(body: Text('Page 1')), home: const Scaffold(body: Text('Page 1')),
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'/next': (BuildContext context) { '/next': (BuildContext context) {
@ -234,11 +237,12 @@ void main() {
// Page 2 didn't move // Page 2 didn't move
expect(tester.getTopLeft(find.text('Page 2')), Offset.zero); expect(tester.getTopLeft(find.text('Page 2')), Offset.zero);
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); });
testWidgets('test back gesture', (WidgetTester tester) async { testWidgets('test back gesture on iOS', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Scaffold(body: Text('Page 1')), home: const Scaffold(body: Text('Page 1')),
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'/next': (BuildContext context) { '/next': (BuildContext context) {
@ -275,7 +279,7 @@ void main() {
await tester.pump(); await tester.pump();
expect(tester.getTopLeft(find.text('Page 2')), const Offset(100.0, 0.0)); expect(tester.getTopLeft(find.text('Page 2')), const Offset(100.0, 0.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('back gesture while OS changes', (WidgetTester tester) async { testWidgets('back gesture while OS changes', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@ -342,36 +346,13 @@ void main() {
expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 3); expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 3);
expect(find.text('PUSH'), findsOneWidget); expect(find.text('PUSH'), findsOneWidget);
expect(find.text('HELLO'), findsNothing); expect(find.text('HELLO'), findsNothing);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.macOS),
routes: routes,
),
);
await tester.tap(find.text('PUSH'));
expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 2);
expect(find.text('PUSH'), findsNothing);
expect(find.text('HELLO'), findsOneWidget);
final Offset helloPosition5 = tester.getCenter(find.text('HELLO'));
await gesture.down(const Offset(2.5, 300.0));
await tester.pump(const Duration(milliseconds: 20));
await gesture.moveBy(const Offset(100.0, 0.0));
expect(find.text('PUSH'), findsNothing);
expect(find.text('HELLO'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 20));
expect(find.text('PUSH'), findsOneWidget);
expect(find.text('HELLO'), findsOneWidget);
final Offset helloPosition6 = tester.getCenter(find.text('HELLO'));
expect(helloPosition5.dx, lessThan(helloPosition6.dx));
expect(helloPosition5.dy, helloPosition6.dy);
expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.macOS);
}); });
testWidgets('test no back gesture on fullscreen dialogs', (WidgetTester tester) async { testWidgets('test no back gesture on iOS fullscreen dialogs', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( MaterialApp(
home: Scaffold(body: Text('Page 1')), theme: ThemeData(platform: TargetPlatform.iOS),
home: const Scaffold(body: Text('Page 1')),
), ),
); );
@ -396,7 +377,7 @@ void main() {
// Page 2 didn't move // Page 2 didn't move
expect(tester.getTopLeft(find.text('Page 2')), Offset.zero); expect(tester.getTopLeft(find.text('Page 2')), Offset.zero);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('test adaptable transitions switch during execution', (WidgetTester tester) async { testWidgets('test adaptable transitions switch during execution', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
@ -436,6 +417,7 @@ void main() {
// Re-pump the same app but with iOS instead of Android. // Re-pump the same app but with iOS instead of Android.
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(child: Text('Page 1')), home: const Material(child: Text('Page 1')),
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'/next': (BuildContext context) { '/next': (BuildContext context) {
@ -470,7 +452,7 @@ void main() {
// Page 1 is back where it started. // Page 1 is back where it started.
expect(widget1InitialTopLeft == widget1TransientTopLeft, true); expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('throws when builder returns null', (WidgetTester tester) async { testWidgets('throws when builder returns null', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp( await tester.pumpWidget(const MaterialApp(
@ -488,7 +470,7 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
// An exception should've been thrown because the `builder` returned null. // An exception should've been thrown because the `builder` returned null.
final dynamic exception = tester.takeException(); final dynamic exception = tester.takeException();
expect(exception, isFlutterError); expect(exception, isInstanceOf<FlutterError>());
expect(exception.toStringDeep(), equalsIgnoringHashCodes( expect(exception.toStringDeep(), equalsIgnoringHashCodes(
'FlutterError\n' 'FlutterError\n'
' The builder for route "broken" returned null.\n' ' The builder for route "broken" returned null.\n'
@ -496,9 +478,10 @@ void main() {
)); ));
}); });
testWidgets('test edge swipe then drop back at starting point works', (WidgetTester tester) async { testWidgets('test iOS edge swipe then drop back at starting point works', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
onGenerateRoute: (RouteSettings settings) { onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
settings: settings, settings: settings,
@ -529,11 +512,12 @@ void main() {
expect(find.text('Page 1'), findsNothing); expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage); expect(find.text('Page 2'), isOnstage);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('test edge swipe then drop back at ending point works', (WidgetTester tester) async { testWidgets('test iOS edge swipe then drop back at ending point works', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
onGenerateRoute: (RouteSettings settings) { onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
settings: settings, settings: settings,
@ -562,7 +546,7 @@ void main() {
expect(find.text('Page 1'), isOnstage); expect(find.text('Page 1'), isOnstage);
expect(find.text('Page 2'), findsNothing); expect(find.text('Page 2'), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Back swipe dismiss interrupted by route push', (WidgetTester tester) async { testWidgets('Back swipe dismiss interrupted by route push', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/28728 // Regression test for https://github.com/flutter/flutter/issues/28728
@ -570,6 +554,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold( home: Scaffold(
key: scaffoldKey, key: scaffoldKey,
body: Center( body: Center(
@ -657,7 +642,7 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('route'), findsOneWidget); expect(find.text('route'), findsOneWidget);
expect(find.text('push'), findsNothing); expect(find.text('push'), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('During back swipe the route ignores input', (WidgetTester tester) async { testWidgets('During back swipe the route ignores input', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/39989 // Regression test for https://github.com/flutter/flutter/issues/39989
@ -669,6 +654,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold( home: Scaffold(
key: homeScaffoldKey, key: homeScaffoldKey,
body: GestureDetector( body: GestureDetector(
@ -727,7 +713,7 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(tester.getTopLeft(find.byKey(pageScaffoldKey)), const Offset(400, 0)); expect(tester.getTopLeft(find.byKey(pageScaffoldKey)), const Offset(400, 0));
expect(tester.getTopLeft(find.byKey(homeScaffoldKey)).dx, lessThan(0)); expect(tester.getTopLeft(find.byKey(homeScaffoldKey)).dx, lessThan(0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('After a pop caused by a back-swipe, input reaches the exposed route', (WidgetTester tester) async { testWidgets('After a pop caused by a back-swipe, input reaches the exposed route', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/41024 // Regression test for https://github.com/flutter/flutter/issues/41024
@ -739,6 +725,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold( home: Scaffold(
key: homeScaffoldKey, key: homeScaffoldKey,
body: GestureDetector( body: GestureDetector(
@ -798,9 +785,9 @@ void main() {
await tester.tap(find.byKey(homeScaffoldKey)); await tester.tap(find.byKey(homeScaffoldKey));
expect(homeTapCount, 2); expect(homeTapCount, 2);
expect(pageTapCount, 1); expect(pageTapCount, 1);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('A MaterialPageRoute should slide out with CupertinoPageTransition when a compatible PageRoute is pushed on top of it', (WidgetTester tester) async { testWidgets('On iOS, a MaterialPageRoute should slide out with CupertinoPageTransition when a compatible PageRoute is pushed on top of it', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/44864. // Regression test for https://github.com/flutter/flutter/issues/44864.
await tester.pumpWidget( await tester.pumpWidget(
@ -826,5 +813,5 @@ void main() {
// Title of the first route slides to the left. // Title of the first route slides to the left.
expect(titleInitialTopLeft.dy, equals(titleTransientTopLeft.dy)); expect(titleInitialTopLeft.dy, equals(titleTransientTopLeft.dy));
expect(titleInitialTopLeft.dx, greaterThan(titleTransientTopLeft.dx)); expect(titleInitialTopLeft.dx, greaterThan(titleTransientTopLeft.dx));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
} }

View File

@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -12,16 +11,11 @@ void main() {
await tester.pumpWidget(const MaterialApp(home: Text('home'))); await tester.pumpWidget(const MaterialApp(home: Text('home')));
final PageTransitionsTheme theme = Theme.of(tester.element(find.text('home'))).pageTransitionsTheme; final PageTransitionsTheme theme = Theme.of(tester.element(find.text('home'))).pageTransitionsTheme;
expect(theme.builders, isNotNull); expect(theme.builders, isNotNull);
for (final TargetPlatform platform in TargetPlatform.values) { expect(theme.builders[TargetPlatform.android], isNotNull);
if (platform == TargetPlatform.fuchsia) { expect(theme.builders[TargetPlatform.iOS], isNotNull);
// No builder on Fuchsia.
continue;
}
expect(theme.builders[platform], isNotNull, reason: 'theme builder for $platform is null');
}
}); });
testWidgets('Default PageTranstionsTheme builds a CupertionPageTransition', (WidgetTester tester) async { testWidgets('Default PageTranstionsTheme builds a CupertionPageTransition for iOS', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => Material( '/': (BuildContext context) => Material(
child: FlatButton( child: FlatButton(
@ -34,18 +28,19 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
routes: routes, routes: routes,
), ),
); );
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride); expect(Theme.of(tester.element(find.text('push'))).platform, TargetPlatform.iOS);
expect(find.byType(CupertinoPageTransition), findsOneWidget); expect(find.byType(CupertinoPageTransition), findsOneWidget);
await tester.tap(find.text('push')); await tester.tap(find.text('push'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('page b'), findsOneWidget); expect(find.text('page b'), findsOneWidget);
expect(find.byType(CupertinoPageTransition), findsOneWidget); expect(find.byType(CupertinoPageTransition), findsOneWidget);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Default PageTranstionsTheme builds a _FadeUpwardsPageTransition for android', (WidgetTester tester) async { testWidgets('Default PageTranstionsTheme builds a _FadeUpwardsPageTransition for android', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@ -60,6 +55,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
routes: routes, routes: routes,
), ),
); );
@ -71,16 +67,16 @@ void main() {
); );
} }
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride); expect(Theme.of(tester.element(find.text('push'))).platform, TargetPlatform.android);
expect(findFadeUpwardsPageTransition(), findsOneWidget); expect(findFadeUpwardsPageTransition(), findsOneWidget);
await tester.tap(find.text('push')); await tester.tap(find.text('push'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('page b'), findsOneWidget); expect(find.text('page b'), findsOneWidget);
expect(findFadeUpwardsPageTransition(), findsOneWidget); expect(findFadeUpwardsPageTransition(), findsOneWidget);
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); });
testWidgets('pageTranstionsTheme override builds a _OpenUpwardsPageTransition', (WidgetTester tester) async { testWidgets('pageTranstionsTheme override builds a _OpenUpwardsPageTransition for android', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => Material( '/': (BuildContext context) => Material(
child: FlatButton( child: FlatButton(
@ -94,6 +90,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData( theme: ThemeData(
platform: TargetPlatform.android,
pageTransitionsTheme: const PageTransitionsTheme( pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{ builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.android: OpenUpwardsPageTransitionsBuilder(), // creates a _OpenUpwardsPageTransition TargetPlatform.android: OpenUpwardsPageTransitionsBuilder(), // creates a _OpenUpwardsPageTransition
@ -111,16 +108,16 @@ void main() {
); );
} }
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride); expect(Theme.of(tester.element(find.text('push'))).platform, TargetPlatform.android);
expect(findOpenUpwardsPageTransition(), findsOneWidget); expect(findOpenUpwardsPageTransition(), findsOneWidget);
await tester.tap(find.text('push')); await tester.tap(find.text('push'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('page b'), findsOneWidget); expect(find.text('page b'), findsOneWidget);
expect(findOpenUpwardsPageTransition(), findsOneWidget); expect(findOpenUpwardsPageTransition(), findsOneWidget);
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); });
testWidgets('pageTranstionsTheme override builds a _ZoomPageTransition', (WidgetTester tester) async { testWidgets('pageTranstionsTheme override builds a _ZoomPageTransition for android', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => Material( '/': (BuildContext context) => Material(
child: FlatButton( child: FlatButton(
@ -134,6 +131,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData( theme: ThemeData(
platform: TargetPlatform.android,
pageTransitionsTheme: const PageTransitionsTheme( pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{ builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.android: ZoomPageTransitionsBuilder(), // creates a _ZoomPageTransition TargetPlatform.android: ZoomPageTransitionsBuilder(), // creates a _ZoomPageTransition
@ -151,12 +149,12 @@ void main() {
); );
} }
expect(Theme.of(tester.element(find.text('push'))).platform, debugDefaultTargetPlatformOverride); expect(Theme.of(tester.element(find.text('push'))).platform, TargetPlatform.android);
expect(findZoomPageTransition(), findsOneWidget); expect(findZoomPageTransition(), findsOneWidget);
await tester.tap(find.text('push')); await tester.tap(find.text('push'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('page b'), findsOneWidget); expect(find.text('page b'), findsOneWidget);
expect(findZoomPageTransition(), findsOneWidget); expect(findZoomPageTransition(), findsOneWidget);
}, variant: TargetPlatformVariant.only(TargetPlatform.android)); });
} }

View File

@ -164,7 +164,7 @@ void main() {
// the column overflows because we're forcing it to 600 pixels high // the column overflows because we're forcing it to 600 pixels high
final dynamic exception = tester.takeException(); final dynamic exception = tester.takeException();
expect(exception, isFlutterError); expect(exception, isInstanceOf<FlutterError>());
expect(exception.diagnostics.first.level, DiagnosticLevel.summary); expect(exception.diagnostics.first.level, DiagnosticLevel.summary);
expect(exception.diagnostics.first.toString(), startsWith('A RenderFlex overflowed by ')); expect(exception.diagnostics.first.toString(), startsWith('A RenderFlex overflowed by '));
@ -252,7 +252,7 @@ void main() {
)); ));
// the column overflows because we're forcing it to 600 pixels high // the column overflows because we're forcing it to 600 pixels high
final dynamic exception = tester.takeException(); final dynamic exception = tester.takeException();
expect(exception, isFlutterError); expect(exception, isInstanceOf<FlutterError>());
expect(exception.diagnostics.first.level, DiagnosticLevel.summary); expect(exception.diagnostics.first.level, DiagnosticLevel.summary);
expect(exception.diagnostics.first.toString(), contains('A RenderFlex overflowed by')); expect(exception.diagnostics.first.toString(), contains('A RenderFlex overflowed by'));

View File

@ -325,12 +325,6 @@ void main() {
expect(find.byIcon(Icons.more_vert), findsNothing); expect(find.byIcon(Icons.more_vert), findsNothing);
expect(find.byIcon(Icons.more_horiz), findsOneWidget); expect(find.byIcon(Icons.more_horiz), findsOneWidget);
await tester.pumpWidget(build(TargetPlatform.macOS));
await tester.pumpAndSettle(); // Run theme change animation.
expect(find.byIcon(Icons.more_vert), findsNothing);
expect(find.byIcon(Icons.more_horiz), findsOneWidget);
}); });
group('PopupMenuButton with Icon', () { group('PopupMenuButton with Icon', () {
@ -351,7 +345,7 @@ void main() {
icon: const Icon(Icons.view_carousel), icon: const Icon(Icons.view_carousel),
itemBuilder: simplePopupMenuItemBuilder, itemBuilder: simplePopupMenuItemBuilder,
); );
}, throwsAssertionError); }, throwsA(isInstanceOf<AssertionError>()));
}); });
testWidgets('PopupMenuButton creates IconButton when given an icon', (WidgetTester tester) async { testWidgets('PopupMenuButton creates IconButton when given an icon', (WidgetTester tester) async {

View File

@ -387,7 +387,8 @@ void main() {
expect(tester.takeException(), isFlutterError); expect(tester.takeException(), isFlutterError);
}); });
testWidgets('Refresh starts while scroll view moves back to 0.0 after overscroll', (WidgetTester tester) async { testWidgets('Refresh starts while scroll view moves back to 0.0 after overscroll on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
refreshCalled = false; refreshCalled = false;
double lastScrollOffset; double lastScrollOffset;
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
@ -419,5 +420,7 @@ void main() {
expect(controller.offset, greaterThan(lastScrollOffset)); expect(controller.offset, greaterThan(lastScrollOffset));
expect(controller.offset, lessThan(0.0)); expect(controller.offset, lessThan(0.0));
expect(refreshCalled, isTrue); expect(refreshCalled, isTrue);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
} }

View File

@ -320,17 +320,17 @@ void main() {
); );
} }
testWidgets('Tapping the status bar scrolls to top', (WidgetTester tester) async { testWidgets('Tapping the status bar scrolls to top on iOS', (WidgetTester tester) async {
await tester.pumpWidget(_buildStatusBarTestApp(debugDefaultTargetPlatformOverride)); await tester.pumpWidget(_buildStatusBarTestApp(TargetPlatform.iOS));
final ScrollableState scrollable = tester.state(find.byType(Scrollable)); final ScrollableState scrollable = tester.state(find.byType(Scrollable));
scrollable.position.jumpTo(500.0); scrollable.position.jumpTo(500.0);
expect(scrollable.position.pixels, equals(500.0)); expect(scrollable.position.pixels, equals(500.0));
await tester.tapAt(const Offset(100.0, 10.0)); await tester.tapAt(const Offset(100.0, 10.0));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(scrollable.position.pixels, equals(0.0)); expect(scrollable.position.pixels, equals(0.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Tapping the status bar does not scroll to top', (WidgetTester tester) async { testWidgets('Tapping the status bar does not scroll to top on Android', (WidgetTester tester) async {
await tester.pumpWidget(_buildStatusBarTestApp(TargetPlatform.android)); await tester.pumpWidget(_buildStatusBarTestApp(TargetPlatform.android));
final ScrollableState scrollable = tester.state(find.byType(Scrollable)); final ScrollableState scrollable = tester.state(find.byType(Scrollable));
scrollable.position.jumpTo(500.0); scrollable.position.jumpTo(500.0);
@ -339,7 +339,7 @@ void main() {
await tester.pump(); await tester.pump();
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
expect(scrollable.position.pixels, equals(500.0)); expect(scrollable.position.pixels, equals(500.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android })); });
testWidgets('Bottom sheet cannot overlap app bar', (WidgetTester tester) async { testWidgets('Bottom sheet cannot overlap app bar', (WidgetTester tester) async {
final Key sheetKey = UniqueKey(); final Key sheetKey = UniqueKey();
@ -506,7 +506,7 @@ void main() {
}); });
group('back arrow', () { group('back arrow', () {
Future<void> expectBackIcon(WidgetTester tester, IconData expectedIcon) async { Future<void> expectBackIcon(WidgetTester tester, TargetPlatform platform, IconData expectedIcon) async {
final GlobalKey rootKey = GlobalKey(); final GlobalKey rootKey = GlobalKey();
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (_) => Container(key: rootKey, child: const Text('Home')), '/': (_) => Container(key: rootKey, child: const Text('Home')),
@ -515,7 +515,9 @@ void main() {
body: const Text('Scaffold'), body: const Text('Scaffold'),
), ),
}; };
await tester.pumpWidget(MaterialApp(routes: routes)); await tester.pumpWidget(
MaterialApp(theme: ThemeData(platform: platform), routes: routes)
);
Navigator.pushNamed(rootKey.currentContext, '/scaffold'); Navigator.pushNamed(rootKey.currentContext, '/scaffold');
await tester.pump(); await tester.pump();
@ -525,20 +527,24 @@ void main() {
expect(icon.icon, expectedIcon); expect(icon.icon, expectedIcon);
} }
testWidgets('Back arrow uses correct default', (WidgetTester tester) async { testWidgets('Back arrow uses correct default on Android', (WidgetTester tester) async {
await expectBackIcon(tester, Icons.arrow_back); await expectBackIcon(tester, TargetPlatform.android, Icons.arrow_back);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); });
testWidgets('Back arrow uses correct default', (WidgetTester tester) async { testWidgets('Back arrow uses correct default on Fuchsia', (WidgetTester tester) async {
await expectBackIcon(tester, Icons.arrow_back_ios); await expectBackIcon(tester, TargetPlatform.fuchsia, Icons.arrow_back);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Back arrow uses correct default on iOS', (WidgetTester tester) async {
await expectBackIcon(tester, TargetPlatform.iOS, Icons.arrow_back_ios);
});
}); });
group('close button', () { group('close button', () {
Future<void> expectCloseIcon(WidgetTester tester, PageRoute<void> routeBuilder(), String type) async { Future<void> expectCloseIcon(WidgetTester tester, TargetPlatform platform, IconData expectedIcon, PageRoute<void> routeBuilder()) async {
const IconData expectedIcon = Icons.close;
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: platform),
home: Scaffold(appBar: AppBar(), body: const Text('Page 1')), home: Scaffold(appBar: AppBar(), body: const Text('Page 1')),
), ),
); );
@ -549,8 +555,8 @@ void main() {
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
final Icon icon = tester.widget(find.byType(Icon)); final Icon icon = tester.widget(find.byType(Icon));
expect(icon.icon, expectedIcon, reason: "didn't find close icon for $type"); expect(icon.icon, expectedIcon);
expect(find.byType(CloseButton), findsOneWidget, reason: "didn't find close button for $type"); expect(find.byType(CloseButton), findsOneWidget);
} }
PageRoute<void> materialRouteBuilder() { PageRoute<void> materialRouteBuilder() {
@ -580,17 +586,41 @@ void main() {
); );
} }
testWidgets('Close button shows correctly', (WidgetTester tester) async { testWidgets('Close button shows correctly on Android', (WidgetTester tester) async {
await expectCloseIcon(tester, materialRouteBuilder, 'materialRouteBuilder'); await expectCloseIcon(tester, TargetPlatform.android, Icons.close, materialRouteBuilder);
}, variant: TargetPlatformVariant.all()); });
testWidgets('Close button shows correctly with PageRouteBuilder', (WidgetTester tester) async { testWidgets('Close button shows correctly on Fuchsia', (WidgetTester tester) async {
await expectCloseIcon(tester, pageRouteBuilder, 'pageRouteBuilder'); await expectCloseIcon(tester, TargetPlatform.fuchsia, Icons.close, materialRouteBuilder);
}, variant: TargetPlatformVariant.all()); });
testWidgets('Close button shows correctly with custom page route', (WidgetTester tester) async { testWidgets('Close button shows correctly on iOS', (WidgetTester tester) async {
await expectCloseIcon(tester, customPageRouteBuilder, 'customPageRouteBuilder'); await expectCloseIcon(tester, TargetPlatform.iOS, Icons.close, materialRouteBuilder);
}, variant: TargetPlatformVariant.all()); });
testWidgets('Close button shows correctly with PageRouteBuilder on Android', (WidgetTester tester) async {
await expectCloseIcon(tester, TargetPlatform.android, Icons.close, pageRouteBuilder);
});
testWidgets('Close button shows correctly with PageRouteBuilder on Fuchsia', (WidgetTester tester) async {
await expectCloseIcon(tester, TargetPlatform.fuchsia, Icons.close, pageRouteBuilder);
});
testWidgets('Close button shows correctly with PageRouteBuilder on iOS', (WidgetTester tester) async {
await expectCloseIcon(tester, TargetPlatform.iOS, Icons.close, pageRouteBuilder);
});
testWidgets('Close button shows correctly with custom page route on Android', (WidgetTester tester) async {
await expectCloseIcon(tester, TargetPlatform.android, Icons.close, customPageRouteBuilder);
});
testWidgets('Close button shows correctly with custom page route on Fuchsia', (WidgetTester tester) async {
await expectCloseIcon(tester, TargetPlatform.fuchsia, Icons.close, customPageRouteBuilder);
});
testWidgets('Close button shows correctly with custom page route on iOS', (WidgetTester tester) async {
await expectCloseIcon(tester, TargetPlatform.iOS, Icons.close, customPageRouteBuilder);
});
}); });
group('body size', () { group('body size', () {
@ -1794,7 +1824,7 @@ void main() {
'the ScaffoldState rather than using the Scaffold.of() function.\n', 'the ScaffoldState rather than using the Scaffold.of() function.\n',
), ),
); );
expect(error.diagnostics[4], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[4], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.toStringDeep(), expect(error.toStringDeep(),
'FlutterError\n' 'FlutterError\n'
' Scaffold.of() called with a context that does not contain a\n' ' Scaffold.of() called with a context that does not contain a\n'
@ -1863,7 +1893,7 @@ void main() {
'Scaffold.geometryOf().\n', 'Scaffold.geometryOf().\n',
), ),
); );
expect(error.diagnostics[4], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[4], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.toStringDeep(), expect(error.toStringDeep(),
'FlutterError\n' 'FlutterError\n'
' Scaffold.geometryOf() called with a context that does not contain\n' ' Scaffold.geometryOf() called with a context that does not contain\n'

View File

@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
@ -153,20 +152,6 @@ void main() {
await tester.drag(find.byType(SingleChildScrollView), const Offset(0.0, -10.0)); await tester.drag(find.byType(SingleChildScrollView), const Offset(0.0, -10.0));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 200)); await tester.pump(const Duration(milliseconds: 200));
expect(find.byType(Scrollbar), paints..rrect());
expect(find.byType(CupertinoScrollbar), paints..rrect());
await gesture.up();
await tester.pumpAndSettle();
await tester.pumpWidget(viewWithScroll(TargetPlatform.macOS));
await gesture.down(
tester.getCenter(find.byType(SingleChildScrollView)),
);
await gesture.moveBy(const Offset(0.0, -10.0));
await tester.drag(find.byType(SingleChildScrollView), const Offset(0.0, -10.0));
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
expect(find.byType(Scrollbar), paints..rrect());
expect(find.byType(CupertinoScrollbar), paints..rrect()); expect(find.byType(CupertinoScrollbar), paints..rrect());
}); });
@ -188,7 +173,7 @@ void main() {
); );
} }
await tester.pumpWidget(viewWithScroll(debugDefaultTargetPlatformOverride)); await tester.pumpWidget(viewWithScroll(TargetPlatform.iOS));
final TestGesture gesture = await tester.startGesture( final TestGesture gesture = await tester.startGesture(
tester.getCenter(find.byType(SingleChildScrollView)) tester.getCenter(find.byType(SingleChildScrollView))
); );
@ -199,6 +184,6 @@ void main() {
expect(find.byType(CupertinoScrollbar), paints..rrect()); expect(find.byType(CupertinoScrollbar), paints..rrect());
final CupertinoScrollbar scrollbar = find.byType(CupertinoScrollbar).evaluate().first.widget as CupertinoScrollbar; final CupertinoScrollbar scrollbar = find.byType(CupertinoScrollbar).evaluate().first.widget as CupertinoScrollbar;
expect(scrollbar.controller, isNotNull); expect(scrollbar.controller, isNotNull);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
} }

View File

@ -573,8 +573,7 @@ void main() {
SemanticsFlag.isTextField, SemanticsFlag.isTextField,
SemanticsFlag.isFocused, SemanticsFlag.isFocused,
SemanticsFlag.isHeader, SemanticsFlag.isHeader,
if (debugDefaultTargetPlatformOverride != TargetPlatform.iOS && if (debugDefaultTargetPlatformOverride != TargetPlatform.iOS) SemanticsFlag.namesRoute,
debugDefaultTargetPlatformOverride != TargetPlatform.macOS) SemanticsFlag.namesRoute,
], ],
actions: <SemanticsAction>[ actions: <SemanticsAction>[
SemanticsAction.tap, SemanticsAction.tap,
@ -623,7 +622,8 @@ void main() {
semantics.dispose(); semantics.dispose();
}); });
testWidgets('does not include routeName', (WidgetTester tester) async { testWidgets('does not include routeName on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
final _TestSearchDelegate delegate = _TestSearchDelegate(); final _TestSearchDelegate delegate = _TestSearchDelegate();
await tester.pumpWidget(TestHomePage( await tester.pumpWidget(TestHomePage(
@ -636,8 +636,9 @@ void main() {
expect(semantics, hasSemantics(buildExpected(routeName: ''), expect(semantics, hasSemantics(buildExpected(routeName: ''),
ignoreId: true, ignoreRect: true, ignoreTransform: true)); ignoreId: true, ignoreRect: true, ignoreTransform: true));
debugDefaultTargetPlatformOverride = null;
semantics.dispose(); semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
}); });
} }

View File

@ -1250,14 +1250,16 @@ void main() {
)); ));
semantics.dispose(); semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); });
testWidgets('Slider Semantics', (WidgetTester tester) async { testWidgets('Slider Semantics - iOS', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget( await tester.pumpWidget(
Theme( Theme(
data: ThemeData.light(), data: ThemeData.light().copyWith(
platform: TargetPlatform.iOS,
),
child: Directionality( child: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: MediaQuery( child: MediaQuery(
@ -1292,7 +1294,7 @@ void main() {
ignoreTransform: true, ignoreTransform: true,
)); ));
semantics.dispose(); semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Slider semantics with custom formatter', (WidgetTester tester) async { testWidgets('Slider semantics with custom formatter', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
@ -1483,34 +1485,27 @@ void main() {
); );
} }
for (final TargetPlatform platform in <TargetPlatform>[TargetPlatform.iOS, TargetPlatform.macOS]) { await tester.pumpWidget(buildFrame(TargetPlatform.iOS));
value = 0.5; expect(find.byType(Slider), findsOneWidget);
await tester.pumpWidget(buildFrame(platform)); expect(find.byType(CupertinoSlider), findsOneWidget);
expect(find.byType(Slider), findsOneWidget);
expect(find.byType(CupertinoSlider), findsOneWidget);
expect(value, 0.5, reason: 'on ${describeEnum(platform)}'); expect(value, 0.5);
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CupertinoSlider))); TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CupertinoSlider)));
// Drag to the right end of the track. // Drag to the right end of the track.
await gesture.moveBy(const Offset(600.0, 0.0)); await gesture.moveBy(const Offset(600.0, 0.0));
expect(value, 1.0, reason: 'on ${describeEnum(platform)}'); expect(value, 1.0);
await gesture.up();
}
for (final TargetPlatform platform in <TargetPlatform>[TargetPlatform.android, TargetPlatform.fuchsia]) { value = 0.5;
value = 0.5; await tester.pumpWidget(buildFrame(TargetPlatform.android));
await tester.pumpWidget(buildFrame(platform)); await tester.pumpAndSettle(); // Finish the theme change animation.
await tester.pumpAndSettle(); // Finish the theme change animation. expect(find.byType(Slider), findsOneWidget);
expect(find.byType(Slider), findsOneWidget); expect(find.byType(CupertinoSlider), findsNothing);
expect(find.byType(CupertinoSlider), findsNothing);
expect(value, 0.5, reason: 'on ${describeEnum(platform)}'); expect(value, 0.5);
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Slider))); gesture = await tester.startGesture(tester.getCenter(find.byType(Slider)));
// Drag to the right end of the track. // Drag to the right end of the track.
await gesture.moveBy(const Offset(600.0, 0.0)); await gesture.moveBy(const Offset(600.0, 0.0));
expect(value, 1.0, reason: 'on ${describeEnum(platform)}'); expect(value, 1.0);
await gesture.up();
}
}); });
testWidgets('Slider respects height from theme', (WidgetTester tester) async { testWidgets('Slider respects height from theme', (WidgetTester tester) async {

View File

@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
@ -86,26 +85,20 @@ void main() {
); );
} }
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.iOS, TargetPlatform.macOS ]) { await tester.pumpWidget(buildFrame(TargetPlatform.iOS));
value = false; expect(find.byType(CupertinoSwitch), findsOneWidget);
await tester.pumpWidget(buildFrame(platform)); expect(value, isFalse);
expect(find.byType(CupertinoSwitch), findsOneWidget);
expect(value, isFalse, reason: 'on ${describeEnum(platform)}');
await tester.tap(find.byType(SwitchListTile)); await tester.tap(find.byType(SwitchListTile));
expect(value, isTrue, reason: 'on ${describeEnum(platform)}'); expect(value, isTrue);
}
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.android, TargetPlatform.fuchsia ]) { await tester.pumpWidget(buildFrame(TargetPlatform.android));
value = false; await tester.pumpAndSettle(); // Finish the theme change animation.
await tester.pumpWidget(buildFrame(platform));
await tester.pumpAndSettle(); // Finish the theme change animation.
expect(find.byType(CupertinoSwitch), findsNothing); expect(find.byType(CupertinoSwitch), findsNothing);
expect(value, isFalse, reason: 'on ${describeEnum(platform)}'); expect(value, isTrue);
await tester.tap(find.byType(SwitchListTile)); await tester.tap(find.byType(SwitchListTile));
expect(value, isTrue, reason: 'on ${describeEnum(platform)}'); expect(value, isFalse);
}
}); });
testWidgets('SwitchListTile contentPadding', (WidgetTester tester) async { testWidgets('SwitchListTile contentPadding', (WidgetTester tester) async {

View File

@ -610,28 +610,23 @@ void main() {
); );
} }
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.iOS, TargetPlatform.macOS ]) { await tester.pumpWidget(buildFrame(TargetPlatform.iOS));
value = false; expect(find.byType(CupertinoSwitch), findsOneWidget);
await tester.pumpWidget(buildFrame(platform));
expect(find.byType(CupertinoSwitch), findsOneWidget, reason: 'on ${describeEnum(platform)}');
final CupertinoSwitch adaptiveSwitch = tester.widget(find.byType(CupertinoSwitch)); final CupertinoSwitch adaptiveSwitch = tester.widget(find.byType(CupertinoSwitch));
expect(adaptiveSwitch.trackColor, inactiveTrackColor, reason: 'on ${describeEnum(platform)}'); expect(adaptiveSwitch.trackColor, inactiveTrackColor);
expect(value, isFalse, reason: 'on ${describeEnum(platform)}'); expect(value, isFalse);
await tester.tap(find.byType(Switch)); await tester.tap(find.byType(Switch));
expect(value, isTrue, reason: 'on ${describeEnum(platform)}'); expect(value, isTrue);
}
await tester.pumpWidget(buildFrame(TargetPlatform.android));
await tester.pumpAndSettle(); // Finish the theme change animation.
expect(find.byType(CupertinoSwitch), findsNothing);
expect(value, isTrue);
await tester.tap(find.byType(Switch));
expect(value, isFalse);
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.android, TargetPlatform.fuchsia ]) {
value = false;
await tester.pumpWidget(buildFrame(platform));
await tester.pumpAndSettle(); // Finish the theme change animation.
expect(find.byType(CupertinoSwitch), findsNothing);
expect(value, isFalse, reason: 'on ${describeEnum(platform)}');
await tester.tap(find.byType(Switch));
expect(value, isTrue, reason: 'on ${describeEnum(platform)}');
}
}); });
testWidgets('Switch is focusable and has correct focus color', (WidgetTester tester) async { testWidgets('Switch is focusable and has correct focus color', (WidgetTester tester) async {

View File

@ -304,7 +304,9 @@ void main() {
await checkCursorToggle(); await checkCursorToggle();
}); });
testWidgets('Cursor animates', (WidgetTester tester) async { testWidgets('Cursor animates on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
home: Material( home: Material(
@ -338,9 +340,13 @@ void main() {
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
expect(renderEditable.cursorColor.alpha, 0); expect(renderEditable.cursorColor.alpha, 0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('Cursor radius is 2.0', (WidgetTester tester) async { debugDefaultTargetPlatformOverride = null;
});
testWidgets('Cursor radius is 2.0 on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
home: Material( home: Material(
@ -353,7 +359,9 @@ void main() {
final RenderEditable renderEditable = editableTextState.renderEditable; final RenderEditable renderEditable = editableTextState.renderEditable;
expect(renderEditable.cursorRadius, const Radius.circular(2.0)); expect(renderEditable.cursorRadius, const Radius.circular(2.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('cursor has expected defaults', (WidgetTester tester) async { testWidgets('cursor has expected defaults', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
@ -408,7 +416,9 @@ void main() {
); );
}); });
testWidgets('Material cursor golden', (WidgetTester tester) async { testWidgets('Material cursor iOS golden', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Widget widget = overlay( final Widget widget = overlay(
child: const RepaintBoundary( child: const RepaintBoundary(
key: ValueKey<int>(1), key: ValueKey<int>(1),
@ -428,13 +438,12 @@ void main() {
await tester.tapAt(textOffsetToPosition(tester, testValue.length)); await tester.tapAt(textOffsetToPosition(tester, testValue.length));
await tester.pump(); await tester.pump();
debugDefaultTargetPlatformOverride = null;
await expectLater( await expectLater(
find.byKey(const ValueKey<int>(1)), find.byKey(const ValueKey<int>(1)),
matchesGoldenFile( matchesGoldenFile('text_field_cursor_test.material.1.png'),
'text_field_cursor_test_${describeEnum(debugDefaultTargetPlatformOverride).toLowerCase()}.material.1.png',
),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('text field selection toolbar renders correctly inside opacity', (WidgetTester tester) async { testWidgets('text field selection toolbar renders correctly inside opacity', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
@ -487,13 +496,14 @@ void main() {
); );
}, skip: isBrowser); }, skip: isBrowser);
testWidgets('text field toolbar options correctly changes options', testWidgets('text field toolbar options correctly changes options (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -534,9 +544,9 @@ void main() {
expect(find.text('Copy'), findsOneWidget); expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), findsNothing); expect(find.text('Cut'), findsNothing);
expect(find.text('Select All'), findsNothing); expect(find.text('Select All'), findsNothing);
}, skip: isBrowser, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); }, skip: isBrowser);
testWidgets('text field toolbar options correctly changes options', testWidgets('text field toolbar options correctly changes options (Android)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
@ -567,8 +577,10 @@ void main() {
expect(find.text('COPY'), findsOneWidget); expect(find.text('COPY'), findsOneWidget);
expect(find.text('CUT'), findsNothing); expect(find.text('CUT'), findsNothing);
expect(find.text('SELECT ALL'), findsNothing); expect(find.text('SELECT ALL'), findsNothing);
}, skip: isBrowser, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); }, skip: isBrowser);
// TODO(hansmuller): restore these tests after the fix for #24876 has landed.
/*
testWidgets('cursor layout has correct width', (WidgetTester tester) async { testWidgets('cursor layout has correct width', (WidgetTester tester) async {
EditableText.debugDeterministicCursor = true; EditableText.debugDeterministicCursor = true;
await tester.pumpWidget( await tester.pumpWidget(
@ -585,10 +597,10 @@ void main() {
await expectLater( await expectLater(
find.byType(TextField), find.byType(TextField),
matchesGoldenFile('text_field_cursor_width_test.0.0.png', version: 0), matchesGoldenFile('text_field_test.0.0.png'),
); );
EditableText.debugDeterministicCursor = false; EditableText.debugDeterministicCursor = false;
}, skip: !isLinux); }, skip: !Platform.isLinux);
testWidgets('cursor layout has correct radius', (WidgetTester tester) async { testWidgets('cursor layout has correct radius', (WidgetTester tester) async {
EditableText.debugDeterministicCursor = true; EditableText.debugDeterministicCursor = true;
@ -607,10 +619,11 @@ void main() {
await expectLater( await expectLater(
find.byType(TextField), find.byType(TextField),
matchesGoldenFile('text_field_cursor_width_test.1.0.png', version: 0), matchesGoldenFile('text_field_test.1.0.png'),
); );
EditableText.debugDeterministicCursor = false; EditableText.debugDeterministicCursor = false;
}, skip: !isLinux); }, skip: !Platform.isLinux);
*/
testWidgets('Overflowing a line with spaces stops the cursor at the end', (WidgetTester tester) async { testWidgets('Overflowing a line with spaces stops the cursor at the end', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
@ -857,27 +870,6 @@ void main() {
expect(handle.opacity.value, equals(1.0)); expect(handle.opacity.value, equals(1.0));
}); });
testWidgets('Long pressing a field with selection 0,0 shows the selection menu', (WidgetTester tester) async {
await tester.pumpWidget(overlay(
child: TextField(
controller: TextEditingController.fromValue(
const TextEditingValue(
selection: TextSelection(baseOffset: 0, extentOffset: 0),
),
),
),
));
expect(find.text('PASTE'), findsNothing);
final Offset emptyPos = textOffsetToPosition(tester, 0);
await tester.longPressAt(emptyPos, pointer: 7);
await tester.pumpAndSettle();
expect(find.text('PASTE'), findsOneWidget);
});
testWidgets('Entering text hides selection handle caret', (WidgetTester tester) async { testWidgets('Entering text hides selection handle caret', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
@ -986,10 +978,11 @@ void main() {
expect(find.text('CUT'), findsNothing); expect(find.text('CUT'), findsNothing);
}); });
testWidgets('does not paint toolbar when no options available', (WidgetTester tester) async { testWidgets('does not paint toolbar when no options available on ios', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( MaterialApp(
home: Material( theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField( child: TextField(
readOnly: true, readOnly: true,
), ),
@ -1005,9 +998,9 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.byType(CupertinoTextSelectionToolbar), paintsNothing); expect(find.byType(CupertinoTextSelectionToolbar), paintsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('text field build empty toolbar when no options available', (WidgetTester tester) async { testWidgets('text field build empty toolbar when no options available android', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
home: Material( home: Material(
@ -1029,7 +1022,7 @@ void main() {
matching: find.byType(Container), matching: find.byType(Container),
)); ));
expect(container.size, Size.zero); expect(container.size, Size.zero);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); });
testWidgets('Sawping controllers should update selection', (WidgetTester tester) async { testWidgets('Sawping controllers should update selection', (WidgetTester tester) async {
TextEditingController controller = TextEditingController(text: 'readonly'); TextEditingController controller = TextEditingController(text: 'readonly');
@ -5507,13 +5500,14 @@ void main() {
}); });
testWidgets( testWidgets(
'tap moves cursor to the edge of the word it tapped', 'tap moves cursor to the edge of the word it tapped on (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -5537,9 +5531,12 @@ void main() {
// But don't trigger the toolbar. // But don't trigger the toolbar.
expect(find.byType(CupertinoButton), findsNothing); expect(find.byType(CupertinoButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets('tap moves cursor to the position tapped', (WidgetTester tester) async { testWidgets(
'tap moves cursor to the position tapped (Android)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
@ -5568,16 +5565,18 @@ void main() {
// But don't trigger the toolbar. // But don't trigger the toolbar.
expect(find.byType(FlatButton), findsNothing); expect(find.byType(FlatButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); },
);
testWidgets( testWidgets(
'two slow taps do not trigger a word selection', 'two slow taps do not trigger a word selection (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -5603,16 +5602,18 @@ void main() {
// No toolbar. // No toolbar.
expect(find.byType(CupertinoButton), findsNothing); expect(find.byType(CupertinoButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets( testWidgets(
'double tap selects word and first tap of double tap moves cursor', 'double tap selects word and first tap of double tap moves cursor (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -5648,10 +5649,11 @@ void main() {
// Selected text shows 3 toolbar buttons. // Selected text shows 3 toolbar buttons.
expect(find.byType(CupertinoButton), findsNWidgets(3)); expect(find.byType(CupertinoButton), findsNWidgets(3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets( testWidgets(
'double tap selects word and first tap of double tap moves cursor and shows toolbar', 'double tap selects word and first tap of double tap moves cursor and shows toolbar (Android)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
@ -5693,10 +5695,11 @@ void main() {
// Selected text shows 4 toolbar buttons: cut, copy, paste, select all // Selected text shows 4 toolbar buttons: cut, copy, paste, select all
expect(find.byType(FlatButton), findsNWidgets(4)); expect(find.byType(FlatButton), findsNWidgets(4));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); },
);
testWidgets( testWidgets(
'double tap on top of cursor also selects word', 'double tap on top of cursor also selects word (Android)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
@ -5742,7 +5745,8 @@ void main() {
// Selected text shows 4 toolbar buttons: cut, copy, paste, select all // Selected text shows 4 toolbar buttons: cut, copy, paste, select all
expect(find.byType(FlatButton), findsNWidgets(4)); expect(find.byType(FlatButton), findsNWidgets(4));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); },
);
testWidgets( testWidgets(
'double double tap just shows the selection menu', 'double double tap just shows the selection menu',
@ -5869,13 +5873,14 @@ void main() {
); );
testWidgets( testWidgets(
'double tap hold selects word', 'double tap hold selects word (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -5913,16 +5918,18 @@ void main() {
); );
// The toolbar is still showing. // The toolbar is still showing.
expect(find.byType(CupertinoButton), findsNWidgets(3)); expect(find.byType(CupertinoButton), findsNWidgets(3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets( testWidgets(
'tap after a double tap select is not affected', 'tap after a double tap select is not affected (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -5959,16 +5966,18 @@ void main() {
// No toolbar. // No toolbar.
expect(find.byType(CupertinoButton), findsNothing); expect(find.byType(CupertinoButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets( testWidgets(
'long press moves cursor to the exact long press position and shows toolbar', 'long press moves cursor to the exact long press position and shows toolbar (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -5992,10 +6001,11 @@ void main() {
// Collapsed toolbar shows 2 buttons. // Collapsed toolbar shows 2 buttons.
expect(find.byType(CupertinoButton), findsNWidgets(2)); expect(find.byType(CupertinoButton), findsNWidgets(2));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets( testWidgets(
'long press selects word and shows toolbar', 'long press selects word and shows toolbar (Android)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
@ -6024,16 +6034,18 @@ void main() {
// Collapsed toolbar shows 4 buttons: cut, copy, paste, select all // Collapsed toolbar shows 4 buttons: cut, copy, paste, select all
expect(find.byType(FlatButton), findsNWidgets(4)); expect(find.byType(FlatButton), findsNWidgets(4));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); },
);
testWidgets( testWidgets(
'long press tap cannot initiate a double tap', 'long press tap cannot initiate a double tap (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -6061,16 +6073,18 @@ void main() {
// Collapsed toolbar shows 2 buttons. // Collapsed toolbar shows 2 buttons.
expect(find.byType(CupertinoButton), findsNothing); expect(find.byType(CupertinoButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets( testWidgets(
'long press drag moves the cursor under the drag and shows toolbar on lift', 'long press drag moves the cursor under the drag and shows toolbar on lift (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -6127,14 +6141,16 @@ void main() {
); );
// The toolbar now shows up. // The toolbar now shows up.
expect(find.byType(CupertinoButton), findsNWidgets(2)); expect(find.byType(CupertinoButton), findsNWidgets(2));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets('long press drag can edge scroll', (WidgetTester tester) async { testWidgets('long press drag can edge scroll (iOS)', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -6216,16 +6232,17 @@ void main() {
expect(firstCharEndpoint.length, 1); expect(firstCharEndpoint.length, 1);
// The first character is now offscreen to the left. // The first character is now offscreen to the left.
expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257, epsilon: 1)); expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257, epsilon: 1));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets( testWidgets(
'long tap after a double tap select is not affected', 'long tap after a double tap select is not affected (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -6259,16 +6276,18 @@ void main() {
// Long press toolbar. // Long press toolbar.
expect(find.byType(CupertinoButton), findsNWidgets(2)); expect(find.byType(CupertinoButton), findsNWidgets(2));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets( testWidgets(
'double tap after a long tap is not affected', 'double tap after a long tap is not affected (iOS)',
(WidgetTester tester) async { (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -6300,14 +6319,18 @@ void main() {
const TextSelection(baseOffset: 8, extentOffset: 12), const TextSelection(baseOffset: 8, extentOffset: 12),
); );
expect(find.byType(CupertinoButton), findsNWidgets(3)); expect(find.byType(CupertinoButton), findsNWidgets(3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets('double tap chains work', (WidgetTester tester) async { testWidgets(
'double tap chains work (iOS)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: Center( child: Center(
child: TextField( child: TextField(
@ -6364,9 +6387,10 @@ void main() {
const TextSelection(baseOffset: 8, extentOffset: 12), const TextSelection(baseOffset: 8, extentOffset: 12),
); );
expect(find.byType(CupertinoButton), findsNWidgets(3)); expect(find.byType(CupertinoButton), findsNWidgets(3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); },
);
testWidgets('force press does not select a word', (WidgetTester tester) async { testWidgets('force press does not select a word on (android)', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
@ -6394,7 +6418,7 @@ void main() {
pressureMin: 0.0, pressureMin: 0.0,
), ),
); );
await gesture.updateWithCustomEvent(PointerMoveEvent(pointer: pointerValue, position: offset + const Offset(150.0, 9.0), pressure: 0.5, pressureMin: 0, pressureMax: 1,),); await gesture.updateWithCustomEvent(PointerMoveEvent(pointer: pointerValue, position: offset + const Offset(150.0, 9.0), pressure: 0.5, pressureMin: 0, pressureMax: 1));
// We don't want this gesture to select any word on Android. // We don't want this gesture to select any word on Android.
expect(controller.selection, const TextSelection.collapsed(offset: -1)); expect(controller.selection, const TextSelection.collapsed(offset: -1));
@ -6402,14 +6426,15 @@ void main() {
await gesture.up(); await gesture.up();
await tester.pump(); await tester.pump();
expect(find.byType(FlatButton), findsNothing); expect(find.byType(FlatButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); });
testWidgets('force press selects word', (WidgetTester tester) async { testWidgets('force press selects word (iOS)', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: TextField( child: TextField(
controller: controller, controller: controller,
@ -6434,15 +6459,7 @@ void main() {
), ),
); );
await gesture.updateWithCustomEvent( await gesture.updateWithCustomEvent(PointerMoveEvent(pointer: pointerValue, position: textfieldStart + const Offset(150.0, 9.0), pressure: 0.5, pressureMin: 0, pressureMax: 1));
PointerMoveEvent(
pointer: pointerValue,
position: textfieldStart + const Offset(150.0, 9.0),
pressure: 0.5,
pressureMin: 0,
pressureMax: 1,
),
);
// We expect the force press to select a word at the given location. // We expect the force press to select a word at the given location.
expect( expect(
controller.selection, controller.selection,
@ -6452,15 +6469,15 @@ void main() {
await gesture.up(); await gesture.up();
await tester.pump(); await tester.pump();
expect(find.byType(CupertinoButton), findsNWidgets(3)); expect(find.byType(CupertinoButton), findsNWidgets(3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { testWidgets('tap on non-force-press-supported devices work (iOS)', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure', text: 'Atwater Peel Sherbrooke Bonaventure',
); );
await tester.pumpWidget(Container(key: GlobalKey()));
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material( home: Material(
child: TextField( child: TextField(
controller: controller, controller: controller,
@ -6486,15 +6503,7 @@ void main() {
), ),
); );
await gesture.updateWithCustomEvent( await gesture.updateWithCustomEvent(PointerMoveEvent(pointer: pointerValue, position: textfieldStart + const Offset(150.0, 9.0), pressure: 0.5, pressureMin: 0, pressureMax: 1));
PointerMoveEvent(
pointer: pointerValue,
position: textfieldStart + const Offset(150.0, 9.0),
pressure: 0.5,
pressureMin: 0,
pressureMax: 1,
),
);
await gesture.up(); await gesture.up();
// The event should fallback to a normal tap and move the cursor. // The event should fallback to a normal tap and move the cursor.
// Single taps selects the edge of the word. // Single taps selects the edge of the word.
@ -6506,10 +6515,7 @@ void main() {
await tester.pump(); await tester.pump();
// Single taps shouldn't trigger the toolbar. // Single taps shouldn't trigger the toolbar.
expect(find.byType(CupertinoButton), findsNothing); expect(find.byType(CupertinoButton), findsNothing);
});
// TODO(gspencergoog): Add in TargetPlatform.macOS in the line below when we figure out what global state is leaking.
// https://github.com/flutter/flutter/issues/43445
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS));
testWidgets('default TextField debugFillProperties', (WidgetTester tester) async { testWidgets('default TextField debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
@ -6916,6 +6922,7 @@ void main() {
}); });
testWidgets('iOS selection handles are rendered and not faded away', (WidgetTester tester) async { testWidgets('iOS selection handles are rendered and not faded away', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
const String testText = 'lorem ipsum'; const String testText = 'lorem ipsum';
final TextEditingController controller = TextEditingController(text: testText); final TextEditingController controller = TextEditingController(text: testText);
@ -6944,7 +6951,9 @@ void main() {
expect(left.opacity.value, equals(1.0)); expect(left.opacity.value, equals(1.0));
expect(right.opacity.value, equals(1.0)); expect(right.opacity.value, equals(1.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('Tap shows handles but not toolbar', (WidgetTester tester) async { testWidgets('Tap shows handles but not toolbar', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(

View File

@ -196,7 +196,6 @@ void main() {
const PageTransitionsTheme pageTransitionTheme = PageTransitionsTheme( const PageTransitionsTheme pageTransitionTheme = PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{ builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
TargetPlatform.macOS: CupertinoPageTransitionsBuilder(),
}, },
); );

View File

@ -21,36 +21,17 @@ void main() {
expect(Typography(platform: TargetPlatform.fuchsia).black.title.fontFamily, 'Roboto'); expect(Typography(platform: TargetPlatform.fuchsia).black.title.fontFamily, 'Roboto');
}); });
// Ref: https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/
final Matcher isDisplayFont = predicate((TextStyle s) {
return s.fontFamily == '.SF UI Display';
}, 'Uses SF Display font');
final Matcher isTextFont = predicate((TextStyle s) {
return s.fontFamily == '.SF UI Text';
}, 'Uses SF Text font');
test('Typography on iOS defaults to the correct SF font family based on size', () { test('Typography on iOS defaults to the correct SF font family based on size', () {
final Typography typography = Typography(platform: TargetPlatform.iOS); // Ref: https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/
for (final TextTheme textTheme in <TextTheme>[typography.black, typography.white]) { final Matcher isDisplayFont = predicate((TextStyle s) {
expect(textTheme.display4, isDisplayFont); return s.fontFamily == '.SF UI Display';
expect(textTheme.display3, isDisplayFont); }, 'Uses SF Display font');
expect(textTheme.display2, isDisplayFont);
expect(textTheme.display1, isDisplayFont);
expect(textTheme.headline, isDisplayFont);
expect(textTheme.title, isDisplayFont);
expect(textTheme.subhead, isTextFont);
expect(textTheme.body2, isTextFont);
expect(textTheme.body1, isTextFont);
expect(textTheme.caption, isTextFont);
expect(textTheme.button, isTextFont);
expect(textTheme.subtitle, isTextFont);
expect(textTheme.overline, isTextFont);
}
});
test('Typography on macOS defaults to the correct SF font family based on size', () { final Matcher isTextFont = predicate((TextStyle s) {
final Typography typography = Typography(platform: TargetPlatform.macOS); return s.fontFamily == '.SF UI Text';
}, 'Uses SF Text font');
final Typography typography = Typography(platform: TargetPlatform.iOS);
for (final TextTheme textTheme in <TextTheme>[typography.black, typography.white]) { for (final TextTheme textTheme in <TextTheme>[typography.black, typography.white]) {
expect(textTheme.display4, isDisplayFont); expect(textTheme.display4, isDisplayFont);
expect(textTheme.display3, isDisplayFont); expect(textTheme.display3, isDisplayFont);

View File

@ -502,7 +502,7 @@ void main() {
); );
expect( expect(
const BorderDirectional(start: magenta3) + const BorderDirectional(start: yellow2), const BorderDirectional(start: magenta3) + const BorderDirectional(start: yellow2),
isNot(isA<BorderDirectional>()), // see shape_border_test.dart for better tests of this case isNot(isInstanceOf<BorderDirectional>()), // see shape_border_test.dart for better tests of this case
); );
const BorderDirectional b3 = BorderDirectional(top: magenta3); const BorderDirectional b3 = BorderDirectional(top: magenta3);
const BorderDirectional b6 = BorderDirectional(top: magenta6); const BorderDirectional b6 = BorderDirectional(top: magenta6);

View File

@ -97,7 +97,7 @@ void main() {
); );
expect( expect(
const Border(left: magenta3) + const Border(left: yellow2), const Border(left: magenta3) + const Border(left: yellow2),
isNot(isA<Border>()), // see shape_border_test.dart for better tests of this case isNot(isInstanceOf<Border>()), // see shape_border_test.dart for better tests of this case
); );
const Border b3 = Border(top: magenta3); const Border b3 = Border(top: magenta3);
const Border b6 = Border(top: magenta6); const Border b6 = Border(top: magenta6);

View File

@ -223,10 +223,10 @@ void main() {
final Invocation call = canvas.invocations.singleWhere((Invocation call) => call.memberName == #drawImageNine); final Invocation call = canvas.invocations.singleWhere((Invocation call) => call.memberName == #drawImageNine);
expect(call.isMethod, isTrue); expect(call.isMethod, isTrue);
expect(call.positionalArguments, hasLength(4)); expect(call.positionalArguments, hasLength(4));
expect(call.positionalArguments[0], isA<TestImage>()); expect(call.positionalArguments[0], isInstanceOf<TestImage>());
expect(call.positionalArguments[1], const Rect.fromLTRB(10.0, 20.0, 40.0, 60.0)); expect(call.positionalArguments[1], const Rect.fromLTRB(10.0, 20.0, 40.0, 60.0));
expect(call.positionalArguments[2], const Rect.fromLTRB(0.0, 0.0, 100.0, 100.0)); expect(call.positionalArguments[2], const Rect.fromLTRB(0.0, 0.0, 100.0, 100.0));
expect(call.positionalArguments[3], isA<Paint>()); expect(call.positionalArguments[3], isInstanceOf<Paint>());
expect(call.positionalArguments[3].isAntiAlias, false); expect(call.positionalArguments[3].isAntiAlias, false);
expect(call.positionalArguments[3].colorFilter, colorFilter); expect(call.positionalArguments[3].colorFilter, colorFilter);
expect(call.positionalArguments[3].filterQuality, FilterQuality.low); expect(call.positionalArguments[3].filterQuality, FilterQuality.low);
@ -253,8 +253,8 @@ void main() {
} }
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 4); expect(error.diagnostics.length, 4);
expect(error.diagnostics[2], isA<DiagnosticsProperty<DecorationImage>>()); expect(error.diagnostics[2], isInstanceOf<DiagnosticsProperty<DecorationImage>>());
expect(error.diagnostics[3], isA<DiagnosticsProperty<ImageConfiguration>>()); expect(error.diagnostics[3], isInstanceOf<DiagnosticsProperty<ImageConfiguration>>());
expect(error.toStringDeep(), expect(error.toStringDeep(),
'FlutterError\n' 'FlutterError\n'
' DecorationImage.matchTextDirection can only be used when a\n' ' DecorationImage.matchTextDirection can only be used when a\n'
@ -375,10 +375,10 @@ void main() {
}); });
test('Decoration.lerp with unrelated decorations', () { test('Decoration.lerp with unrelated decorations', () {
expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 0.0), isA<FlutterLogoDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 0.0), isInstanceOf<FlutterLogoDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION
expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 0.25), isA<FlutterLogoDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 0.25), isInstanceOf<FlutterLogoDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION
expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 0.75), isA<BoxDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 0.75), isInstanceOf<BoxDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION
expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 1.0), isA<BoxDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION expect(Decoration.lerp(const FlutterLogoDecoration(), const BoxDecoration(), 1.0), isInstanceOf<BoxDecoration>()); // ignore: CONST_EVAL_THROWS_EXCEPTION
}); });
test('paintImage BoxFit.none scale test', () { test('paintImage BoxFit.none scale test', () {
@ -406,7 +406,7 @@ void main() {
expect(call.isMethod, isTrue); expect(call.isMethod, isTrue);
expect(call.positionalArguments, hasLength(4)); expect(call.positionalArguments, hasLength(4));
expect(call.positionalArguments[0], isA<TestImage>()); expect(call.positionalArguments[0], isInstanceOf<TestImage>());
// sourceRect should contain all pixels of the source image // sourceRect should contain all pixels of the source image
expect(call.positionalArguments[1], Offset.zero & imageSize); expect(call.positionalArguments[1], Offset.zero & imageSize);
@ -420,7 +420,7 @@ void main() {
); );
expect(call.positionalArguments[2], expectedTileRect); expect(call.positionalArguments[2], expectedTileRect);
expect(call.positionalArguments[3], isA<Paint>()); expect(call.positionalArguments[3], isInstanceOf<Paint>());
} }
}); });
@ -450,7 +450,7 @@ void main() {
expect(call.isMethod, isTrue); expect(call.isMethod, isTrue);
expect(call.positionalArguments, hasLength(4)); expect(call.positionalArguments, hasLength(4));
expect(call.positionalArguments[0], isA<TestImage>()); expect(call.positionalArguments[0], isInstanceOf<TestImage>());
// sourceRect should contain all pixels of the source image // sourceRect should contain all pixels of the source image
expect(call.positionalArguments[1], Offset.zero & imageSize); expect(call.positionalArguments[1], Offset.zero & imageSize);
@ -464,7 +464,7 @@ void main() {
); );
expect(call.positionalArguments[2], expectedTileRect); expect(call.positionalArguments[2], expectedTileRect);
expect(call.positionalArguments[3], isA<Paint>()); expect(call.positionalArguments[3], isInstanceOf<Paint>());
} }
}); });
@ -493,7 +493,7 @@ void main() {
expect(call.isMethod, isTrue); expect(call.isMethod, isTrue);
expect(call.positionalArguments, hasLength(4)); expect(call.positionalArguments, hasLength(4));
expect(call.positionalArguments[0], isA<TestImage>()); expect(call.positionalArguments[0], isInstanceOf<TestImage>());
// sourceRect should contain all pixels of the source image // sourceRect should contain all pixels of the source image
expect(call.positionalArguments[1], Offset.zero & imageSize); expect(call.positionalArguments[1], Offset.zero & imageSize);
@ -507,7 +507,7 @@ void main() {
); );
expect(call.positionalArguments[2], expectedTileRect); expect(call.positionalArguments[2], expectedTileRect);
expect(call.positionalArguments[3], isA<Paint>()); expect(call.positionalArguments[3], isInstanceOf<Paint>());
}); });
test('paintImage boxFit, scale and alignment test', () { test('paintImage boxFit, scale and alignment test', () {

View File

@ -175,7 +175,7 @@ void main() {
test('EdgeInsetsGeometry operators', () { test('EdgeInsetsGeometry operators', () {
final EdgeInsetsGeometry a = const EdgeInsetsDirectional.fromSTEB(1.0, 2.0, 3.0, 5.0).add(EdgeInsets.zero); final EdgeInsetsGeometry a = const EdgeInsetsDirectional.fromSTEB(1.0, 2.0, 3.0, 5.0).add(EdgeInsets.zero);
expect(a, isNot(isA<EdgeInsetsDirectional>())); expect(a, isNot(isInstanceOf<EdgeInsetsDirectional>()));
expect(a * 2.0, const EdgeInsetsDirectional.fromSTEB(2.0, 4.0, 6.0, 10.0)); expect(a * 2.0, const EdgeInsetsDirectional.fromSTEB(2.0, 4.0, 6.0, 10.0));
expect(a / 2.0, const EdgeInsetsDirectional.fromSTEB(0.5, 1.0, 1.5, 2.5)); expect(a / 2.0, const EdgeInsetsDirectional.fromSTEB(0.5, 1.0, 1.5, 2.5));
expect(a % 2.0, const EdgeInsetsDirectional.fromSTEB(1.0, 0.0, 1.0, 1.0)); expect(a % 2.0, const EdgeInsetsDirectional.fromSTEB(1.0, 0.0, 1.0, 1.0));

View File

@ -133,7 +133,7 @@ void main() {
test('Returns null if an error is caught resolving an image', () { test('Returns null if an error is caught resolving an image', () {
final ErrorImageProvider errorImage = ErrorImageProvider(); final ErrorImageProvider errorImage = ErrorImageProvider();
expect(() => imageCache.putIfAbsent(errorImage, () => errorImage.load(errorImage, null)), throwsA(isA<Error>())); expect(() => imageCache.putIfAbsent(errorImage, () => errorImage.load(errorImage, null)), throwsA(isInstanceOf<Error>()));
bool caughtError = false; bool caughtError = false;
final ImageStreamCompleter result = imageCache.putIfAbsent(errorImage, () => errorImage.load(errorImage, null), onError: (dynamic error, StackTrace stackTrace) { final ImageStreamCompleter result = imageCache.putIfAbsent(errorImage, () => errorImage.load(errorImage, null), onError: (dynamic error, StackTrace stackTrace) {
caughtError = true; caughtError = true;

View File

@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:test_api/test_api.dart' show TypeMatcher; // ignore: deprecated_member_use
import '../rendering/rendering_tester.dart'; import '../rendering/rendering_tester.dart';
import 'image_data.dart'; import 'image_data.dart';
@ -181,7 +182,7 @@ void main() {
final dynamic err = await caughtError.future; final dynamic err = await caughtError.future;
expect( expect(
err, err,
isA<NetworkImageLoadException>() const TypeMatcher<NetworkImageLoadException>()
.having((NetworkImageLoadException e) => e.statusCode, 'statusCode', errorStatusCode) .having((NetworkImageLoadException e) => e.statusCode, 'statusCode', errorStatusCode)
.having((NetworkImageLoadException e) => e.uri, 'uri', Uri.base.resolve(requestUrl)), .having((NetworkImageLoadException e) => e.uri, 'uri', Uri.base.resolve(requestUrl)),
); );

View File

@ -4,8 +4,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import '../flutter_test_alternative.dart';
import 'rendering_tester.dart'; import 'rendering_tester.dart';
void main() { void main() {
@ -114,7 +113,7 @@ void main() {
errors.addAll(renderer.takeAllFlutterErrorDetails()); errors.addAll(renderer.takeAllFlutterErrorDetails());
}); });
expect(errors, hasLength(2)); expect(errors, hasLength(2));
expect(errors.first.exception, isFlutterError); expect(errors.first.exception, isA<FlutterError>());
expect(errors.first.exception.toStringDeep(), expect(errors.first.exception.toStringDeep(),
'FlutterError\n' 'FlutterError\n'
' RenderAspectRatio has unbounded constraints.\n' ' RenderAspectRatio has unbounded constraints.\n'

View File

@ -3,7 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import '../flutter_test_alternative.dart';
void main() { void main() {
test('BoxConstraints toString', () { test('BoxConstraints toString', () {
@ -153,9 +153,9 @@ void main() {
minHeight: 20.0, minHeight: 20.0,
maxHeight: 30.0, maxHeight: 30.0,
); );
expect(() => BoxConstraints.lerp(constraints1, constraints2, 0.5), throwsAssertionError); expect(() => BoxConstraints.lerp(constraints1, constraints2, 0.5), throwsA(isInstanceOf<AssertionError>()));
expect(() => BoxConstraints.lerp(constraints1, constraints3, 0.5), throwsAssertionError); expect(() => BoxConstraints.lerp(constraints1, constraints3, 0.5), throwsA(isInstanceOf<AssertionError>()));
expect(() => BoxConstraints.lerp(constraints2, constraints3, 0.5), throwsAssertionError); expect(() => BoxConstraints.lerp(constraints2, constraints3, 0.5), throwsA(isInstanceOf<AssertionError>()));
}); });
test('BoxConstraints normalize', () { test('BoxConstraints normalize', () {

View File

@ -34,7 +34,7 @@ void main() {
); );
final dynamic exception = tester.takeException(); final dynamic exception = tester.takeException();
expect(exception, isFlutterError); expect(exception, isInstanceOf<FlutterError>());
expect(exception.diagnostics.first.level, DiagnosticLevel.summary); expect(exception.diagnostics.first.level, DiagnosticLevel.summary);
expect(exception.diagnostics.first.toString(), startsWith('A RenderUnconstrainedBox overflowed by ')); expect(exception.diagnostics.first.toString(), startsWith('A RenderUnconstrainedBox overflowed by '));
expect(find.byType(UnconstrainedBox), paints..rect()); expect(find.byType(UnconstrainedBox), paints..rect());

View File

@ -388,7 +388,7 @@ void main() {
exceptions.addAll(renderer.takeAllFlutterExceptions()); exceptions.addAll(renderer.takeAllFlutterExceptions());
}); });
expect(exceptions, isNotEmpty); expect(exceptions, isNotEmpty);
expect(exceptions.first, isFlutterError); expect(exceptions.first, isInstanceOf<FlutterError>());
}); });
test('MainAxisSize.min inside unconstrained', () { test('MainAxisSize.min inside unconstrained', () {
@ -416,7 +416,7 @@ void main() {
exceptions.addAll(renderer.takeAllFlutterExceptions()); exceptions.addAll(renderer.takeAllFlutterExceptions());
}); });
expect(exceptions, isNotEmpty); expect(exceptions, isNotEmpty);
expect(exceptions.first, isFlutterError); expect(exceptions.first, isInstanceOf<FlutterError>());
}); });
test('MainAxisSize.min inside tightly constrained', () { test('MainAxisSize.min inside tightly constrained', () {

View File

@ -148,7 +148,7 @@ void _testPaintingContextLayerReuse<L extends Layer>(_LayerTestPaintCallback pai
box.markNeedsPaint(); box.markNeedsPaint();
pumpFrame(phase: EnginePhase.paint); pumpFrame(phase: EnginePhase.paint);
expect(box.paintedLayers, hasLength(2)); expect(box.paintedLayers, hasLength(2));
expect(box.paintedLayers[0], isA<L>()); expect(box.paintedLayers[0], isInstanceOf<L>());
expect(box.paintedLayers[0], same(box.paintedLayers[1])); expect(box.paintedLayers[0], same(box.paintedLayers[1]));
} }

View File

@ -81,25 +81,21 @@ void main() {
}); });
test('RenderPhysicalModel compositing on non-Fuchsia', () { test('RenderPhysicalModel compositing on non-Fuchsia', () {
for (final TargetPlatform platform in TargetPlatform.values) { debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
if (platform == TargetPlatform.fuchsia) {
continue;
}
debugDefaultTargetPlatformOverride = platform;
final RenderPhysicalModel root = RenderPhysicalModel(color: const Color(0xffff00ff)); final RenderPhysicalModel root = RenderPhysicalModel(color: const Color(0xffff00ff));
layout(root, phase: EnginePhase.composite); layout(root, phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue); expect(root.needsCompositing, isTrue);
// Flutter now composites physical shapes on all platforms. // Flutter now composites physical shapes on all platforms.
root.elevation = 1.0; root.elevation = 1.0;
pumpFrame(phase: EnginePhase.composite); pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue); expect(root.needsCompositing, isTrue);
root.elevation = 0.0;
pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
root.elevation = 0.0;
pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
}
debugDefaultTargetPlatformOverride = null; debugDefaultTargetPlatformOverride = null;
}); });
@ -125,53 +121,44 @@ void main() {
}); });
group('RenderPhysicalShape', () { group('RenderPhysicalShape', () {
setUp(() {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
});
test('shape change triggers repaint', () { test('shape change triggers repaint', () {
for (final TargetPlatform platform in TargetPlatform.values) { final RenderPhysicalShape root = RenderPhysicalShape(
if (platform == TargetPlatform.fuchsia) { color: const Color(0xffff00ff),
continue; clipper: const ShapeBorderClipper(shape: CircleBorder()),
} );
debugDefaultTargetPlatformOverride = platform; layout(root, phase: EnginePhase.composite);
expect(root.debugNeedsPaint, isFalse);
final RenderPhysicalShape root = RenderPhysicalShape( // Same shape, no repaint.
color: const Color(0xffff00ff), root.clipper = const ShapeBorderClipper(shape: CircleBorder());
clipper: const ShapeBorderClipper(shape: CircleBorder()), expect(root.debugNeedsPaint, isFalse);
);
layout(root, phase: EnginePhase.composite);
expect(root.debugNeedsPaint, isFalse);
// Same shape, no repaint. // Different shape triggers repaint.
root.clipper = const ShapeBorderClipper(shape: CircleBorder()); root.clipper = const ShapeBorderClipper(shape: StadiumBorder());
expect(root.debugNeedsPaint, isFalse); expect(root.debugNeedsPaint, isTrue);
// Different shape triggers repaint.
root.clipper = const ShapeBorderClipper(shape: StadiumBorder());
expect(root.debugNeedsPaint, isTrue);
}
debugDefaultTargetPlatformOverride = null;
}); });
test('compositing on non-Fuchsia', () { test('compositing on non-Fuchsia', () {
for (final TargetPlatform platform in TargetPlatform.values) { final RenderPhysicalShape root = RenderPhysicalShape(
if (platform == TargetPlatform.fuchsia) { color: const Color(0xffff00ff),
continue; clipper: const ShapeBorderClipper(shape: CircleBorder()),
} );
debugDefaultTargetPlatformOverride = platform; layout(root, phase: EnginePhase.composite);
final RenderPhysicalShape root = RenderPhysicalShape( expect(root.needsCompositing, isTrue);
color: const Color(0xffff00ff),
clipper: const ShapeBorderClipper(shape: CircleBorder()),
);
layout(root, phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
// On non-Fuchsia platforms, we composite physical shape layers // On non-Fuchsia platforms, we composite physical shape layers
root.elevation = 1.0; root.elevation = 1.0;
pumpFrame(phase: EnginePhase.composite); pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue); expect(root.needsCompositing, isTrue);
root.elevation = 0.0;
pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
root.elevation = 0.0;
pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
}
debugDefaultTargetPlatformOverride = null; debugDefaultTargetPlatformOverride = null;
}); });
}); });
@ -467,6 +454,18 @@ void main() {
// transform -> clip // transform -> clip
_testFittedBoxWithClipRectLayer(); _testFittedBoxWithClipRectLayer();
}); });
test('RenderFractionalTranslation updates its semantics after its translation value is set', () {
final _TestSemanticsUpdateRenderFractionalTranslation box = _TestSemanticsUpdateRenderFractionalTranslation(
translation: const Offset(0.5, 0.5),
);
layout(box, constraints: BoxConstraints.tight(const Size(200.0, 200.0)));
expect(box.markNeedsSemanticsUpdateCallCount, 1);
box.translation = const Offset(0.4, 0.4);
expect(box.markNeedsSemanticsUpdateCallCount, 2);
box.translation = const Offset(0.3, 0.3);
expect(box.markNeedsSemanticsUpdateCallCount, 3);
});
} }
class _TestRectClipper extends CustomClipper<Rect> { class _TestRectClipper extends CustomClipper<Rect> {
@ -503,7 +502,7 @@ void _testLayerReuse<L extends Layer>(RenderBox renderObject) {
expect(renderObject.debugLayer, null); expect(renderObject.debugLayer, null);
layout(renderObject, phase: EnginePhase.paint, constraints: BoxConstraints.tight(const Size(10, 10))); layout(renderObject, phase: EnginePhase.paint, constraints: BoxConstraints.tight(const Size(10, 10)));
final Layer layer = renderObject.debugLayer; final Layer layer = renderObject.debugLayer;
expect(layer, isA<L>()); expect(layer, isInstanceOf<L>());
expect(layer, isNotNull); expect(layer, isNotNull);
// Mark for repaint otherwise pumpFrame is a noop. // Mark for repaint otherwise pumpFrame is a noop.
@ -523,3 +522,18 @@ class _TestPathClipper extends CustomClipper<Path> {
@override @override
bool shouldReclip(_TestPathClipper oldClipper) => false; bool shouldReclip(_TestPathClipper oldClipper) => false;
} }
class _TestSemanticsUpdateRenderFractionalTranslation extends RenderFractionalTranslation {
_TestSemanticsUpdateRenderFractionalTranslation({
@required Offset translation,
RenderBox child,
}) : super(translation: translation, child: child);
int markNeedsSemanticsUpdateCallCount = 0;
@override
void markNeedsSemanticsUpdate() {
markNeedsSemanticsUpdateCallCount++;
super.markNeedsSemanticsUpdate();
}
}

View File

@ -60,7 +60,7 @@ void main() {
child: repaintBoundary, child: repaintBoundary,
); );
layout(opacity, phase: EnginePhase.flushSemantics); layout(opacity, phase: EnginePhase.flushSemantics);
expect(repaintBoundary.debugLayer, isA<OffsetLayer>()); expect(repaintBoundary.debugLayer, isInstanceOf<OffsetLayer>());
}); });
test('Framework does not create an OffsetLayer for a non-repaint boundary', () { test('Framework does not create an OffsetLayer for a non-repaint boundary', () {
@ -80,7 +80,7 @@ void main() {
child: compositedBox, child: compositedBox,
); );
layout(opacity, phase: EnginePhase.flushSemantics); layout(opacity, phase: EnginePhase.flushSemantics);
expect(compositedBox.debugLayer, isA<OpacityLayer>()); expect(compositedBox.debugLayer, isInstanceOf<OpacityLayer>());
}); });
test('Framework ensures repaint boundary layer is not overwritten', () { test('Framework ensures repaint boundary layer is not overwritten', () {

View File

@ -1145,8 +1145,10 @@ void main() {
); );
}); });
testWidgets('Handles infinite constraints when TargetPlatform is iOS or macOS', (WidgetTester tester) async { testWidgets('Handles infinite constraints when TargetPlatform is iOS', (WidgetTester tester) async {
// regression test for https://github.com/flutter/flutter/issues/45866 // regression test for https://github.com/flutter/flutter/issues/45866
final TargetPlatform oldTargetPlatform = debugDefaultTargetPlatformOverride;
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -1175,5 +1177,6 @@ void main() {
expect(find.text('b'), findsOneWidget); expect(find.text('b'), findsOneWidget);
await tester.drag(find.text('b'), const Offset(0, 200)); await tester.drag(find.text('b'), const Offset(0, 200));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = oldTargetPlatform;
});
} }

View File

@ -33,7 +33,7 @@ void main() {
} }
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 3); expect(error.diagnostics.length, 3);
expect(error.diagnostics.last, isA<DiagnosticsProperty<Ticker>>()); expect(error.diagnostics.last, isInstanceOf<DiagnosticsProperty<Ticker>>());
expect( expect(
error.toStringDeep(), error.toStringDeep(),
startsWith( startsWith(

View File

@ -68,7 +68,7 @@ void main() {
} }
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 2); expect(error.diagnostics.length, 2);
expect(error.diagnostics.last, isA<IntProperty>()); expect(error.diagnostics.last, isInstanceOf<IntProperty>());
expect( expect(
error.toStringDeep(), error.toStringDeep(),
'FlutterError\n' 'FlutterError\n'

View File

@ -70,7 +70,7 @@ void main() {
} }
}, },
); );
expect(channel.invokeMethod<List<String>>('sayHello', 'hello'), throwsA(isCastError)); expect(channel.invokeMethod<List<String>>('sayHello', 'hello'), throwsA(isInstanceOf<CastError>()));
expect(await channel.invokeListMethod<String>('sayHello', 'hello'), <String>['hello', 'world']); expect(await channel.invokeListMethod<String>('sayHello', 'hello'), <String>['hello', 'world']);
}); });
@ -102,7 +102,7 @@ void main() {
} }
}, },
); );
expect(channel.invokeMethod<Map<String, String>>('sayHello', 'hello'), throwsA(isCastError)); expect(channel.invokeMethod<Map<String, String>>('sayHello', 'hello'), throwsA(isInstanceOf<CastError>()));
expect(await channel.invokeMapMethod<String, String>('sayHello', 'hello'), <String, String>{'hello': 'world'}); expect(await channel.invokeMapMethod<String, String>('sayHello', 'hello'), <String, String>{'hello': 'world'});
}); });
@ -292,7 +292,7 @@ void main() {
await Future<void>.delayed(Duration.zero); await Future<void>.delayed(Duration.zero);
expect(events, isEmpty); expect(events, isEmpty);
expect(errors, hasLength(1)); expect(errors, hasLength(1));
expect(errors[0], isA<PlatformException>()); expect(errors[0], isInstanceOf<PlatformException>());
final PlatformException error = errors[0] as PlatformException; final PlatformException error = errors[0] as PlatformException;
expect(error.code, '404'); expect(error.code, '404');
expect(error.message, 'Not Found.'); expect(error.message, 'Not Found.');

View File

@ -27,7 +27,7 @@ void main() {
layoutDirection: TextDirection.ltr, layoutDirection: TextDirection.ltr,
).setSize(const Size(100.0, 100.0)); ).setSize(const Size(100.0, 100.0));
}, },
throwsA(isA<PlatformException>()), throwsA(isInstanceOf<PlatformException>()),
); );
}); });
@ -55,7 +55,7 @@ void main() {
expect( expect(
() => PlatformViewsService.initAndroidView( () => PlatformViewsService.initAndroidView(
id: 0, viewType: 'web', layoutDirection: TextDirection.ltr).setSize(const Size(100.0, 100.0)), id: 0, viewType: 'web', layoutDirection: TextDirection.ltr).setSize(const Size(100.0, 100.0)),
throwsA(isA<PlatformException>())); throwsA(isInstanceOf<PlatformException>()));
}); });
test('dispose Android view', () async { test('dispose Android view', () async {
@ -170,7 +170,7 @@ void main() {
layoutDirection: TextDirection.ltr, layoutDirection: TextDirection.ltr,
); );
}, },
throwsA(isA<PlatformException>()), throwsA(isInstanceOf<PlatformException>()),
); );
}); });
@ -199,7 +199,7 @@ void main() {
expect( expect(
() => PlatformViewsService.initUiKitView( () => PlatformViewsService.initUiKitView(
id: 0, viewType: 'web', layoutDirection: TextDirection.ltr), id: 0, viewType: 'web', layoutDirection: TextDirection.ltr),
throwsA(isA<PlatformException>()), throwsA(isInstanceOf<PlatformException>()),
); );
}); });
@ -228,7 +228,7 @@ void main() {
() async { () async {
await viewController.dispose(); await viewController.dispose();
}, },
throwsA(isA<PlatformException>()), throwsA(isInstanceOf<PlatformException>()),
); );
}); });
}); });

View File

@ -344,7 +344,7 @@ void main() {
'https://api.flutter.dev/flutter/widgets/AnimatedListState-class.html\n' 'https://api.flutter.dev/flutter/widgets/AnimatedListState-class.html\n'
), ),
); );
expect(error.diagnostics[3], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[3], isInstanceOf<DiagnosticsProperty<Element>>());
expect( expect(
error.toStringDeep(), error.toStringDeep(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(

View File

@ -262,7 +262,7 @@ void main() {
expect(find.byType(Column), findsOneWidget); expect(find.byType(Column), findsOneWidget);
for (final Widget child in foundChildren) { for (final Widget child in foundChildren) {
expect(child, isA<KeyedSubtree>()); expect(child, isInstanceOf<KeyedSubtree>());
} }
await tester.pumpWidget( await tester.pumpWidget(
@ -280,7 +280,7 @@ void main() {
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
for (final Widget child in foundChildren) { for (final Widget child in foundChildren) {
expect(child, isA<KeyedSubtree>()); expect(child, isInstanceOf<KeyedSubtree>());
expect( expect(
find.descendant(of: find.byWidget(child), matching: find.byType(SizeTransition)), find.descendant(of: find.byWidget(child), matching: find.byType(SizeTransition)),
findsOneWidget, findsOneWidget,
@ -430,7 +430,7 @@ void main() {
expect(foundChildren.length, equals(3)); expect(foundChildren.length, equals(3));
for (final Widget child in foundChildren) { for (final Widget child in foundChildren) {
expect(child, isA<KeyedSubtree>()); expect(child, isInstanceOf<KeyedSubtree>());
expect( expect(
find.descendant(of: find.byWidget(child), matching: find.byType(FadeTransition)), find.descendant(of: find.byWidget(child), matching: find.byType(FadeTransition)),
findsOneWidget, findsOneWidget,
@ -460,7 +460,7 @@ void main() {
expect(foundChildren.length, equals(3)); expect(foundChildren.length, equals(3));
for (final Widget child in foundChildren) { for (final Widget child in foundChildren) {
expect(child, isA<KeyedSubtree>()); expect(child, isInstanceOf<KeyedSubtree>());
expect( expect(
find.descendant(of: find.byWidget(child), matching: find.byType(ScaleTransition)), find.descendant(of: find.byWidget(child), matching: find.byType(ScaleTransition)),
findsOneWidget, findsOneWidget,

View File

@ -20,7 +20,7 @@ void main() {
color: const Color(0xFF112233), color: const Color(0xFF112233),
onGenerateRoute: generateRoute, onGenerateRoute: generateRoute,
)); ));
expect(key.currentState, isA<NavigatorState>()); expect(key.currentState, isInstanceOf<NavigatorState>());
await tester.pumpWidget(WidgetsApp( await tester.pumpWidget(WidgetsApp(
color: const Color(0xFF112233), color: const Color(0xFF112233),
onGenerateRoute: generateRoute, onGenerateRoute: generateRoute,
@ -31,6 +31,6 @@ void main() {
color: const Color(0xFF112233), color: const Color(0xFF112233),
onGenerateRoute: generateRoute, onGenerateRoute: generateRoute,
)); ));
expect(key.currentState, isA<NavigatorState>()); expect(key.currentState, isInstanceOf<NavigatorState>());
}); });
} }

View File

@ -145,6 +145,69 @@ void main() {
await tester.tap(find.byKey(key1)); await tester.tap(find.byKey(key1));
expect(_pointerDown, isTrue); expect(_pointerDown, isTrue);
}); });
testWidgets('semantics bounds are updated', (WidgetTester tester) async {
final GlobalKey fractionalTranslationKey = GlobalKey();
final GlobalKey textKey = GlobalKey();
Offset offset = const Offset(0.4, 0.4);
await tester.pumpWidget(
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Semantics(
explicitChildNodes: true,
child: FractionalTranslation(
key: fractionalTranslationKey,
translation: offset,
transformHitTests: true,
child: GestureDetector(
onTap: () {
setState(() {
offset = const Offset(0.8, 0.8);
});
},
child: SizedBox(
width: 100.0,
height: 100.0,
child: Text(
'foo',
key: textKey,
),
),
),
),
),
),
);
},
)
);
expect(
tester.getSemantics(find.byKey(textKey)).transform,
Matrix4(
3.0, 0.0, 0.0, 0.0,
0.0, 3.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
1170.0, 870.0, 0.0, 1.0,
),
);
await tester.tap(find.byKey(fractionalTranslationKey));
await tester.pump();
expect(
tester.getSemantics(find.byKey(textKey)).transform,
Matrix4(
3.0, 0.0, 0.0, 0.0,
0.0, 3.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
1290.0, 990.0, 0.0, 1.0,
),
);
});
}); });
group('Row', () { group('Row', () {

View File

@ -74,7 +74,7 @@ void main() {
} finally { } finally {
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 4); expect(error.diagnostics.length, 4);
expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[2], isInstanceOf<DiagnosticsProperty<Element>>());
expect( expect(
error.toStringDeep(), error.toStringDeep(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
@ -106,7 +106,7 @@ void main() {
} finally { } finally {
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 5); expect(error.diagnostics.length, 5);
expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[2], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.diagnostics.last.level, DiagnosticLevel.hint); expect(error.diagnostics.last.level, DiagnosticLevel.hint);
expect( expect(
error.diagnostics.last.toStringDeep(), error.diagnostics.last.toStringDeep(),
@ -147,7 +147,7 @@ void main() {
} finally { } finally {
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 4); expect(error.diagnostics.length, 4);
expect(error.diagnostics[1], isA<DiagnosticsProperty<Widget>>()); expect(error.diagnostics[1], isInstanceOf<DiagnosticsProperty<Widget>>());
expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty); expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty);
expect( expect(
error.diagnostics[1].toStringDeep(), error.diagnostics[1].toStringDeep(),
@ -190,7 +190,7 @@ void main() {
} finally { } finally {
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 3); expect(error.diagnostics.length, 3);
expect(error.diagnostics[1], isA<DiagnosticsProperty<Widget>>()); expect(error.diagnostics[1], isInstanceOf<DiagnosticsProperty<Widget>>());
expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty); expect(error.diagnostics[1].style, DiagnosticsTreeStyle.errorProperty);
expect( expect(
error.diagnostics[1].toStringDeep(), error.diagnostics[1].toStringDeep(),

View File

@ -105,7 +105,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget); expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), findsOneWidget); expect(find.text('Item 21'), findsOneWidget);
expect(find.text('Item 31'), findsOneWidget); expect(find.text('Item 31'), findsOneWidget);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
testWidgets('Can be dragged down when not full height', (WidgetTester tester) async { testWidgets('Can be dragged down when not full height', (WidgetTester tester) async {
await tester.pumpWidget(_boilerplate(null)); await tester.pumpWidget(_boilerplate(null));
@ -118,7 +118,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget); expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), findsNothing); expect(find.text('Item 21'), findsNothing);
expect(find.text('Item 36'), findsNothing); expect(find.text('Item 36'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
testWidgets('Can be dragged down when list is shorter than full height', (WidgetTester tester) async { testWidgets('Can be dragged down when list is shorter than full height', (WidgetTester tester) async {
await tester.pumpWidget(_boilerplate(null, itemCount: 30, initialChildSize: .25)); await tester.pumpWidget(_boilerplate(null, itemCount: 30, initialChildSize: .25));
@ -135,7 +135,7 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('Item 1').hitTestable(), findsOneWidget); expect(find.text('Item 1').hitTestable(), findsOneWidget);
expect(find.text('Item 29').hitTestable(), findsNothing); expect(find.text('Item 29').hitTestable(), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
testWidgets('Can be dragged up and cover its container and scroll in single motion, and then dragged back down', (WidgetTester tester) async { testWidgets('Can be dragged up and cover its container and scroll in single motion, and then dragged back down', (WidgetTester tester) async {
int taps = 0; int taps = 0;
@ -164,7 +164,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget); expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 18'), findsOneWidget); expect(find.text('Item 18'), findsOneWidget);
expect(find.text('Item 36'), findsNothing); expect(find.text('Item 36'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
testWidgets('Can be flung up gently', (WidgetTester tester) async { testWidgets('Can be flung up gently', (WidgetTester tester) async {
int taps = 0; int taps = 0;
@ -187,7 +187,7 @@ void main() {
expect(find.text('Item 21'), findsOneWidget); expect(find.text('Item 21'), findsOneWidget);
expect(find.text('Item 36'), findsOneWidget); expect(find.text('Item 36'), findsOneWidget);
expect(find.text('Item 70'), findsNothing); expect(find.text('Item 70'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
testWidgets('Can be flung up', (WidgetTester tester) async { testWidgets('Can be flung up', (WidgetTester tester) async {
int taps = 0; int taps = 0;
@ -208,7 +208,7 @@ void main() {
expect(find.text('Item 1'), findsNothing); expect(find.text('Item 1'), findsNothing);
expect(find.text('Item 21'), findsNothing); expect(find.text('Item 21'), findsNothing);
expect(find.text('Item 70'), findsOneWidget); expect(find.text('Item 70'), findsOneWidget);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
testWidgets('Can be flung down when not full height', (WidgetTester tester) async { testWidgets('Can be flung down when not full height', (WidgetTester tester) async {
await tester.pumpWidget(_boilerplate(null)); await tester.pumpWidget(_boilerplate(null));
@ -221,7 +221,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget); expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), findsNothing); expect(find.text('Item 21'), findsNothing);
expect(find.text('Item 36'), findsNothing); expect(find.text('Item 36'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
testWidgets('Can be flung up and then back down', (WidgetTester tester) async { testWidgets('Can be flung up and then back down', (WidgetTester tester) async {
int taps = 0; int taps = 0;
@ -260,7 +260,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget); expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), findsNothing); expect(find.text('Item 21'), findsNothing);
expect(find.text('Item 70'), findsNothing); expect(find.text('Item 70'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all()); }, skip: isBrowser);
debugDefaultTargetPlatformOverride = null; debugDefaultTargetPlatformOverride = null;
}); });

View File

@ -304,7 +304,9 @@ void main() {
expect(buttonPressed, equals(true)); expect(buttonPressed, equals(true));
}); });
testWidgets('Dismissible ModalBarrier includes button in semantic tree', (WidgetTester tester) async { testWidgets('Dismissible ModalBarrier includes button in semantic tree on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
@ -329,7 +331,9 @@ void main() {
expect(semantics, includesNodeWith(label: 'Dismiss')); expect(semantics, includesNodeWith(label: 'Dismiss'));
semantics.dispose(); semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('Dismissible ModalBarrier is hidden on Android (back button is used to dismiss)', (WidgetTester tester) async { testWidgets('Dismissible ModalBarrier is hidden on Android (back button is used to dismiss)', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
@ -357,7 +361,7 @@ void main() {
expect(semantics, isNot(includesNodeWith(label: 'Dismiss'))); expect(semantics, isNot(includesNodeWith(label: 'Dismiss')));
semantics.dispose(); semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android })); });
testWidgets('Drawer contains route semantics flags', (WidgetTester tester) async { testWidgets('Drawer contains route semantics flags', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);

View File

@ -145,9 +145,10 @@ void main() {
); );
}); });
testWidgets('Cursor animates', (WidgetTester tester) async { testWidgets('Cursor animates on iOS', (WidgetTester tester) async {
const Widget widget = MaterialApp( final Widget widget = MaterialApp(
home: Material( theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField( child: TextField(
maxLines: 3, maxLines: 3,
), ),
@ -199,7 +200,7 @@ void main() {
// Cursor starts coming back. // Cursor starts coming back.
expect(renderEditable.cursorColor.alpha, 79); expect(renderEditable.cursorColor.alpha, 79);
expect(renderEditable, paints..rrect(color: const Color(0x4f2196f3))); expect(renderEditable, paints..rrect(color: const Color(0x4f2196f3)));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Cursor does not animate on Android', (WidgetTester tester) async { testWidgets('Cursor does not animate on Android', (WidgetTester tester) async {
const Widget widget = MaterialApp( const Widget widget = MaterialApp(
@ -240,10 +241,11 @@ void main() {
expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0));
}); });
testWidgets('Cursor does not animates when debugDeterministicCursor is set', (WidgetTester tester) async { testWidgets('Cursor does not animates on iOS when debugDeterministicCursor is set', (WidgetTester tester) async {
EditableText.debugDeterministicCursor = true; EditableText.debugDeterministicCursor = true;
const Widget widget = MaterialApp( final Widget widget = MaterialApp(
home: Material( theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField( child: TextField(
maxLines: 3, maxLines: 3,
), ),
@ -275,7 +277,7 @@ void main() {
expect(renderEditable, paints..rrect(color: const Color(0xff2196f3))); expect(renderEditable, paints..rrect(color: const Color(0xff2196f3)));
EditableText.debugDeterministicCursor = false; EditableText.debugDeterministicCursor = false;
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Cursor does not animate on Android when debugDeterministicCursor is set', (WidgetTester tester) async { testWidgets('Cursor does not animate on Android when debugDeterministicCursor is set', (WidgetTester tester) async {
EditableText.debugDeterministicCursor = true; EditableText.debugDeterministicCursor = true;
@ -344,9 +346,10 @@ void main() {
expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0));
}); });
testWidgets('Cursor radius is 2.0', (WidgetTester tester) async { testWidgets('Cursor radius is 2.0 on iOS', (WidgetTester tester) async {
const Widget widget = MaterialApp( final Widget widget = MaterialApp(
home: Material( theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField( child: TextField(
maxLines: 3, maxLines: 3,
), ),
@ -358,7 +361,7 @@ void main() {
final RenderEditable renderEditable = editableTextState.renderEditable; final RenderEditable renderEditable = editableTextState.renderEditable;
expect(renderEditable.cursorRadius, const Radius.circular(2.0)); expect(renderEditable.cursorRadius, const Radius.circular(2.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Cursor gets placed correctly after going out of bounds', (WidgetTester tester) async { testWidgets('Cursor gets placed correctly after going out of bounds', (WidgetTester tester) async {
const String text = 'hello world this is fun and cool and awesome!'; const String text = 'hello world this is fun and cool and awesome!';
@ -642,7 +645,9 @@ void main() {
expect(controller.selection.baseOffset, text.length); expect(controller.selection.baseOffset, text.length);
}, skip: isBrowser); }, skip: isBrowser);
testWidgets('Floating cursor is painted', (WidgetTester tester) async { testWidgets('Floating cursor is painted on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
const TextStyle textStyle = TextStyle(); const TextStyle textStyle = TextStyle();
const String text = 'hello world this is fun and cool and awesome!'; const String text = 'hello world this is fun and cool and awesome!';
@ -651,6 +656,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Padding( home: Padding(
padding: const EdgeInsets.only(top: 0.25), padding: const EdgeInsets.only(top: 0.25),
child: Material( child: Material(
@ -725,13 +731,16 @@ void main() {
editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.End)); editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.End));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
debugDefaultTargetPlatformOverride = null; debugDefaultTargetPlatformOverride = null;
}, skip: isBrowser, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); }, skip: isBrowser);
testWidgets('cursor layout', (WidgetTester tester) async { testWidgets('cursor layout iOS', (WidgetTester tester) async {
final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>(); final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>();
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
String changedValue; String changedValue;
final Widget widget = MaterialApp( final Widget widget = MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: RepaintBoundary( home: RepaintBoundary(
key: const ValueKey<int>(1), key: const ValueKey<int>(1),
child: Column( child: Column(
@ -742,7 +751,7 @@ void main() {
key: editableTextKey, key: editableTextKey,
controller: TextEditingController(), controller: TextEditingController(),
focusNode: FocusNode(), focusNode: FocusNode(),
style: Typography(platform: debugDefaultTargetPlatformOverride).black.subhead, style: Typography(platform: TargetPlatform.iOS).black.subhead,
cursorColor: Colors.blue, cursorColor: Colors.blue,
selectionControls: materialTextSelectionControls, selectionControls: materialTextSelectionControls,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
@ -784,5 +793,6 @@ void main() {
find.byKey(const ValueKey<int>(1)), find.byKey(const ValueKey<int>(1)),
matchesGoldenFile('editable_text_test.2.png'), matchesGoldenFile('editable_text_test.2.png'),
); );
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
} }

View File

@ -3757,7 +3757,9 @@ void main() {
}); });
// Regression test for https://github.com/flutter/flutter/issues/31287 // Regression test for https://github.com/flutter/flutter/issues/31287
testWidgets('text selection handle visibility', (WidgetTester tester) async { testWidgets('iOS text selection handle visibility', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
// Text with two separate words to select. // Text with two separate words to select.
const String testText = 'XXXXX XXXXX'; const String testText = 'XXXXX XXXXX';
final TextEditingController controller = TextEditingController(text: testText); final TextEditingController controller = TextEditingController(text: testText);
@ -3772,7 +3774,7 @@ void main() {
showSelectionHandles: true, showSelectionHandles: true,
controller: controller, controller: controller,
focusNode: FocusNode(), focusNode: FocusNode(),
style: Typography(platform: debugDefaultTargetPlatformOverride).black.subhead, style: Typography(platform: TargetPlatform.iOS).black.subhead,
cursorColor: Colors.blue, cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey, backgroundCursorColor: Colors.grey,
selectionControls: cupertinoTextSelectionControls, selectionControls: cupertinoTextSelectionControls,
@ -3922,7 +3924,9 @@ void main() {
// at all. Again, both handles should be invisible. // at all. Again, both handles should be invisible.
scrollable.controller.jumpTo(0); scrollable.controller.jumpTo(0);
await verifyVisibility(HandlePositionInViewport.rightEdge, false, HandlePositionInViewport.rightEdge, false); await verifyVisibility(HandlePositionInViewport.rightEdge, false, HandlePositionInViewport.rightEdge, false);
}, skip: isBrowser, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
}, skip: isBrowser);
testWidgets('scrolling doesn\'t bounce', (WidgetTester tester) async { testWidgets('scrolling doesn\'t bounce', (WidgetTester tester) async {
// 3 lines of text, where the last line overflows and requires scrolling. // 3 lines of text, where the last line overflows and requires scrolling.

View File

@ -150,9 +150,9 @@ void main() {
ContainerLayer layer = RendererBinding.instance.renderView.debugLayer; ContainerLayer layer = RendererBinding.instance.renderView.debugLayer;
while (layer != null && layer is! OpacityLayer) while (layer != null && layer is! OpacityLayer)
layer = layer.firstChild as ContainerLayer; layer = layer.firstChild as ContainerLayer;
expect(layer, isA<OpacityLayer>()); expect(layer, isInstanceOf<OpacityLayer>());
final OpacityLayer opacityLayer = layer as OpacityLayer; final OpacityLayer opacityLayer = layer as OpacityLayer;
expect(opacityLayer.alpha, equals(opacity * 255)); expect(opacityLayer.alpha, equals(opacity * 255));
expect(layer.firstChild, isA<TransformLayer>()); expect(layer.firstChild, isInstanceOf<TransformLayer>());
}); });
} }

View File

@ -543,7 +543,7 @@ Future<void> main() async {
final FlutterError error = exception as FlutterError; final FlutterError error = exception as FlutterError;
expect(error.diagnostics.length, 3); expect(error.diagnostics.length, 3);
final DiagnosticsNode last = error.diagnostics.last; final DiagnosticsNode last = error.diagnostics.last;
expect(last, isA<DiagnosticsProperty<StatefulElement>>()); expect(last, isInstanceOf<DiagnosticsProperty<StatefulElement>>());
expect( expect(
last.toStringDeep(), last.toStringDeep(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
@ -1614,7 +1614,10 @@ Future<void> main() async {
testWidgets('Heroes do not transition on back gestures by default', (WidgetTester tester) async { testWidgets('Heroes do not transition on back gestures by default', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
routes: routes, theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes,
)); ));
expect(find.byKey(firstKey), isOnstage); expect(find.byKey(firstKey), isOnstage);
@ -1649,11 +1652,14 @@ Future<void> main() async {
expect(find.byKey(firstKey), isInCard); expect(find.byKey(firstKey), isInCard);
expect(find.byKey(secondKey), isOnstage); expect(find.byKey(secondKey), isOnstage);
expect(find.byKey(secondKey), isInCard); expect(find.byKey(secondKey), isInCard);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Heroes can transition on gesture in one frame', (WidgetTester tester) async { testWidgets('Heroes can transition on gesture in one frame', (WidgetTester tester) async {
transitionFromUserGestures = true; transitionFromUserGestures = true;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes, routes: routes,
)); ));
@ -1692,11 +1698,14 @@ Future<void> main() async {
expect(find.byKey(firstKey), isOnstage); expect(find.byKey(firstKey), isOnstage);
expect(find.byKey(firstKey), isInCard); expect(find.byKey(firstKey), isInCard);
expect(find.byKey(secondKey), findsNothing); expect(find.byKey(secondKey), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Heroes animate should hide destination hero and display original hero in case of dismissed', (WidgetTester tester) async { testWidgets('Heroes animate should hide destination hero and display original hero in case of dismissed', (WidgetTester tester) async {
transitionFromUserGestures = true; transitionFromUserGestures = true;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes, routes: routes,
)); ));
@ -1728,7 +1737,7 @@ Future<void> main() async {
expect(find.byKey(firstKey), findsNothing); expect(find.byKey(firstKey), findsNothing);
expect(find.byKey(secondKey), isOnstage); expect(find.byKey(secondKey), isOnstage);
expect(find.byKey(secondKey), isInCard); expect(find.byKey(secondKey), isInCard);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Handles transitions when a non-default initial route is set', (WidgetTester tester) async { testWidgets('Handles transitions when a non-default initial route is set', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
@ -2289,6 +2298,9 @@ Future<void> main() async {
testWidgets('Remove user gesture driven flights when the gesture is invalid', (WidgetTester tester) async { testWidgets('Remove user gesture driven flights when the gesture is invalid', (WidgetTester tester) async {
transitionFromUserGestures = true; transitionFromUserGestures = true;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes, routes: routes,
)); ));
@ -2312,7 +2324,7 @@ Future<void> main() async {
// The simple route should still be on top. // The simple route should still be on top.
expect(find.byKey(simpleKey), findsOneWidget); expect(find.byKey(simpleKey), findsOneWidget);
expect(tester.takeException(), isNull); expect(tester.takeException(), isNull);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
// Regression test for https://github.com/flutter/flutter/issues/40239. // Regression test for https://github.com/flutter/flutter/issues/40239.
testWidgets( testWidgets(

View File

@ -1101,14 +1101,14 @@ void main() {
expect(find.byType(Center), findsOneWidget); expect(find.byType(Center), findsOneWidget);
expect(find.byType(Padding), findsOneWidget); expect(find.byType(Padding), findsOneWidget);
expect(find.byType(RawImage), findsOneWidget); expect(find.byType(RawImage), findsOneWidget);
expect(tester.widget<Padding>(find.byType(Padding)).child, isA<RawImage>()); expect(tester.widget<Padding>(find.byType(Padding)).child, isInstanceOf<RawImage>());
streamCompleter.setData(chunkEvent: const ImageChunkEvent(cumulativeBytesLoaded: 10, expectedTotalBytes: 100)); streamCompleter.setData(chunkEvent: const ImageChunkEvent(cumulativeBytesLoaded: 10, expectedTotalBytes: 100));
await tester.pump(); await tester.pump();
expect(find.byType(Center), findsOneWidget); expect(find.byType(Center), findsOneWidget);
expect(find.byType(Padding), findsOneWidget); expect(find.byType(Padding), findsOneWidget);
expect(find.byType(RawImage), findsOneWidget); expect(find.byType(RawImage), findsOneWidget);
expect(tester.widget<Center>(find.byType(Center)).child, isA<Padding>()); expect(tester.widget<Center>(find.byType(Center)).child, isInstanceOf<Padding>());
expect(tester.widget<Padding>(find.byType(Padding)).child, isA<RawImage>()); expect(tester.widget<Padding>(find.byType(Padding)).child, isInstanceOf<RawImage>());
}, skip: isBrowser); }, skip: isBrowser);
testWidgets('Image state handles loadingBuilder update from null to non-null', (WidgetTester tester) async { testWidgets('Image state handles loadingBuilder update from null to non-null', (WidgetTester tester) async {

View File

@ -1203,6 +1203,8 @@ void main() {
}); });
testWidgets('high fling velocities lands exactly on items', (WidgetTester tester) async { testWidgets('high fling velocities lands exactly on items', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final FixedExtentScrollController controller = FixedExtentScrollController(initialItem: 40); final FixedExtentScrollController controller = FixedExtentScrollController(initialItem: 40);
final List<double> scrolledPositions = <double>[]; final List<double> scrolledPositions = <double>[];
@ -1250,7 +1252,9 @@ void main() {
expect(controller.selectedItem, 49); expect(controller.selectedItem, 49);
// More importantly, lands tightly on 49. // More importantly, lands tightly on 49.
expect(scrolledPositions.last, moreOrLessEquals(49 * 100.0, epsilon: 0.3)); expect(scrolledPositions.last, moreOrLessEquals(49 * 100.0, epsilon: 0.3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
}); });
testWidgets('ListWheelScrollView getOffsetToReveal', (WidgetTester tester) async { testWidgets('ListWheelScrollView getOffsetToReveal', (WidgetTester tester) async {

View File

@ -25,7 +25,7 @@ void main() {
expect(exception ,isFlutterError); expect(exception ,isFlutterError);
final FlutterError error = exception as FlutterError; final FlutterError error = exception as FlutterError;
expect(error.diagnostics.length, 3); expect(error.diagnostics.length, 3);
expect(error.diagnostics.last, isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics.last, isInstanceOf<DiagnosticsProperty<Element>>());
expect( expect(
error.toStringDeep(), error.toStringDeep(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(

View File

@ -340,6 +340,8 @@ void main() {
}); });
testWidgets('Dismissible ModalBarrier includes button in semantic tree on iOS', (WidgetTester tester) async { testWidgets('Dismissible ModalBarrier includes button in semantic tree on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(const Directionality( await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -362,7 +364,8 @@ void main() {
expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); expect(semantics, hasSemantics(expectedSemantics, ignoreId: true));
semantics.dispose(); semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
testWidgets('Dismissible ModalBarrier is hidden on Android (back button is used to dismiss)', (WidgetTester tester) async { testWidgets('Dismissible ModalBarrier is hidden on Android (back button is used to dismiss)', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);

View File

@ -13,12 +13,12 @@ void checkTree(WidgetTester tester, List<BoxDecoration> expectedDecorations) {
(Element element) => element is MultiChildRenderObjectElement (Element element) => element is MultiChildRenderObjectElement
)); ));
expect(element, isNotNull); expect(element, isNotNull);
expect(element.renderObject, isA<RenderStack>()); expect(element.renderObject is RenderStack, isTrue);
final RenderStack renderObject = element.renderObject as RenderStack; final RenderStack renderObject = element.renderObject as RenderStack;
try { try {
RenderObject child = renderObject.firstChild; RenderObject child = renderObject.firstChild;
for (final BoxDecoration decoration in expectedDecorations) { for (final BoxDecoration decoration in expectedDecorations) {
expect(child, isA<RenderDecoratedBox>()); expect(child is RenderDecoratedBox, isTrue);
final RenderDecoratedBox decoratedBox = child as RenderDecoratedBox; final RenderDecoratedBox decoratedBox = child as RenderDecoratedBox;
expect(decoratedBox.decoration, equals(decoration)); expect(decoratedBox.decoration, equals(decoration));
final StackParentData decoratedBoxParentData = decoratedBox.parentData as StackParentData; final StackParentData decoratedBoxParentData = decoratedBox.parentData as StackParentData;

View File

@ -155,7 +155,7 @@ void main() {
); );
await tester.pumpWidget(widget); await tester.pumpWidget(widget);
await tester.tap(find.byKey(targetKey)); await tester.tap(find.byKey(targetKey));
expect(exception, isFlutterError); expect(exception, isInstanceOf<FlutterError>());
expect('$exception', startsWith('Navigator operation requested with a context')); expect('$exception', startsWith('Navigator operation requested with a context'));
}); });
@ -1027,7 +1027,7 @@ void main() {
); );
final dynamic exception = tester.takeException(); final dynamic exception = tester.takeException();
expect(exception, isA<String>()); expect(exception is String, isTrue);
expect(exception.startsWith('Could not navigate to initial route.'), isTrue); expect(exception.startsWith('Could not navigate to initial route.'), isTrue);
// Only the root route should've been pushed. // Only the root route should've been pushed.
@ -1048,7 +1048,7 @@ void main() {
expect(exception, isFlutterError); expect(exception, isFlutterError);
final FlutterError error = exception as FlutterError; final FlutterError error = exception as FlutterError;
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.last, isA<DiagnosticsProperty<NavigatorState>>()); expect(error.diagnostics.last, isInstanceOf<DiagnosticsProperty<NavigatorState>>());
expect( expect(
error.toStringDeep(), error.toStringDeep(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
@ -1075,7 +1075,7 @@ void main() {
expect(exception, isFlutterError); expect(exception, isFlutterError);
final FlutterError error = exception as FlutterError; final FlutterError error = exception as FlutterError;
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.last, isA<DiagnosticsProperty<NavigatorState>>()); expect(error.diagnostics.last, isInstanceOf<DiagnosticsProperty<NavigatorState>>());
expect( expect(
error.toStringDeep(), error.toStringDeep(),
equalsIgnoringHashCodes( equalsIgnoringHashCodes(

View File

@ -113,6 +113,7 @@ Widget buildTest({ ScrollController controller, String title = 'TTTTTTTT' }) {
void main() { void main() {
testWidgets('NestedScrollView overscroll and release and hold', (WidgetTester tester) async { testWidgets('NestedScrollView overscroll and release and hold', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(buildTest()); await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget); expect(find.text('aaa2'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 250)); await tester.pump(const Duration(milliseconds: 250));
@ -127,8 +128,10 @@ void main() {
// TODO(ianh): Once we improve how we handle scrolling down from overscroll, // TODO(ianh): Once we improve how we handle scrolling down from overscroll,
// the following expectation should switch to 200.0. // the following expectation should switch to 200.0.
expect(tester.renderObject<RenderBox>(find.byType(AppBar)).size.height, 120.0); expect(tester.renderObject<RenderBox>(find.byType(AppBar)).size.height, 120.0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
testWidgets('NestedScrollView overscroll and release and hold', (WidgetTester tester) async { testWidgets('NestedScrollView overscroll and release and hold', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(buildTest()); await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget); expect(find.text('aaa2'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 250)); await tester.pump(const Duration(milliseconds: 250));
@ -146,8 +149,10 @@ void main() {
await tester.pump(const Duration(milliseconds: 10)); await tester.pump(const Duration(milliseconds: 10));
expect(find.text('aaa2'), findsNothing); expect(find.text('aaa2'), findsNothing);
await tester.pump(const Duration(milliseconds: 1000)); await tester.pump(const Duration(milliseconds: 1000));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
testWidgets('NestedScrollView overscroll and release', (WidgetTester tester) async { testWidgets('NestedScrollView overscroll and release', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(buildTest()); await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget); expect(find.text('aaa2'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 500));
@ -159,10 +164,8 @@ void main() {
await gesture1.up(); await gesture1.up();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('aaa2'), findsOneWidget); expect(find.text('aaa2'), findsOneWidget);
}, debugDefaultTargetPlatformOverride = null;
skip: true, // https://github.com/flutter/flutter/issues/9040 }, skip: true); // https://github.com/flutter/flutter/issues/9040
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('NestedScrollView', (WidgetTester tester) async { testWidgets('NestedScrollView', (WidgetTester tester) async {
await tester.pumpWidget(buildTest()); await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget); expect(find.text('aaa2'), findsOneWidget);
@ -607,11 +610,12 @@ void main() {
debugDisableShadows = true; debugDisableShadows = true;
}); });
testWidgets('NestedScrollView and bouncing', (WidgetTester tester) async { testWidgets('NestedScrollView and iOS bouncing', (WidgetTester tester) async {
// This verifies that overscroll bouncing works correctly on iOS. For // This verifies that overscroll bouncing works correctly on iOS. For
// example, this checks that if you pull to overscroll, friction is applied; // example, this checks that if you pull to overscroll, friction is applied;
// it also makes sure that if you scroll back the other way, the scroll // it also makes sure that if you scroll back the other way, the scroll
// positions of the inner and outer list don't have a discontinuity. // positions of the inner and outer list don't have a discontinuity.
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
const Key key1 = ValueKey<int>(1); const Key key1 = ValueKey<int>(1);
const Key key2 = ValueKey<int>(2); const Key key2 = ValueKey<int>(2);
await tester.pumpWidget( await tester.pumpWidget(
@ -670,7 +674,8 @@ void main() {
await tester.pump(); await tester.pump();
expect(tester.getRect(find.byKey(key1)), const Rect.fromLTWH(0.0, 0.0, 800.0, 100.0)); expect(tester.getRect(find.byKey(key1)), const Rect.fromLTWH(0.0, 0.0, 800.0, 100.0));
await gesture.up(); await gesture.up();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); debugDefaultTargetPlatformOverride = null;
});
} }
class TestHeader extends SliverPersistentHeaderDelegate { class TestHeader extends SliverPersistentHeaderDelegate {

View File

@ -634,9 +634,9 @@ void main() {
'The most common way to add an Overlay to an application is to\n' 'The most common way to add an Overlay to an application is to\n'
'include a MaterialApp or Navigator widget in the runApp() call.\n', 'include a MaterialApp or Navigator widget in the runApp() call.\n',
)); ));
expect(error.diagnostics[3], isA<DiagnosticsProperty<Widget>>()); expect(error.diagnostics[3], isInstanceOf<DiagnosticsProperty<Widget>>());
expect(error.diagnostics[3].value, debugRequiredFor); expect(error.diagnostics[3].value, debugRequiredFor);
expect(error.diagnostics[4], isA<DiagnosticsProperty<Element>>()); expect(error.diagnostics[4], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.toStringDeep(), equalsIgnoringHashCodes( expect(error.toStringDeep(), equalsIgnoringHashCodes(
'FlutterError\n' 'FlutterError\n'
' No Overlay widget found.\n' ' No Overlay widget found.\n'

View File

@ -157,7 +157,10 @@ void main() {
), ),
}; };
await tester.pumpWidget(MaterialApp(routes: routes)); await tester.pumpWidget(MaterialApp(
routes: routes,
theme: ThemeData(platform: TargetPlatform.iOS),
));
Navigator.pushNamed(containerKey1.currentContext, '/settings'); Navigator.pushNamed(containerKey1.currentContext, '/settings');
@ -196,7 +199,7 @@ void main() {
settingsOffset = tester.getTopLeft(find.text('Settings')); settingsOffset = tester.getTopLeft(find.text('Settings'));
expect(settingsOffset.dx, greaterThan(100.0)); expect(settingsOffset.dx, greaterThan(100.0));
expect(settingsOffset.dy, 100.0); expect(settingsOffset.dy, 100.0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Check back gesture doesn\'t start during transitions', (WidgetTester tester) async { testWidgets('Check back gesture doesn\'t start during transitions', (WidgetTester tester) async {
final GlobalKey containerKey1 = GlobalKey(); final GlobalKey containerKey1 = GlobalKey();
@ -206,7 +209,10 @@ void main() {
'/settings': (_) => Scaffold(key: containerKey2, body: const Text('Settings')), '/settings': (_) => Scaffold(key: containerKey2, body: const Text('Settings')),
}; };
await tester.pumpWidget(MaterialApp(routes: routes)); await tester.pumpWidget(MaterialApp(
routes: routes,
theme: ThemeData(platform: TargetPlatform.iOS),
));
Navigator.pushNamed(containerKey1.currentContext, '/settings'); Navigator.pushNamed(containerKey1.currentContext, '/settings');
@ -239,7 +245,7 @@ void main() {
expect(find.text('Home'), isOnstage); expect(find.text('Home'), isOnstage);
expect(find.text('Settings'), findsNothing); expect(find.text('Settings'), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
// Tests bug https://github.com/flutter/flutter/issues/6451 // Tests bug https://github.com/flutter/flutter/issues/6451
testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async { testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async {
@ -250,7 +256,10 @@ void main() {
'/sheet': (_) => PersistentBottomSheetTest(key: containerKey2), '/sheet': (_) => PersistentBottomSheetTest(key: containerKey2),
}; };
await tester.pumpWidget(MaterialApp(routes: routes)); await tester.pumpWidget(MaterialApp(
routes: routes,
theme: ThemeData(platform: TargetPlatform.iOS),
));
Navigator.pushNamed(containerKey1.currentContext, '/sheet'); Navigator.pushNamed(containerKey1.currentContext, '/sheet');
@ -293,7 +302,7 @@ void main() {
// Sheet did not call setState (since the gesture did nothing). // Sheet did not call setState (since the gesture did nothing).
expect(sheet.setStateCalled, isFalse); expect(sheet.setStateCalled, isFalse);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('Test completed future', (WidgetTester tester) async { testWidgets('Test completed future', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{

View File

@ -83,6 +83,7 @@ void main() {
testWidgets('PageView does not squish when overscrolled', (WidgetTester tester) async { testWidgets('PageView does not squish when overscrolled', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: PageView( home: PageView(
children: List<Widget>.generate(10, (int i) { children: List<Widget>.generate(10, (int i) {
return Container( return Container(
@ -112,7 +113,7 @@ void main() {
expect(leftOf(0), lessThan(0.0)); expect(leftOf(0), lessThan(0.0));
expect(sizeOf(0), equals(const Size(800.0, 600.0))); expect(sizeOf(0), equals(const Size(800.0, 600.0)));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); });
testWidgets('PageController control test', (WidgetTester tester) async { testWidgets('PageController control test', (WidgetTester tester) async {
final PageController controller = PageController(initialPage: 4); final PageController controller = PageController(initialPage: 4);

View File

@ -22,14 +22,14 @@ void checkTree(WidgetTester tester, List<TestParentData> expectedParentData) {
find.byElementPredicate((Element element) => element is MultiChildRenderObjectElement) find.byElementPredicate((Element element) => element is MultiChildRenderObjectElement)
); );
expect(element, isNotNull); expect(element, isNotNull);
expect(element.renderObject, isA<RenderStack>()); expect(element.renderObject is RenderStack, isTrue);
final RenderStack renderObject = element.renderObject as RenderStack; final RenderStack renderObject = element.renderObject as RenderStack;
try { try {
RenderObject child = renderObject.firstChild; RenderObject child = renderObject.firstChild;
for (final TestParentData expected in expectedParentData) { for (final TestParentData expected in expectedParentData) {
expect(child, isA<RenderDecoratedBox>()); expect(child is RenderDecoratedBox, isTrue);
final RenderDecoratedBox decoratedBox = child as RenderDecoratedBox; final RenderDecoratedBox decoratedBox = child as RenderDecoratedBox;
expect(decoratedBox.parentData, isA<StackParentData>()); expect(decoratedBox.parentData is StackParentData, isTrue);
final StackParentData parentData = decoratedBox.parentData as StackParentData; final StackParentData parentData = decoratedBox.parentData as StackParentData;
expect(parentData.top, equals(expected.top)); expect(parentData.top, equals(expected.top));
expect(parentData.right, equals(expected.right)); expect(parentData.right, equals(expected.right));

View File

@ -105,7 +105,7 @@ void main() {
); );
final dynamic exception = tester.takeException(); final dynamic exception = tester.takeException();
expect(exception, isFlutterError); expect(exception, isInstanceOf<FlutterError>());
expect(exception.diagnostics.first.level, DiagnosticLevel.summary); expect(exception.diagnostics.first.level, DiagnosticLevel.summary);
expect(exception.diagnostics.first.toString(), startsWith('A RenderFlex overflowed by ')); expect(exception.diagnostics.first.toString(), startsWith('A RenderFlex overflowed by '));
await expectLater( await expectLater(

View File

@ -128,7 +128,7 @@ void main() {
); );
final Layer textureParentLayer = tester.layers[tester.layers.length - 2]; final Layer textureParentLayer = tester.layers[tester.layers.length - 2];
expect(textureParentLayer, isA<ClipRectLayer>()); expect(textureParentLayer, isInstanceOf<ClipRectLayer>());
final ClipRectLayer clipRect = textureParentLayer as ClipRectLayer; final ClipRectLayer clipRect = textureParentLayer as ClipRectLayer;
expect(clipRect.clipRect, const Rect.fromLTWH(0.0, 0.0, 100.0, 50.0)); expect(clipRect.clipRect, const Rect.fromLTWH(0.0, 0.0, 100.0, 50.0));
expect( expect(

View File

@ -52,7 +52,7 @@ void main() {
SingleChildRenderObjectElement element = SingleChildRenderObjectElement element =
tester.element(find.byElementType(SingleChildRenderObjectElement)); tester.element(find.byElementType(SingleChildRenderObjectElement));
expect(element, isNotNull); expect(element, isNotNull);
expect(element.renderObject, isA<RenderDecoratedBox>()); expect(element.renderObject is RenderDecoratedBox, isTrue);
RenderDecoratedBox renderObject = element.renderObject as RenderDecoratedBox; RenderDecoratedBox renderObject = element.renderObject as RenderDecoratedBox;
expect(renderObject.decoration, equals(kBoxDecorationA)); expect(renderObject.decoration, equals(kBoxDecorationA));
expect(renderObject.position, equals(DecorationPosition.background)); expect(renderObject.position, equals(DecorationPosition.background));
@ -60,7 +60,7 @@ void main() {
await tester.pumpWidget(DecoratedBox(decoration: kBoxDecorationB)); await tester.pumpWidget(DecoratedBox(decoration: kBoxDecorationB));
element = tester.element(find.byElementType(SingleChildRenderObjectElement)); element = tester.element(find.byElementType(SingleChildRenderObjectElement));
expect(element, isNotNull); expect(element, isNotNull);
expect(element.renderObject, isA<RenderDecoratedBox>()); expect(element.renderObject is RenderDecoratedBox, isTrue);
renderObject = element.renderObject as RenderDecoratedBox; renderObject = element.renderObject as RenderDecoratedBox;
expect(renderObject.decoration, equals(kBoxDecorationB)); expect(renderObject.decoration, equals(kBoxDecorationB));
expect(renderObject.position, equals(DecorationPosition.background)); expect(renderObject.position, equals(DecorationPosition.background));
@ -72,12 +72,12 @@ void main() {
final SingleChildRenderObjectElement element = final SingleChildRenderObjectElement element =
tester.firstElement(find.byElementType(SingleChildRenderObjectElement)); tester.firstElement(find.byElementType(SingleChildRenderObjectElement));
expect(element, isNotNull); expect(element, isNotNull);
expect(element.renderObject, isA<RenderDecoratedBox>()); expect(element.renderObject is RenderDecoratedBox, isTrue);
final RenderDecoratedBox renderObject = element.renderObject as RenderDecoratedBox; final RenderDecoratedBox renderObject = element.renderObject as RenderDecoratedBox;
expect(renderObject.decoration, equals(kBoxDecorationA)); expect(renderObject.decoration, equals(kBoxDecorationA));
expect(renderObject.position, equals(DecorationPosition.background)); expect(renderObject.position, equals(DecorationPosition.background));
expect(renderObject.child, isNotNull); expect(renderObject.child, isNotNull);
expect(renderObject.child, isA<RenderDecoratedBox>()); expect(renderObject.child is RenderDecoratedBox, isTrue);
final RenderDecoratedBox child = renderObject.child as RenderDecoratedBox; final RenderDecoratedBox child = renderObject.child as RenderDecoratedBox;
expect(child.decoration, equals(kBoxDecorationB)); expect(child.decoration, equals(kBoxDecorationB));
expect(child.position, equals(DecorationPosition.background)); expect(child.position, equals(DecorationPosition.background));
@ -88,7 +88,7 @@ void main() {
final SingleChildRenderObjectElement element = final SingleChildRenderObjectElement element =
tester.element(find.byElementType(SingleChildRenderObjectElement)); tester.element(find.byElementType(SingleChildRenderObjectElement));
expect(element, isNotNull); expect(element, isNotNull);
expect(element.renderObject, isA<RenderDecoratedBox>()); expect(element.renderObject is RenderDecoratedBox, isTrue);
final RenderDecoratedBox renderObject = element.renderObject as RenderDecoratedBox; final RenderDecoratedBox renderObject = element.renderObject as RenderDecoratedBox;
expect(renderObject.decoration, equals(kBoxDecorationA)); expect(renderObject.decoration, equals(kBoxDecorationA));
expect(renderObject.position, equals(DecorationPosition.background)); expect(renderObject.position, equals(DecorationPosition.background));
@ -164,12 +164,12 @@ void main() {
SingleChildRenderObjectElement element = SingleChildRenderObjectElement element =
tester.firstElement(find.byElementType(SingleChildRenderObjectElement)); tester.firstElement(find.byElementType(SingleChildRenderObjectElement));
expect(element.renderObject, isA<RenderDecoratedBox>()); expect(element.renderObject is RenderDecoratedBox, isTrue);
final RenderDecoratedBox parent = element.renderObject as RenderDecoratedBox; final RenderDecoratedBox parent = element.renderObject as RenderDecoratedBox;
expect(parent.child, isA<RenderDecoratedBox>()); expect(parent.child is RenderDecoratedBox, isTrue);
final RenderDecoratedBox child = parent.child as RenderDecoratedBox; final RenderDecoratedBox child = parent.child as RenderDecoratedBox;
expect(child.decoration, equals(kBoxDecorationB)); expect(child.decoration, equals(kBoxDecorationB));
expect(child.child, isA<RenderDecoratedBox>()); expect(child.child is RenderDecoratedBox, isTrue);
final RenderDecoratedBox grandChild = child.child as RenderDecoratedBox; final RenderDecoratedBox grandChild = child.child as RenderDecoratedBox;
expect(grandChild.decoration, equals(kBoxDecorationC)); expect(grandChild.decoration, equals(kBoxDecorationC));
expect(grandChild.child, isNull); expect(grandChild.child, isNull);
@ -180,7 +180,7 @@ void main() {
element = element =
tester.element(find.byElementType(SingleChildRenderObjectElement)); tester.element(find.byElementType(SingleChildRenderObjectElement));
expect(element.renderObject, isA<RenderDecoratedBox>()); expect(element.renderObject is RenderDecoratedBox, isTrue);
expect(element.renderObject, equals(parent)); expect(element.renderObject, equals(parent));
expect(parent.child, isNull); expect(parent.child, isNull);

View File

@ -48,7 +48,7 @@ class TestRoute extends Route<String> with LocalHistoryRoute<String> {
@override @override
void didReplace(Route<dynamic> oldRoute) { void didReplace(Route<dynamic> oldRoute) {
expect(oldRoute, isA<TestRoute>()); expect(oldRoute, isInstanceOf<TestRoute>());
final TestRoute castRoute = oldRoute as TestRoute; final TestRoute castRoute = oldRoute as TestRoute;
log('didReplace ${castRoute.name}'); log('didReplace ${castRoute.name}');
super.didReplace(castRoute); super.didReplace(castRoute);
@ -65,7 +65,7 @@ class TestRoute extends Route<String> with LocalHistoryRoute<String> {
@override @override
void didPopNext(Route<dynamic> nextRoute) { void didPopNext(Route<dynamic> nextRoute) {
expect(nextRoute, isA<TestRoute>()); expect(nextRoute, isInstanceOf<TestRoute>());
final TestRoute castRoute = nextRoute as TestRoute; final TestRoute castRoute = nextRoute as TestRoute;
log('didPopNext ${castRoute.name}'); log('didPopNext ${castRoute.name}');
super.didPopNext(castRoute); super.didPopNext(castRoute);
@ -73,7 +73,7 @@ class TestRoute extends Route<String> with LocalHistoryRoute<String> {
@override @override
void didChangeNext(Route<dynamic> nextRoute) { void didChangeNext(Route<dynamic> nextRoute) {
expect(nextRoute, anyOf(isNull, isA<TestRoute>())); expect(nextRoute, anyOf(isNull, isInstanceOf<TestRoute>()));
final TestRoute castRoute = nextRoute as TestRoute; final TestRoute castRoute = nextRoute as TestRoute;
log('didChangeNext ${castRoute?.name}'); log('didChangeNext ${castRoute?.name}');
super.didChangeNext(castRoute); super.didChangeNext(castRoute);

View File

@ -47,7 +47,7 @@ void main() {
expect(behavior, isNotNull); expect(behavior, isNotNull);
expect(behavior.flag, isTrue); expect(behavior.flag, isTrue);
expect(position.physics, isA<ClampingScrollPhysics>()); expect(position.physics, isInstanceOf<ClampingScrollPhysics>());
ScrollMetrics metrics = position.copyWith(); ScrollMetrics metrics = position.copyWith();
expect(metrics.extentAfter, equals(400.0)); expect(metrics.extentAfter, equals(400.0));
expect(metrics.viewportDimension, equals(600.0)); expect(metrics.viewportDimension, equals(600.0));
@ -62,7 +62,7 @@ void main() {
expect(behavior, isNotNull); expect(behavior, isNotNull);
expect(behavior.flag, isFalse); expect(behavior.flag, isFalse);
expect(position.physics, isA<BouncingScrollPhysics>()); expect(position.physics, isInstanceOf<BouncingScrollPhysics>());
// Regression test for https://github.com/flutter/flutter/issues/5856 // Regression test for https://github.com/flutter/flutter/issues/5856
metrics = position.copyWith(); metrics = position.copyWith();
expect(metrics.extentAfter, equals(400.0)); expect(metrics.extentAfter, equals(400.0));

View File

@ -24,7 +24,7 @@ void main() {
final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0)); final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
expect(notification, isA<ScrollStartNotification>()); expect(notification, isInstanceOf<ScrollStartNotification>());
expect(notification.depth, equals(0)); expect(notification.depth, equals(0));
final ScrollStartNotification start = notification as ScrollStartNotification; final ScrollStartNotification start = notification as ScrollStartNotification;
expect(start.dragDetails, isNotNull); expect(start.dragDetails, isNotNull);
@ -32,7 +32,7 @@ void main() {
await gesture.moveBy(const Offset(-10.0, -10.0)); await gesture.moveBy(const Offset(-10.0, -10.0));
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
expect(notification, isA<ScrollUpdateNotification>()); expect(notification, isInstanceOf<ScrollUpdateNotification>());
expect(notification.depth, equals(0)); expect(notification.depth, equals(0));
final ScrollUpdateNotification update = notification as ScrollUpdateNotification; final ScrollUpdateNotification update = notification as ScrollUpdateNotification;
expect(update.dragDetails, isNotNull); expect(update.dragDetails, isNotNull);
@ -41,7 +41,7 @@ void main() {
await gesture.up(); await gesture.up();
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
expect(notification, isA<ScrollEndNotification>()); expect(notification, isInstanceOf<ScrollEndNotification>());
expect(notification.depth, equals(0)); expect(notification.depth, equals(0));
final ScrollEndNotification end = notification as ScrollEndNotification; final ScrollEndNotification end = notification as ScrollEndNotification;
expect(end.dragDetails, isNotNull); expect(end.dragDetails, isNotNull);

View File

@ -239,10 +239,10 @@ void main() {
} finally { } finally {
expect(error, isNotNull); expect(error, isNotNull);
expect(error.diagnostics.length, 4); expect(error.diagnostics.length, 4);
expect(error.diagnostics[2], isA<DiagnosticsProperty<ScrollPhysics>>()); expect(error.diagnostics[2], isInstanceOf<DiagnosticsProperty<ScrollPhysics>>());
expect(error.diagnostics[2].style, DiagnosticsTreeStyle.errorProperty); expect(error.diagnostics[2].style, DiagnosticsTreeStyle.errorProperty);
expect(error.diagnostics[2].value, physics); expect(error.diagnostics[2].value, physics);
expect(error.diagnostics[3], isA<DiagnosticsProperty<ScrollMetrics>>()); expect(error.diagnostics[3], isInstanceOf<DiagnosticsProperty<ScrollMetrics>>());
expect(error.diagnostics[3].style, DiagnosticsTreeStyle.errorProperty); expect(error.diagnostics[3].style, DiagnosticsTreeStyle.errorProperty);
expect(error.diagnostics[3].value, position); expect(error.diagnostics[3].value, position);
// RegExp matcher is required here due to flutter web and flutter mobile generating // RegExp matcher is required here due to flutter web and flutter mobile generating

View File

@ -326,22 +326,22 @@ void main() {
testWidgets('Primary ListViews are always scrollable', (WidgetTester tester) async { testWidgets('Primary ListViews are always scrollable', (WidgetTester tester) async {
final ListView view = ListView(primary: true); final ListView view = ListView(primary: true);
expect(view.physics, isA<AlwaysScrollableScrollPhysics>()); expect(view.physics, isInstanceOf<AlwaysScrollableScrollPhysics>());
}); });
testWidgets('Non-primary ListViews are not always scrollable', (WidgetTester tester) async { testWidgets('Non-primary ListViews are not always scrollable', (WidgetTester tester) async {
final ListView view = ListView(primary: false); final ListView view = ListView(primary: false);
expect(view.physics, isNot(isA<AlwaysScrollableScrollPhysics>())); expect(view.physics, isNot(isInstanceOf<AlwaysScrollableScrollPhysics>()));
}); });
testWidgets('Defaulting-to-primary ListViews are always scrollable', (WidgetTester tester) async { testWidgets('Defaulting-to-primary ListViews are always scrollable', (WidgetTester tester) async {
final ListView view = ListView(scrollDirection: Axis.vertical); final ListView view = ListView(scrollDirection: Axis.vertical);
expect(view.physics, isA<AlwaysScrollableScrollPhysics>()); expect(view.physics, isInstanceOf<AlwaysScrollableScrollPhysics>());
}); });
testWidgets('Defaulting-to-not-primary ListViews are not always scrollable', (WidgetTester tester) async { testWidgets('Defaulting-to-not-primary ListViews are not always scrollable', (WidgetTester tester) async {
final ListView view = ListView(scrollDirection: Axis.horizontal); final ListView view = ListView(scrollDirection: Axis.horizontal);
expect(view.physics, isNot(isA<AlwaysScrollableScrollPhysics>())); expect(view.physics, isNot(isInstanceOf<AlwaysScrollableScrollPhysics>()));
}); });
testWidgets('primary:true leads to scrolling', (WidgetTester tester) async { testWidgets('primary:true leads to scrolling', (WidgetTester tester) async {
@ -459,7 +459,7 @@ void main() {
// A separatorBuilder that returns null throws a FlutterError // A separatorBuilder that returns null throws a FlutterError
await tester.pumpWidget(buildFrame(null)); await tester.pumpWidget(buildFrame(null));
expect(tester.takeException(), isFlutterError); expect(tester.takeException(), isInstanceOf<FlutterError>());
expect(find.byType(ErrorWidget), findsOneWidget); expect(find.byType(ErrorWidget), findsOneWidget);
}); });
@ -520,7 +520,7 @@ void main() {
// When it does throw, one error widget is rendered in the item's place // When it does throw, one error widget is rendered in the item's place
await tester.pumpWidget(buildFrame(true)); await tester.pumpWidget(buildFrame(true));
expect(tester.takeException(), isA<Exception>()); expect(tester.takeException(), isInstanceOf<Exception>());
expect(finder, findsOneWidget); expect(finder, findsOneWidget);
}); });
@ -556,7 +556,7 @@ void main() {
// When it does throw, one error widget is rendered in the separator's place // When it does throw, one error widget is rendered in the separator's place
await tester.pumpWidget(buildFrame(true)); await tester.pumpWidget(buildFrame(true));
expect(tester.takeException(), isA<Exception>()); expect(tester.takeException(), isInstanceOf<Exception>());
expect(finder, findsOneWidget); expect(finder, findsOneWidget);
}); });
@ -566,7 +566,7 @@ void main() {
return const SizedBox(); return const SizedBox();
}, },
itemCount: -1, itemCount: -1,
), throwsAssertionError); ), throwsA(isInstanceOf<AssertionError>()));
}); });
testWidgets('ListView.builder asserts on negative semanticChildCount', (WidgetTester tester) async { testWidgets('ListView.builder asserts on negative semanticChildCount', (WidgetTester tester) async {
@ -576,7 +576,7 @@ void main() {
}, },
itemCount: 1, itemCount: 1,
semanticChildCount: -1, semanticChildCount: -1,
), throwsAssertionError); ), throwsA(isInstanceOf<AssertionError>()));
}); });
testWidgets('ListView.builder asserts on nonsensical childCount/semanticChildCount', (WidgetTester tester) async { testWidgets('ListView.builder asserts on nonsensical childCount/semanticChildCount', (WidgetTester tester) async {
@ -586,6 +586,6 @@ void main() {
}, },
itemCount: 1, itemCount: 1,
semanticChildCount: 4, semanticChildCount: 4,
), throwsAssertionError); ), throwsA(isInstanceOf<AssertionError>()));
}); });
} }

View File

@ -28,9 +28,10 @@ void main() {
await tester.pump(const Duration(hours: 5)); await tester.pump(const Duration(hours: 5));
}); });
testWidgets('Disposing a (nested) Scrollable while holding in overscroll does not crash', (WidgetTester tester) async { testWidgets('Disposing a (nested) Scrollable while holding in overscroll (iOS) does not crash', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/27707. // Regression test for https://github.com/flutter/flutter/issues/27707.
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final ScrollController controller = ScrollController(); final ScrollController controller = ScrollController();
final Key outterContainer = GlobalKey(); final Key outterContainer = GlobalKey();
@ -87,5 +88,7 @@ void main() {
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(controller.hasClients, isFalse); expect(controller.hasClients, isFalse);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
} }

Some files were not shown because too many files have changed in this diff Show More