[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
/// 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) {
// This should not be necessary, but it turns out that

View File

@ -25,7 +25,7 @@ void main() {
expectAsync1((List<String> commandLine) async {
return processRunner.runProcess(commandLine);
})(<String>['this_executable_better_not_exist_2857632534321']),
throwsA(isA<PreparePackageException>()));
throwsA(isInstanceOf<PreparePackageException>()));
try {
await processRunner.runProcess(<String>['this_executable_better_not_exist_2857632534321']);
} on PreparePackageException catch (e) {
@ -64,7 +64,7 @@ void main() {
expectAsync1((List<String> commandLine) async {
return processRunner.runProcess(commandLine);
})(<String>['echo', 'test']),
throwsA(isA<PreparePackageException>()));
throwsA(isInstanceOf<PreparePackageException>()));
});
});
group('ArchiveCreator for $platformName', () {
@ -185,7 +185,8 @@ void main() {
'git reset --hard $testRef': <ProcessResult>[ProcessResult(0, -1, 'output2', '')],
};
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 {

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
/// 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;
/// 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
/// 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) {
// This should not be necessary, but it turns out that

View File

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

View File

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

View File

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

View File

@ -792,18 +792,14 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
this.barrierColor,
this.barrierLabel,
this.builder,
bool semanticsDismissible,
ImageFilter filter,
RouteSettings settings,
}) : super(
filter: filter,
settings: settings,
) {
_semanticsDismissible = semanticsDismissible;
}
);
final WidgetBuilder builder;
bool _semanticsDismissible;
@override
final String barrierLabel;
@ -815,7 +811,7 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
bool get barrierDismissible => true;
@override
bool get semanticsDismissible => _semanticsDismissible ?? false;
bool get semanticsDismissible => false;
@override
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
/// 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.
/// Content below the widget is dimmed with a [ModalBarrier]. The widget built
/// by the `builder` does not share a context with the location that
@ -898,7 +891,6 @@ Future<T> showCupertinoModalPopup<T>({
@required WidgetBuilder builder,
ImageFilter filter,
bool useRootNavigator = true,
bool semanticsDismissible,
}) {
assert(useRootNavigator != null);
return Navigator.of(context, rootNavigator: useRootNavigator).push(
@ -907,7 +899,6 @@ Future<T> showCupertinoModalPopup<T>({
barrierLabel: 'Dismiss',
builder: builder,
filter: filter,
semanticsDismissible: semanticsDismissible,
),
);
}

View File

@ -61,8 +61,6 @@ const Duration _kFadeDuration = Duration(milliseconds: 165);
///
/// 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/>
class CupertinoSegmentedControl<T> extends StatefulWidget {
/// Creates an iOS-style segmented control bar.

View File

@ -118,8 +118,6 @@ class _FontWeightTween extends Tween<FontWeight> {
///
/// 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/>
class CupertinoSlidingSegmentedControl<T> extends StatefulWidget {
/// Creates an iOS-style segmented control bar.

View File

@ -32,7 +32,7 @@ const int _kDefaultSizeBytes = 100 << 20; // 100 MiB
/// {@tool snippet}
///
/// This sample shows how to supply your own caching logic and replace the
/// global [imageCache] variable.
/// global [imageCache] varible.
///
/// ```dart
/// /// This is the custom implementation of [ImageCache] where we can override
@ -64,6 +64,7 @@ const int _kDefaultSizeBytes = 100 << 20; // 100 MiB
/// }
/// ```
/// {@end-tool}
class ImageCache {
final Map<Object, _PendingImage> _pendingImages = <Object, _PendingImage>{};
final Map<Object, _CachedImage> _cache = <Object, _CachedImage>{};
@ -140,13 +141,12 @@ class ImageCache {
}
/// Evicts a single entry from the cache, returning true if successful.
/// Pending images waiting for completion are removed as well, returning true
/// if successful.
/// Pending images waiting for completion are removed as well, returning true if successful.
///
/// When a pending image is removed the listener on it is removed as well to
/// prevent it from adding itself to the cache if it eventually completes.
/// When a pending image is removed the listener on it is removed as well to prevent
/// 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].
///
/// 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.
@immutable
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.
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
/// 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
/// double the height and width that should be used when painting the image
/// (e.g. in the arguments given to [Canvas.drawImage]).
/// by the [dart:ui.Image.width] and [dart:ui.Image.height] properties) are double the
/// height and width that should be used when painting the image (e.g. in the
/// arguments given to [Canvas.drawImage]).
final double scale;
@override
@ -58,11 +58,11 @@ class ImageInfo {
/// 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
/// as a listener (e.g. via [ImageStream.addListener]), you can instantiate a
/// _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.
///
/// 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
// 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
// if the selection offset didn't change.
final bool focusingEmpty = nextSelection.baseOffset == 0
&& nextSelection.extentOffset == 0
&& !hasFocus;
if (nextSelection == selection
&& cause != SelectionChangedCause.keyboard
&& !focusingEmpty) {
// changed.
if (nextSelection == selection && cause != SelectionChangedCause.keyboard) {
return;
}
if (onSelectionChanged != null) {

View File

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

View File

@ -172,10 +172,10 @@ void main() {
final TickerFuture f = controller1.forward();
await tester.pump(); // start 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'; });
expect(await f.then<bool>((_) => true), isTrue);
expect(f.whenComplete(() => false), isA<Future<void>>());
expect(f.timeout(const Duration(seconds: 5)), isA<Future<void>>());
expect(f.whenComplete(() => false), isInstanceOf<Future<void>>());
expect(f.timeout(const Duration(seconds: 5)), isInstanceOf<Future<void>>());
});
}

View File

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

View File

@ -3,14 +3,11 @@
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import '../widgets/semantics_tester.dart';
void main() {
MockNavigatorObserver navigatorObserver;
@ -1055,75 +1052,6 @@ void main() {
expect(rootObserver.dialogCount, 0);
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 {}

View File

@ -43,6 +43,7 @@ void main() {
});
testWidgets('Switch emits light haptic vibration on tap', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Key switchKey = UniqueKey();
bool value = false;
@ -79,9 +80,11 @@ void main() {
expect(log, hasLength(1));
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 {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Key switchKey = UniqueKey();
final Key switchKey2 = UniqueKey();
bool value = false;
@ -149,9 +152,11 @@ void main() {
expect(log, hasLength(4));
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 {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
bool value = false;
final List<MethodCall> log = <MethodCall>[];
@ -186,9 +191,11 @@ void main() {
expect(log, hasLength(1));
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 {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final Key switchKey = UniqueKey();
bool value = false;
@ -237,7 +244,8 @@ void main() {
await tester.pump();
expect(log, hasLength(0));
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS));
debugDefaultTargetPlatformOverride = null;
});
testWidgets('Switch can drag (LTR)', (WidgetTester tester) async {
bool value = false;

View File

@ -425,7 +425,9 @@ void main() {
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(
const CupertinoApp(
home: CupertinoTextField(),
@ -457,9 +459,13 @@ void main() {
await tester.pump(const Duration(milliseconds: 50));
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(
const CupertinoApp(
home: CupertinoTextField(),
@ -470,7 +476,9 @@ void main() {
final RenderEditable renderEditable = editableTextState.renderEditable;
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 {
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(
home: Center(
child: RepaintBoundary(
@ -520,13 +530,12 @@ void main() {
await tester.tapAt(textOffsetToPosition(tester, testValue.length));
await tester.pumpAndSettle();
debugDefaultTargetPlatformOverride = null;
await expectLater(
find.byKey(const ValueKey<int>(1)),
matchesGoldenFile(
'text_field_cursor_test.cupertino_${describeEnum(debugDefaultTargetPlatformOverride).toLowerCase()}.1.png',
),
matchesGoldenFile('text_field_cursor_test.cupertino.1.png'),
);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
testWidgets(
'can control text content via controller',
@ -2937,7 +2946,8 @@ void main() {
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';
final TextEditingController controller = TextEditingController(text: testText);
@ -2967,7 +2977,9 @@ void main() {
expect(left.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 {
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
/// 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.
const bool isBrowser = identical(0, 0.0);

View File

@ -110,7 +110,8 @@ void main() {
});
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 {

View File

@ -27,9 +27,9 @@ Future<int> test2Async(int value) async {
void main() {
test('compute()', () async {
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(compute(test2Async, 0), throwsException);
expect(compute(test2Async, 0), throwsA(isInstanceOf<Exception>()));
});
}

View File

@ -489,51 +489,43 @@ void main() {
extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
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'}));
expect(result, <String, String>{'value': 'android'});
expect(binding.reassembled, 3);
expect(binding.reassembled, 2);
expect(defaultTargetPlatform, TargetPlatform.android);
expect(extensionChangedEvents.length, 3);
expect(extensionChangedEvents.length, 2);
extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'android');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'fuchsia'}));
expect(result, <String, String>{'value': 'fuchsia'});
expect(binding.reassembled, 4);
expect(binding.reassembled, 3);
expect(defaultTargetPlatform, TargetPlatform.fuchsia);
expect(extensionChangedEvents.length, 4);
expect(extensionChangedEvents.length, 3);
extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'fuchsia');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'default'}));
expect(result, <String, String>{'value': 'android'});
expect(binding.reassembled, 5);
expect(binding.reassembled, 4);
expect(defaultTargetPlatform, TargetPlatform.android);
expect(extensionChangedEvents.length, 5);
expect(extensionChangedEvents.length, 4);
extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'android');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'iOS'}));
expect(result, <String, String>{'value': 'iOS'});
expect(binding.reassembled, 6);
expect(binding.reassembled, 5);
expect(defaultTargetPlatform, TargetPlatform.iOS);
expect(extensionChangedEvents.length, 6);
expect(extensionChangedEvents.length, 5);
extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
expect(extensionChangedEvent['value'], 'iOS');
result = await hasReassemble(binding.testExtension('platformOverride', <String, String>{'value': 'bogus'}));
expect(result, <String, String>{'value': 'android'});
expect(binding.reassembled, 7);
expect(binding.reassembled, 6);
expect(defaultTargetPlatform, TargetPlatform.android);
expect(extensionChangedEvents.length, 7);
expect(extensionChangedEvents.length, 6);
extensionChangedEvent = extensionChangedEvents.last;
expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride');
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
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
@ -84,68 +83,66 @@ void main() {
Size size = tester.getSize(title);
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 platforms.
await tester.pumpWidget(Container(key: UniqueKey()));
// Clear the widget tree to avoid animating between Android and iOS.
await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: platform),
home: Scaffold(
appBar: AppBar(
title: const Text('X'),
),
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
appBar: AppBar(
title: const Text('X'),
),
),
);
),
);
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}');
expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}');
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, greaterThan(400 - size.width / 2.0));
expect(center.dx, lessThan(400 + size.width / 2.0));
// One action is still centered.
// One action is still centered.
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: platform),
home: Scaffold(
appBar: AppBar(
title: const Text('X'),
actions: const <Widget>[
Icon(Icons.thumb_up),
],
),
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
appBar: AppBar(
title: const Text('X'),
actions: const <Widget>[
Icon(Icons.thumb_up),
],
),
),
);
),
);
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, greaterThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}');
expect(center.dx, lessThan(400 + size.width / 2.0), reason: 'on ${describeEnum(platform)}');
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, greaterThan(400 - size.width / 2.0));
expect(center.dx, lessThan(400 + size.width / 2.0));
// Two actions is left aligned again.
// Two actions is left aligned again.
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: platform),
home: Scaffold(
appBar: AppBar(
title: const Text('X'),
actions: const <Widget>[
Icon(Icons.thumb_up),
Icon(Icons.thumb_up),
],
),
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
appBar: AppBar(
title: const Text('X'),
actions: const <Widget>[
Icon(Icons.thumb_up),
Icon(Icons.thumb_up),
],
),
),
);
),
);
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, lessThan(400 - size.width / 2.0), reason: 'on ${describeEnum(platform)}');
}
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, lessThan(400 - size.width / 2.0));
});
testWidgets('AppBar centerTitle:true centers on Android', (WidgetTester tester) async {

View File

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

View File

@ -322,7 +322,7 @@ void main() {
),
);
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(find.text('route "/"'), findsOneWidget);
expect(find.text('route "/a"'), findsNothing);
@ -474,7 +474,7 @@ void main() {
color: const Color(0xFF112233),
home: const Placeholder(),
));
expect(key.currentState, isA<NavigatorState>());
expect(key.currentState, isInstanceOf<NavigatorState>());
await tester.pumpWidget(const MaterialApp(
color: Color(0xFF112233),
home: Placeholder(),
@ -485,7 +485,7 @@ void main() {
color: const Color(0xFF112233),
home: const Placeholder(),
));
expect(key.currentState, isA<NavigatorState>());
expect(key.currentState, isInstanceOf<NavigatorState>());
});
testWidgets('Has default material and cupertino localizations', (WidgetTester tester) async {

View File

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

View File

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

View File

@ -184,7 +184,7 @@ void main() {
expect(lightTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d)));
expect(lightTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.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.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde)));
expect(lightTheme.brightness, equals(Brightness.light));
@ -202,7 +202,7 @@ void main() {
expect(darkTheme.secondarySelectedColor, equals(customColor1.withAlpha(0x3d)));
expect(darkTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.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.secondaryLabelStyle.color, equals(customColor1.withAlpha(0xde)));
expect(darkTheme.brightness, equals(Brightness.dark));
@ -220,7 +220,7 @@ void main() {
expect(customTheme.secondarySelectedColor, equals(customColor2.withAlpha(0x3d)));
expect(customTheme.labelPadding, equals(const EdgeInsets.symmetric(horizontal: 8.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.secondaryLabelStyle.color, equals(customColor2.withAlpha(0xde)));
expect(customTheme.brightness, equals(Brightness.light));
@ -263,7 +263,7 @@ void main() {
expect(lerp.selectedShadowColor, equals(middleGrey));
expect(lerp.labelPadding, equals(const EdgeInsets.all(4.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.secondaryLabelStyle.color, equals(middleGrey.withAlpha(0xde)));
expect(lerp.brightness, equals(Brightness.light));
@ -283,7 +283,7 @@ void main() {
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.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.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0x38)));
expect(lerpANull25.brightness, equals(Brightness.light));
@ -301,7 +301,7 @@ void main() {
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.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.secondaryLabelStyle.color, equals(Colors.white.withAlpha(0xa7)));
expect(lerpANull75.brightness, equals(Brightness.light));
@ -319,7 +319,7 @@ void main() {
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.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.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0xa7)));
expect(lerpBNull25.brightness, equals(Brightness.dark));
@ -337,7 +337,7 @@ void main() {
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.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.secondaryLabelStyle.color, equals(Colors.black.withAlpha(0x38)));
expect(lerpBNull75.brightness, equals(Brightness.light));

View File

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

View File

@ -57,8 +57,9 @@ void main() {
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);
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
@ -79,9 +80,10 @@ void main() {
));
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);
await tester.pumpWidget(
const MaterialApp(
@ -103,7 +105,7 @@ void main() {
)));
semantics.dispose();
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
});
testWidgets('Scaffold drawerScrimColor', (WidgetTester tester) async {
// The scrim is a Container within a Semantics node labeled "Dismiss",

View File

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

View File

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
@ -11,10 +10,10 @@ const double expandedAppbarHeight = 250.0;
final Key appbarContainerKey = UniqueKey();
void main() {
testWidgets('FlexibleSpaceBar collapse mode none', (WidgetTester tester) async {
testWidgets('FlexibleSpaceBar collapse mode none on Android', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: debugDefaultTargetPlatformOverride),
theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold(
body: CustomScrollView(
key: blockKey,
@ -47,12 +46,50 @@ void main() {
expect(topBeforeScroll.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(
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(
body: CustomScrollView(
key: blockKey,
@ -85,12 +122,52 @@ void main() {
expect(topBeforeScroll.dy, equals(0.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(
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(
body: CustomScrollView(
key: blockKey,
@ -124,7 +201,46 @@ void main() {
expect(topBeforeScroll.dy, equals(0.0));
expect(topAfterScroll.dy, lessThan(10.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 {

View File

@ -25,28 +25,26 @@ void main() {
Size size = tester.getSize(title);
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 platforms.
await tester.pumpWidget(Container(key: UniqueKey()));
// Clear the widget tree to avoid animating between Android and iOS.
await tester.pumpWidget(Container(key: UniqueKey()));
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: platform),
home: Scaffold(
appBar: AppBar(
flexibleSpace: const FlexibleSpaceBar(
title: Text('X'),
),
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
appBar: AppBar(
flexibleSpace: const FlexibleSpaceBar(
title: Text('X'),
),
),
),
);
),
);
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, greaterThan(400.0 - size.width / 2.0));
expect(center.dx, lessThan(400.0 + size.width / 2.0));
}
center = tester.getCenter(title);
size = tester.getSize(title);
expect(center.dx, greaterThan(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 {
@ -156,15 +154,6 @@ void main() {
await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false));
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);
testWidgets('FlexibleSpaceBar test titlePadding override', (WidgetTester tester) async {
@ -206,15 +195,6 @@ void main() {
await tester.pumpWidget(buildFrame(TargetPlatform.iOS, false));
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);
}

View File

@ -1047,7 +1047,7 @@ PhysicalModelLayer _findPhysicalLayer(Element element) {
object = object.parent as RenderObject;
}
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 Layer child = layer.firstChild;
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
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart' show CupertinoPageRoute;
import 'package:flutter/rendering.dart';
@ -11,9 +10,10 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
void main() {
testWidgets('test page transition', (WidgetTester tester) async {
testWidgets('test Android page transition', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
home: const Material(child: Text('Page 1')),
routes: <String, WidgetBuilder>{
'/next': (BuildContext context) {
@ -66,12 +66,13 @@ void main() {
expect(find.text('Page 1'), isOnstage);
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();
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(child: Text('Page 1')),
routes: <String, WidgetBuilder>{
'/next': (BuildContext context) {
@ -144,12 +145,13 @@ void main() {
// Page 1 is back where it started.
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(
const MaterialApp(
home: Material(child: Text('Page 1')),
MaterialApp(
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.
expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
testWidgets('test no back gesture on Android', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
home: const Scaffold(body: Text('Page 1')),
routes: <String, WidgetBuilder>{
'/next': (BuildContext context) {
@ -234,11 +237,12 @@ void main() {
// Page 2 didn't move
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(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Scaffold(body: Text('Page 1')),
routes: <String, WidgetBuilder>{
'/next': (BuildContext context) {
@ -275,7 +279,7 @@ void main() {
await tester.pump();
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 {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@ -342,36 +346,13 @@ void main() {
expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 3);
expect(find.text('PUSH'), findsOneWidget);
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(
const MaterialApp(
home: Scaffold(body: Text('Page 1')),
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Scaffold(body: Text('Page 1')),
),
);
@ -396,7 +377,7 @@ void main() {
// Page 2 didn't move
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 {
await tester.pumpWidget(
@ -436,6 +417,7 @@ void main() {
// Re-pump the same app but with iOS instead of Android.
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(child: Text('Page 1')),
routes: <String, WidgetBuilder>{
'/next': (BuildContext context) {
@ -470,7 +452,7 @@ void main() {
// Page 1 is back where it started.
expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
testWidgets('throws when builder returns null', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
@ -488,7 +470,7 @@ void main() {
await tester.pumpAndSettle();
// An exception should've been thrown because the `builder` returned null.
final dynamic exception = tester.takeException();
expect(exception, isFlutterError);
expect(exception, isInstanceOf<FlutterError>());
expect(exception.toStringDeep(), equalsIgnoringHashCodes(
'FlutterError\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(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
@ -529,11 +512,12 @@ void main() {
expect(find.text('Page 1'), findsNothing);
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(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
@ -562,7 +546,7 @@ void main() {
expect(find.text('Page 1'), isOnstage);
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 {
// Regression test for https://github.com/flutter/flutter/issues/28728
@ -570,6 +554,7 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
key: scaffoldKey,
body: Center(
@ -657,7 +642,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.text('route'), findsOneWidget);
expect(find.text('push'), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
testWidgets('During back swipe the route ignores input', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/39989
@ -669,6 +654,7 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
key: homeScaffoldKey,
body: GestureDetector(
@ -727,7 +713,7 @@ void main() {
await tester.pumpAndSettle();
expect(tester.getTopLeft(find.byKey(pageScaffoldKey)), const Offset(400, 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 {
// Regression test for https://github.com/flutter/flutter/issues/41024
@ -739,6 +725,7 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
key: homeScaffoldKey,
body: GestureDetector(
@ -798,9 +785,9 @@ void main() {
await tester.tap(find.byKey(homeScaffoldKey));
expect(homeTapCount, 2);
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.
await tester.pumpWidget(
@ -826,5 +813,5 @@ void main() {
// Title of the first route slides to the left.
expect(titleInitialTopLeft.dy, equals(titleTransientTopLeft.dy));
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.
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
@ -12,16 +11,11 @@ void main() {
await tester.pumpWidget(const MaterialApp(home: Text('home')));
final PageTransitionsTheme theme = Theme.of(tester.element(find.text('home'))).pageTransitionsTheme;
expect(theme.builders, isNotNull);
for (final TargetPlatform platform in TargetPlatform.values) {
if (platform == TargetPlatform.fuchsia) {
// No builder on Fuchsia.
continue;
}
expect(theme.builders[platform], isNotNull, reason: 'theme builder for $platform is null');
}
expect(theme.builders[TargetPlatform.android], isNotNull);
expect(theme.builders[TargetPlatform.iOS], isNotNull);
});
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>{
'/': (BuildContext context) => Material(
child: FlatButton(
@ -34,18 +28,19 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
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);
await tester.tap(find.text('push'));
await tester.pumpAndSettle();
expect(find.text('page b'), 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 {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@ -60,6 +55,7 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.android),
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);
await tester.tap(find.text('push'));
await tester.pumpAndSettle();
expect(find.text('page b'), 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>{
'/': (BuildContext context) => Material(
child: FlatButton(
@ -94,6 +90,7 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
platform: TargetPlatform.android,
pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{
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);
await tester.tap(find.text('push'));
await tester.pumpAndSettle();
expect(find.text('page b'), 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>{
'/': (BuildContext context) => Material(
child: FlatButton(
@ -134,6 +131,7 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
platform: TargetPlatform.android,
pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{
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);
await tester.tap(find.text('push'));
await tester.pumpAndSettle();
expect(find.text('page b'), 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
final dynamic exception = tester.takeException();
expect(exception, isFlutterError);
expect(exception, isInstanceOf<FlutterError>());
expect(exception.diagnostics.first.level, DiagnosticLevel.summary);
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
final dynamic exception = tester.takeException();
expect(exception, isFlutterError);
expect(exception, isInstanceOf<FlutterError>());
expect(exception.diagnostics.first.level, DiagnosticLevel.summary);
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_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', () {
@ -351,7 +345,7 @@ void main() {
icon: const Icon(Icons.view_carousel),
itemBuilder: simplePopupMenuItemBuilder,
);
}, throwsAssertionError);
}, throwsA(isInstanceOf<AssertionError>()));
});
testWidgets('PopupMenuButton creates IconButton when given an icon', (WidgetTester tester) async {

View File

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

View File

@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.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.pump();
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());
});
@ -188,7 +173,7 @@ void main() {
);
}
await tester.pumpWidget(viewWithScroll(debugDefaultTargetPlatformOverride));
await tester.pumpWidget(viewWithScroll(TargetPlatform.iOS));
final TestGesture gesture = await tester.startGesture(
tester.getCenter(find.byType(SingleChildScrollView))
);
@ -199,6 +184,6 @@ void main() {
expect(find.byType(CupertinoScrollbar), paints..rrect());
final CupertinoScrollbar scrollbar = find.byType(CupertinoScrollbar).evaluate().first.widget as CupertinoScrollbar;
expect(scrollbar.controller, isNotNull);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
}

View File

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

View File

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

View File

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

View File

@ -610,28 +610,23 @@ void main() {
);
}
for (final TargetPlatform platform in <TargetPlatform>[ TargetPlatform.iOS, TargetPlatform.macOS ]) {
value = false;
await tester.pumpWidget(buildFrame(platform));
expect(find.byType(CupertinoSwitch), findsOneWidget, reason: 'on ${describeEnum(platform)}');
await tester.pumpWidget(buildFrame(TargetPlatform.iOS));
expect(find.byType(CupertinoSwitch), findsOneWidget);
final CupertinoSwitch adaptiveSwitch = tester.widget(find.byType(CupertinoSwitch));
expect(adaptiveSwitch.trackColor, inactiveTrackColor, reason: 'on ${describeEnum(platform)}');
final CupertinoSwitch adaptiveSwitch = tester.widget(find.byType(CupertinoSwitch));
expect(adaptiveSwitch.trackColor, inactiveTrackColor);
expect(value, isFalse, reason: 'on ${describeEnum(platform)}');
await tester.tap(find.byType(Switch));
expect(value, isTrue, reason: 'on ${describeEnum(platform)}');
}
expect(value, isFalse);
await tester.tap(find.byType(Switch));
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 {

View File

@ -304,7 +304,9 @@ void main() {
await checkCursorToggle();
});
testWidgets('Cursor animates', (WidgetTester tester) async {
testWidgets('Cursor animates on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(
const MaterialApp(
home: Material(
@ -338,9 +340,13 @@ void main() {
await tester.pump(const Duration(milliseconds: 50));
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(
const MaterialApp(
home: Material(
@ -353,7 +359,9 @@ void main() {
final RenderEditable renderEditable = editableTextState.renderEditable;
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 {
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(
child: const RepaintBoundary(
key: ValueKey<int>(1),
@ -428,13 +438,12 @@ void main() {
await tester.tapAt(textOffsetToPosition(tester, testValue.length));
await tester.pump();
debugDefaultTargetPlatformOverride = null;
await expectLater(
find.byKey(const ValueKey<int>(1)),
matchesGoldenFile(
'text_field_cursor_test_${describeEnum(debugDefaultTargetPlatformOverride).toLowerCase()}.material.1.png',
),
matchesGoldenFile('text_field_cursor_test.material.1.png'),
);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
testWidgets('text field selection toolbar renders correctly inside opacity', (WidgetTester tester) async {
await tester.pumpWidget(
@ -487,13 +496,14 @@ void main() {
);
}, skip: isBrowser);
testWidgets('text field toolbar options correctly changes options',
testWidgets('text field toolbar options correctly changes options (iOS)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -534,9 +544,9 @@ void main() {
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), 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 {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
@ -567,8 +577,10 @@ void main() {
expect(find.text('COPY'), findsOneWidget);
expect(find.text('CUT'), 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 {
EditableText.debugDeterministicCursor = true;
await tester.pumpWidget(
@ -585,10 +597,10 @@ void main() {
await expectLater(
find.byType(TextField),
matchesGoldenFile('text_field_cursor_width_test.0.0.png', version: 0),
matchesGoldenFile('text_field_test.0.0.png'),
);
EditableText.debugDeterministicCursor = false;
}, skip: !isLinux);
}, skip: !Platform.isLinux);
testWidgets('cursor layout has correct radius', (WidgetTester tester) async {
EditableText.debugDeterministicCursor = true;
@ -607,10 +619,11 @@ void main() {
await expectLater(
find.byType(TextField),
matchesGoldenFile('text_field_cursor_width_test.1.0.png', version: 0),
matchesGoldenFile('text_field_test.1.0.png'),
);
EditableText.debugDeterministicCursor = false;
}, skip: !isLinux);
}, skip: !Platform.isLinux);
*/
testWidgets('Overflowing a line with spaces stops the cursor at the end', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();
@ -857,27 +870,6 @@ void main() {
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 {
final TextEditingController controller = TextEditingController();
@ -986,10 +978,11 @@ void main() {
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(
const MaterialApp(
home: Material(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField(
readOnly: true,
),
@ -1005,9 +998,9 @@ void main() {
await tester.pumpAndSettle();
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(
const MaterialApp(
home: Material(
@ -1029,7 +1022,7 @@ void main() {
matching: find.byType(Container),
));
expect(container.size, Size.zero);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia }));
});
testWidgets('Sawping controllers should update selection', (WidgetTester tester) async {
TextEditingController controller = TextEditingController(text: 'readonly');
@ -5507,13 +5500,14 @@ void main() {
});
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 {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -5537,9 +5531,12 @@ void main() {
// But don't trigger the toolbar.
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(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
@ -5568,16 +5565,18 @@ void main() {
// But don't trigger the toolbar.
expect(find.byType(FlatButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia }));
},
);
testWidgets(
'two slow taps do not trigger a word selection',
'two slow taps do not trigger a word selection (iOS)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -5603,16 +5602,18 @@ void main() {
// No toolbar.
expect(find.byType(CupertinoButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
},
);
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 {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -5648,10 +5649,11 @@ void main() {
// Selected text shows 3 toolbar buttons.
expect(find.byType(CupertinoButton), findsNWidgets(3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
},
);
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 {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
@ -5693,10 +5695,11 @@ void main() {
// Selected text shows 4 toolbar buttons: cut, copy, paste, select all
expect(find.byType(FlatButton), findsNWidgets(4));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia }));
},
);
testWidgets(
'double tap on top of cursor also selects word',
'double tap on top of cursor also selects word (Android)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
@ -5742,7 +5745,8 @@ void main() {
// Selected text shows 4 toolbar buttons: cut, copy, paste, select all
expect(find.byType(FlatButton), findsNWidgets(4));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia }));
},
);
testWidgets(
'double double tap just shows the selection menu',
@ -5869,13 +5873,14 @@ void main() {
);
testWidgets(
'double tap hold selects word',
'double tap hold selects word (iOS)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -5913,16 +5918,18 @@ void main() {
);
// The toolbar is still showing.
expect(find.byType(CupertinoButton), findsNWidgets(3));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
},
);
testWidgets(
'tap after a double tap select is not affected',
'tap after a double tap select is not affected (iOS)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -5959,16 +5966,18 @@ void main() {
// No toolbar.
expect(find.byType(CupertinoButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
},
);
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 {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -5992,10 +6001,11 @@ void main() {
// Collapsed toolbar shows 2 buttons.
expect(find.byType(CupertinoButton), findsNWidgets(2));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
},
);
testWidgets(
'long press selects word and shows toolbar',
'long press selects word and shows toolbar (Android)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
@ -6024,16 +6034,18 @@ void main() {
// Collapsed toolbar shows 4 buttons: cut, copy, paste, select all
expect(find.byType(FlatButton), findsNWidgets(4));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia }));
},
);
testWidgets(
'long press tap cannot initiate a double tap',
'long press tap cannot initiate a double tap (iOS)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -6061,16 +6073,18 @@ void main() {
// Collapsed toolbar shows 2 buttons.
expect(find.byType(CupertinoButton), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
},
);
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 {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -6127,14 +6141,16 @@ void main() {
);
// The toolbar now shows up.
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(
text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -6216,16 +6232,17 @@ void main() {
expect(firstCharEndpoint.length, 1);
// The first character is now offscreen to the left.
expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257, epsilon: 1));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
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 {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -6259,16 +6276,18 @@ void main() {
// Long press toolbar.
expect(find.byType(CupertinoButton), findsNWidgets(2));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
},
);
testWidgets(
'double tap after a long tap is not affected',
'double tap after a long tap is not affected (iOS)',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -6300,14 +6319,18 @@ void main() {
const TextSelection(baseOffset: 8, extentOffset: 12),
);
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(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: Center(
child: TextField(
@ -6364,9 +6387,10 @@ void main() {
const TextSelection(baseOffset: 8, extentOffset: 12),
);
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(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
@ -6394,7 +6418,7 @@ void main() {
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.
expect(controller.selection, const TextSelection.collapsed(offset: -1));
@ -6402,14 +6426,15 @@ void main() {
await gesture.up();
await tester.pump();
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(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: TextField(
controller: controller,
@ -6434,15 +6459,7 @@ void main() {
),
);
await gesture.updateWithCustomEvent(
PointerMoveEvent(
pointer: pointerValue,
position: textfieldStart + const Offset(150.0, 9.0),
pressure: 0.5,
pressureMin: 0,
pressureMax: 1,
),
);
await gesture.updateWithCustomEvent(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.
expect(
controller.selection,
@ -6452,15 +6469,15 @@ void main() {
await gesture.up();
await tester.pump();
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(
text: 'Atwater Peel Sherbrooke Bonaventure',
);
await tester.pumpWidget(Container(key: GlobalKey()));
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Material(
child: TextField(
controller: controller,
@ -6486,15 +6503,7 @@ void main() {
),
);
await gesture.updateWithCustomEvent(
PointerMoveEvent(
pointer: pointerValue,
position: textfieldStart + const Offset(150.0, 9.0),
pressure: 0.5,
pressureMin: 0,
pressureMax: 1,
),
);
await gesture.updateWithCustomEvent(PointerMoveEvent(pointer: pointerValue, position: textfieldStart + const Offset(150.0, 9.0), pressure: 0.5, pressureMin: 0, pressureMax: 1));
await gesture.up();
// The event should fallback to a normal tap and move the cursor.
// Single taps selects the edge of the word.
@ -6506,10 +6515,7 @@ void main() {
await tester.pump();
// Single taps shouldn't trigger the toolbar.
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 {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
@ -6916,6 +6922,7 @@ void main() {
});
testWidgets('iOS selection handles are rendered and not faded away', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
const String testText = 'lorem ipsum';
final TextEditingController controller = TextEditingController(text: testText);
@ -6944,7 +6951,9 @@ void main() {
expect(left.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 {
final TextEditingController controller = TextEditingController(

View File

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

View File

@ -21,36 +21,17 @@ void main() {
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', () {
final Typography typography = Typography(platform: TargetPlatform.iOS);
for (final TextTheme textTheme in <TextTheme>[typography.black, typography.white]) {
expect(textTheme.display4, isDisplayFont);
expect(textTheme.display3, isDisplayFont);
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);
}
});
// 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');
test('Typography on macOS defaults to the correct SF font family based on size', () {
final Typography typography = Typography(platform: TargetPlatform.macOS);
final Matcher isTextFont = predicate((TextStyle s) {
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]) {
expect(textTheme.display4, isDisplayFont);
expect(textTheme.display3, isDisplayFont);

View File

@ -502,7 +502,7 @@ void main() {
);
expect(
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 b6 = BorderDirectional(top: magenta6);

View File

@ -97,7 +97,7 @@ void main() {
);
expect(
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 b6 = Border(top: magenta6);

View File

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

View File

@ -175,7 +175,7 @@ void main() {
test('EdgeInsetsGeometry operators', () {
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(0.5, 1.0, 1.5, 2.5));
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', () {
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;
final ImageStreamCompleter result = imageCache.putIfAbsent(errorImage, () => errorImage.load(errorImage, null), onError: (dynamic error, StackTrace stackTrace) {
caughtError = true;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -148,7 +148,7 @@ void _testPaintingContextLayerReuse<L extends Layer>(_LayerTestPaintCallback pai
box.markNeedsPaint();
pumpFrame(phase: EnginePhase.paint);
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]));
}

View File

@ -81,25 +81,21 @@ void main() {
});
test('RenderPhysicalModel compositing on non-Fuchsia', () {
for (final TargetPlatform platform in TargetPlatform.values) {
if (platform == TargetPlatform.fuchsia) {
continue;
}
debugDefaultTargetPlatformOverride = platform;
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final RenderPhysicalModel root = RenderPhysicalModel(color: const Color(0xffff00ff));
layout(root, phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
final RenderPhysicalModel root = RenderPhysicalModel(color: const Color(0xffff00ff));
layout(root, phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
// Flutter now composites physical shapes on all platforms.
root.elevation = 1.0;
pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
// Flutter now composites physical shapes on all platforms.
root.elevation = 1.0;
pumpFrame(phase: EnginePhase.composite);
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;
});
@ -125,53 +121,44 @@ void main() {
});
group('RenderPhysicalShape', () {
setUp(() {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
});
test('shape change triggers repaint', () {
for (final TargetPlatform platform in TargetPlatform.values) {
if (platform == TargetPlatform.fuchsia) {
continue;
}
debugDefaultTargetPlatformOverride = platform;
final RenderPhysicalShape root = RenderPhysicalShape(
color: const Color(0xffff00ff),
clipper: const ShapeBorderClipper(shape: CircleBorder()),
);
layout(root, phase: EnginePhase.composite);
expect(root.debugNeedsPaint, isFalse);
final RenderPhysicalShape root = RenderPhysicalShape(
color: const Color(0xffff00ff),
clipper: const ShapeBorderClipper(shape: CircleBorder()),
);
layout(root, phase: EnginePhase.composite);
expect(root.debugNeedsPaint, isFalse);
// Same shape, no repaint.
root.clipper = const ShapeBorderClipper(shape: CircleBorder());
expect(root.debugNeedsPaint, isFalse);
// Same shape, no repaint.
root.clipper = const ShapeBorderClipper(shape: CircleBorder());
expect(root.debugNeedsPaint, isFalse);
// Different shape triggers repaint.
root.clipper = const ShapeBorderClipper(shape: StadiumBorder());
expect(root.debugNeedsPaint, isTrue);
}
debugDefaultTargetPlatformOverride = null;
// Different shape triggers repaint.
root.clipper = const ShapeBorderClipper(shape: StadiumBorder());
expect(root.debugNeedsPaint, isTrue);
});
test('compositing on non-Fuchsia', () {
for (final TargetPlatform platform in TargetPlatform.values) {
if (platform == TargetPlatform.fuchsia) {
continue;
}
debugDefaultTargetPlatformOverride = platform;
final RenderPhysicalShape root = RenderPhysicalShape(
color: const Color(0xffff00ff),
clipper: const ShapeBorderClipper(shape: CircleBorder()),
);
layout(root, phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
final RenderPhysicalShape root = RenderPhysicalShape(
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
root.elevation = 1.0;
pumpFrame(phase: EnginePhase.composite);
expect(root.needsCompositing, isTrue);
// On non-Fuchsia platforms, we composite physical shape layers
root.elevation = 1.0;
pumpFrame(phase: EnginePhase.composite);
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;
});
});
@ -467,6 +454,18 @@ void main() {
// transform -> clip
_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> {
@ -503,7 +502,7 @@ void _testLayerReuse<L extends Layer>(RenderBox renderObject) {
expect(renderObject.debugLayer, null);
layout(renderObject, phase: EnginePhase.paint, constraints: BoxConstraints.tight(const Size(10, 10)));
final Layer layer = renderObject.debugLayer;
expect(layer, isA<L>());
expect(layer, isInstanceOf<L>());
expect(layer, isNotNull);
// Mark for repaint otherwise pumpFrame is a noop.
@ -523,3 +522,18 @@ class _TestPathClipper extends CustomClipper<Path> {
@override
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,
);
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', () {
@ -80,7 +80,7 @@ void main() {
child: compositedBox,
);
layout(opacity, phase: EnginePhase.flushSemantics);
expect(compositedBox.debugLayer, isA<OpacityLayer>());
expect(compositedBox.debugLayer, isInstanceOf<OpacityLayer>());
});
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
final TargetPlatform oldTargetPlatform = debugDefaultTargetPlatformOverride;
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
@ -1175,5 +1177,6 @@ void main() {
expect(find.text('b'), findsOneWidget);
await tester.drag(find.text('b'), const Offset(0, 200));
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.diagnostics.length, 3);
expect(error.diagnostics.last, isA<DiagnosticsProperty<Ticker>>());
expect(error.diagnostics.last, isInstanceOf<DiagnosticsProperty<Ticker>>());
expect(
error.toStringDeep(),
startsWith(

View File

@ -68,7 +68,7 @@ void main() {
}
expect(error, isNotNull);
expect(error.diagnostics.length, 2);
expect(error.diagnostics.last, isA<IntProperty>());
expect(error.diagnostics.last, isInstanceOf<IntProperty>());
expect(
error.toStringDeep(),
'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']);
});
@ -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'});
});
@ -292,7 +292,7 @@ void main() {
await Future<void>.delayed(Duration.zero);
expect(events, isEmpty);
expect(errors, hasLength(1));
expect(errors[0], isA<PlatformException>());
expect(errors[0], isInstanceOf<PlatformException>());
final PlatformException error = errors[0] as PlatformException;
expect(error.code, '404');
expect(error.message, 'Not Found.');

View File

@ -27,7 +27,7 @@ void main() {
layoutDirection: TextDirection.ltr,
).setSize(const Size(100.0, 100.0));
},
throwsA(isA<PlatformException>()),
throwsA(isInstanceOf<PlatformException>()),
);
});
@ -55,7 +55,7 @@ void main() {
expect(
() => PlatformViewsService.initAndroidView(
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 {
@ -170,7 +170,7 @@ void main() {
layoutDirection: TextDirection.ltr,
);
},
throwsA(isA<PlatformException>()),
throwsA(isInstanceOf<PlatformException>()),
);
});
@ -199,7 +199,7 @@ void main() {
expect(
() => PlatformViewsService.initUiKitView(
id: 0, viewType: 'web', layoutDirection: TextDirection.ltr),
throwsA(isA<PlatformException>()),
throwsA(isInstanceOf<PlatformException>()),
);
});
@ -228,7 +228,7 @@ void main() {
() async {
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'
),
);
expect(error.diagnostics[3], isA<DiagnosticsProperty<Element>>());
expect(error.diagnostics[3], isInstanceOf<DiagnosticsProperty<Element>>());
expect(
error.toStringDeep(),
equalsIgnoringHashCodes(

View File

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

View File

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

View File

@ -74,7 +74,7 @@ void main() {
} finally {
expect(error, isNotNull);
expect(error.diagnostics.length, 4);
expect(error.diagnostics[2], isA<DiagnosticsProperty<Element>>());
expect(error.diagnostics[2], isInstanceOf<DiagnosticsProperty<Element>>());
expect(
error.toStringDeep(),
equalsIgnoringHashCodes(
@ -106,7 +106,7 @@ void main() {
} finally {
expect(error, isNotNull);
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.toStringDeep(),
@ -147,7 +147,7 @@ void main() {
} finally {
expect(error, isNotNull);
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].toStringDeep(),
@ -190,7 +190,7 @@ void main() {
} finally {
expect(error, isNotNull);
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].toStringDeep(),

View File

@ -105,7 +105,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), 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 {
await tester.pumpWidget(_boilerplate(null));
@ -118,7 +118,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), 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 {
await tester.pumpWidget(_boilerplate(null, itemCount: 30, initialChildSize: .25));
@ -135,7 +135,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.text('Item 1').hitTestable(), findsOneWidget);
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 {
int taps = 0;
@ -164,7 +164,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 18'), findsOneWidget);
expect(find.text('Item 36'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all());
}, skip: isBrowser);
testWidgets('Can be flung up gently', (WidgetTester tester) async {
int taps = 0;
@ -187,7 +187,7 @@ void main() {
expect(find.text('Item 21'), findsOneWidget);
expect(find.text('Item 36'), findsOneWidget);
expect(find.text('Item 70'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all());
}, skip: isBrowser);
testWidgets('Can be flung up', (WidgetTester tester) async {
int taps = 0;
@ -208,7 +208,7 @@ void main() {
expect(find.text('Item 1'), findsNothing);
expect(find.text('Item 21'), findsNothing);
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 {
await tester.pumpWidget(_boilerplate(null));
@ -221,7 +221,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), 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 {
int taps = 0;
@ -260,7 +260,7 @@ void main() {
expect(find.text('Item 1'), findsOneWidget);
expect(find.text('Item 21'), findsNothing);
expect(find.text('Item 70'), findsNothing);
}, skip: isBrowser, variant: TargetPlatformVariant.all());
}, skip: isBrowser);
debugDefaultTargetPlatformOverride = null;
});

View File

@ -304,7 +304,9 @@ void main() {
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 GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
@ -329,7 +331,9 @@ void main() {
expect(semantics, includesNodeWith(label: 'Dismiss'));
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 {
final SemanticsTester semantics = SemanticsTester(tester);
@ -357,7 +361,7 @@ void main() {
expect(semantics, isNot(includesNodeWith(label: 'Dismiss')));
semantics.dispose();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android }));
});
testWidgets('Drawer contains route semantics flags', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);

View File

@ -145,9 +145,10 @@ void main() {
);
});
testWidgets('Cursor animates', (WidgetTester tester) async {
const Widget widget = MaterialApp(
home: Material(
testWidgets('Cursor animates on iOS', (WidgetTester tester) async {
final Widget widget = MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField(
maxLines: 3,
),
@ -199,7 +200,7 @@ void main() {
// Cursor starts coming back.
expect(renderEditable.cursorColor.alpha, 79);
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 {
const Widget widget = MaterialApp(
@ -240,10 +241,11 @@ void main() {
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;
const Widget widget = MaterialApp(
home: Material(
final Widget widget = MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField(
maxLines: 3,
),
@ -275,7 +277,7 @@ void main() {
expect(renderEditable, paints..rrect(color: const Color(0xff2196f3)));
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 {
EditableText.debugDeterministicCursor = true;
@ -344,9 +346,10 @@ void main() {
expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0));
});
testWidgets('Cursor radius is 2.0', (WidgetTester tester) async {
const Widget widget = MaterialApp(
home: Material(
testWidgets('Cursor radius is 2.0 on iOS', (WidgetTester tester) async {
final Widget widget = MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: const Material(
child: TextField(
maxLines: 3,
),
@ -358,7 +361,7 @@ void main() {
final RenderEditable renderEditable = editableTextState.renderEditable;
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 {
const String text = 'hello world this is fun and cool and awesome!';
@ -642,7 +645,9 @@ void main() {
expect(controller.selection.baseOffset, text.length);
}, 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();
const TextStyle textStyle = TextStyle();
const String text = 'hello world this is fun and cool and awesome!';
@ -651,6 +656,7 @@ void main() {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Padding(
padding: const EdgeInsets.only(top: 0.25),
child: Material(
@ -725,13 +731,16 @@ void main() {
editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.End));
await tester.pumpAndSettle();
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>();
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
String changedValue;
final Widget widget = MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: RepaintBoundary(
key: const ValueKey<int>(1),
child: Column(
@ -742,7 +751,7 @@ void main() {
key: editableTextKey,
controller: TextEditingController(),
focusNode: FocusNode(),
style: Typography(platform: debugDefaultTargetPlatformOverride).black.subhead,
style: Typography(platform: TargetPlatform.iOS).black.subhead,
cursorColor: Colors.blue,
selectionControls: materialTextSelectionControls,
keyboardType: TextInputType.text,
@ -784,5 +793,6 @@ void main() {
find.byKey(const ValueKey<int>(1)),
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
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.
const String testText = 'XXXXX XXXXX';
final TextEditingController controller = TextEditingController(text: testText);
@ -3772,7 +3774,7 @@ void main() {
showSelectionHandles: true,
controller: controller,
focusNode: FocusNode(),
style: Typography(platform: debugDefaultTargetPlatformOverride).black.subhead,
style: Typography(platform: TargetPlatform.iOS).black.subhead,
cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey,
selectionControls: cupertinoTextSelectionControls,
@ -3922,7 +3924,9 @@ void main() {
// at all. Again, both handles should be invisible.
scrollable.controller.jumpTo(0);
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 {
// 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;
while (layer != null && layer is! OpacityLayer)
layer = layer.firstChild as ContainerLayer;
expect(layer, isA<OpacityLayer>());
expect(layer, isInstanceOf<OpacityLayer>());
final OpacityLayer opacityLayer = layer as OpacityLayer;
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;
expect(error.diagnostics.length, 3);
final DiagnosticsNode last = error.diagnostics.last;
expect(last, isA<DiagnosticsProperty<StatefulElement>>());
expect(last, isInstanceOf<DiagnosticsProperty<StatefulElement>>());
expect(
last.toStringDeep(),
equalsIgnoringHashCodes(
@ -1614,7 +1614,10 @@ Future<void> main() async {
testWidgets('Heroes do not transition on back gestures by default', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
routes: routes,
theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes,
));
expect(find.byKey(firstKey), isOnstage);
@ -1649,11 +1652,14 @@ Future<void> main() async {
expect(find.byKey(firstKey), isInCard);
expect(find.byKey(secondKey), isOnstage);
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 {
transitionFromUserGestures = true;
await tester.pumpWidget(MaterialApp(
theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes,
));
@ -1692,11 +1698,14 @@ Future<void> main() async {
expect(find.byKey(firstKey), isOnstage);
expect(find.byKey(firstKey), isInCard);
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 {
transitionFromUserGestures = true;
await tester.pumpWidget(MaterialApp(
theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes,
));
@ -1728,7 +1737,7 @@ Future<void> main() async {
expect(find.byKey(firstKey), findsNothing);
expect(find.byKey(secondKey), isOnstage);
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 {
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 {
transitionFromUserGestures = true;
await tester.pumpWidget(MaterialApp(
theme: ThemeData(
platform: TargetPlatform.iOS,
),
routes: routes,
));
@ -2312,7 +2324,7 @@ Future<void> main() async {
// The simple route should still be on top.
expect(find.byKey(simpleKey), findsOneWidget);
expect(tester.takeException(), isNull);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
// Regression test for https://github.com/flutter/flutter/issues/40239.
testWidgets(

View File

@ -1101,14 +1101,14 @@ void main() {
expect(find.byType(Center), findsOneWidget);
expect(find.byType(Padding), 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));
await tester.pump();
expect(find.byType(Center), findsOneWidget);
expect(find.byType(Padding), findsOneWidget);
expect(find.byType(RawImage), findsOneWidget);
expect(tester.widget<Center>(find.byType(Center)).child, isA<Padding>());
expect(tester.widget<Padding>(find.byType(Padding)).child, isA<RawImage>());
expect(tester.widget<Center>(find.byType(Center)).child, isInstanceOf<Padding>());
expect(tester.widget<Padding>(find.byType(Padding)).child, isInstanceOf<RawImage>());
}, skip: isBrowser);
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 {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final FixedExtentScrollController controller = FixedExtentScrollController(initialItem: 40);
final List<double> scrolledPositions = <double>[];
@ -1250,7 +1252,9 @@ void main() {
expect(controller.selectedItem, 49);
// More importantly, lands tightly on 49.
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 {

View File

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

View File

@ -340,6 +340,8 @@ void main() {
});
testWidgets('Dismissible ModalBarrier includes button in semantic tree on iOS', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr,
@ -362,7 +364,8 @@ void main() {
expect(semantics, hasSemantics(expectedSemantics, ignoreId: true));
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 {
final SemanticsTester semantics = SemanticsTester(tester);

View File

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

View File

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

View File

@ -113,6 +113,7 @@ Widget buildTest({ ScrollController controller, String title = 'TTTTTTTT' }) {
void main() {
testWidgets('NestedScrollView overscroll and release and hold', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget);
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,
// the following expectation should switch to 200.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 {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 250));
@ -146,8 +149,10 @@ void main() {
await tester.pump(const Duration(milliseconds: 10));
expect(find.text('aaa2'), findsNothing);
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 {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 500));
@ -159,10 +164,8 @@ void main() {
await gesture1.up();
await tester.pumpAndSettle();
expect(find.text('aaa2'), findsOneWidget);
},
skip: true, // https://github.com/flutter/flutter/issues/9040
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
}, skip: true); // https://github.com/flutter/flutter/issues/9040
testWidgets('NestedScrollView', (WidgetTester tester) async {
await tester.pumpWidget(buildTest());
expect(find.text('aaa2'), findsOneWidget);
@ -607,11 +610,12 @@ void main() {
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
// 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
// positions of the inner and outer list don't have a discontinuity.
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
const Key key1 = ValueKey<int>(1);
const Key key2 = ValueKey<int>(2);
await tester.pumpWidget(
@ -670,7 +674,8 @@ void main() {
await tester.pump();
expect(tester.getRect(find.byKey(key1)), const Rect.fromLTWH(0.0, 0.0, 800.0, 100.0));
await gesture.up();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
debugDefaultTargetPlatformOverride = null;
});
}
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'
'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[4], isA<DiagnosticsProperty<Element>>());
expect(error.diagnostics[4], isInstanceOf<DiagnosticsProperty<Element>>());
expect(error.toStringDeep(), equalsIgnoringHashCodes(
'FlutterError\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');
@ -196,7 +199,7 @@ void main() {
settingsOffset = tester.getTopLeft(find.text('Settings'));
expect(settingsOffset.dx, greaterThan(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 {
final GlobalKey containerKey1 = GlobalKey();
@ -206,7 +209,10 @@ void main() {
'/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');
@ -239,7 +245,7 @@ void main() {
expect(find.text('Home'), isOnstage);
expect(find.text('Settings'), findsNothing);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
// Tests bug https://github.com/flutter/flutter/issues/6451
testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async {
@ -250,7 +256,10 @@ void main() {
'/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');
@ -293,7 +302,7 @@ void main() {
// Sheet did not call setState (since the gesture did nothing).
expect(sheet.setStateCalled, isFalse);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
});
testWidgets('Test completed future', (WidgetTester tester) async {
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 {
await tester.pumpWidget(MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: PageView(
children: List<Widget>.generate(10, (int i) {
return Container(
@ -112,7 +113,7 @@ void main() {
expect(leftOf(0), lessThan(0.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 {
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)
);
expect(element, isNotNull);
expect(element.renderObject, isA<RenderStack>());
expect(element.renderObject is RenderStack, isTrue);
final RenderStack renderObject = element.renderObject as RenderStack;
try {
RenderObject child = renderObject.firstChild;
for (final TestParentData expected in expectedParentData) {
expect(child, isA<RenderDecoratedBox>());
expect(child is RenderDecoratedBox, isTrue);
final RenderDecoratedBox decoratedBox = child as RenderDecoratedBox;
expect(decoratedBox.parentData, isA<StackParentData>());
expect(decoratedBox.parentData is StackParentData, isTrue);
final StackParentData parentData = decoratedBox.parentData as StackParentData;
expect(parentData.top, equals(expected.top));
expect(parentData.right, equals(expected.right));

View File

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

View File

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

View File

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

View File

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

View File

@ -47,7 +47,7 @@ void main() {
expect(behavior, isNotNull);
expect(behavior.flag, isTrue);
expect(position.physics, isA<ClampingScrollPhysics>());
expect(position.physics, isInstanceOf<ClampingScrollPhysics>());
ScrollMetrics metrics = position.copyWith();
expect(metrics.extentAfter, equals(400.0));
expect(metrics.viewportDimension, equals(600.0));
@ -62,7 +62,7 @@ void main() {
expect(behavior, isNotNull);
expect(behavior.flag, isFalse);
expect(position.physics, isA<BouncingScrollPhysics>());
expect(position.physics, isInstanceOf<BouncingScrollPhysics>());
// Regression test for https://github.com/flutter/flutter/issues/5856
metrics = position.copyWith();
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));
await tester.pump(const Duration(seconds: 1));
expect(notification, isA<ScrollStartNotification>());
expect(notification, isInstanceOf<ScrollStartNotification>());
expect(notification.depth, equals(0));
final ScrollStartNotification start = notification as ScrollStartNotification;
expect(start.dragDetails, isNotNull);
@ -32,7 +32,7 @@ void main() {
await gesture.moveBy(const Offset(-10.0, -10.0));
await tester.pump(const Duration(seconds: 1));
expect(notification, isA<ScrollUpdateNotification>());
expect(notification, isInstanceOf<ScrollUpdateNotification>());
expect(notification.depth, equals(0));
final ScrollUpdateNotification update = notification as ScrollUpdateNotification;
expect(update.dragDetails, isNotNull);
@ -41,7 +41,7 @@ void main() {
await gesture.up();
await tester.pump(const Duration(seconds: 1));
expect(notification, isA<ScrollEndNotification>());
expect(notification, isInstanceOf<ScrollEndNotification>());
expect(notification.depth, equals(0));
final ScrollEndNotification end = notification as ScrollEndNotification;
expect(end.dragDetails, isNotNull);

View File

@ -239,10 +239,10 @@ void main() {
} finally {
expect(error, isNotNull);
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].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].value, position);
// 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 {
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 {
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 {
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 {
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 {
@ -459,7 +459,7 @@ void main() {
// A separatorBuilder that returns null throws a FlutterError
await tester.pumpWidget(buildFrame(null));
expect(tester.takeException(), isFlutterError);
expect(tester.takeException(), isInstanceOf<FlutterError>());
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
await tester.pumpWidget(buildFrame(true));
expect(tester.takeException(), isA<Exception>());
expect(tester.takeException(), isInstanceOf<Exception>());
expect(finder, findsOneWidget);
});
@ -556,7 +556,7 @@ void main() {
// When it does throw, one error widget is rendered in the separator's place
await tester.pumpWidget(buildFrame(true));
expect(tester.takeException(), isA<Exception>());
expect(tester.takeException(), isInstanceOf<Exception>());
expect(finder, findsOneWidget);
});
@ -566,7 +566,7 @@ void main() {
return const SizedBox();
},
itemCount: -1,
), throwsAssertionError);
), throwsA(isInstanceOf<AssertionError>()));
});
testWidgets('ListView.builder asserts on negative semanticChildCount', (WidgetTester tester) async {
@ -576,7 +576,7 @@ void main() {
},
itemCount: 1,
semanticChildCount: -1,
), throwsAssertionError);
), throwsA(isInstanceOf<AssertionError>()));
});
testWidgets('ListView.builder asserts on nonsensical childCount/semanticChildCount', (WidgetTester tester) async {
@ -586,6 +586,6 @@ void main() {
},
itemCount: 1,
semanticChildCount: 4,
), throwsAssertionError);
), throwsA(isInstanceOf<AssertionError>()));
});
}

View File

@ -28,9 +28,10 @@ void main() {
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.
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
final ScrollController controller = ScrollController();
final Key outterContainer = GlobalKey();
@ -87,5 +88,7 @@ void main() {
);
await tester.pumpAndSettle();
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