mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[a11y] Make sure RenderFractionalTranslation updates its semantics after the translation field is set (#48985)
This commit is contained in:
parent
fcf341e4f3
commit
b67d5ec6e9
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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>();
|
||||
|
@ -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>();
|
||||
|
@ -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
|
||||
|
@ -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', () {
|
||||
|
@ -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(
|
||||
|
@ -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].
|
||||
|
@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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].
|
||||
|
@ -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) {
|
||||
|
@ -2472,6 +2472,7 @@ class RenderFractionalTranslation extends RenderProxyBox {
|
||||
return;
|
||||
_translation = value;
|
||||
markNeedsPaint();
|
||||
markNeedsSemanticsUpdate();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -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>>());
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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>()));
|
||||
});
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
},
|
||||
);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -1449,7 +1449,7 @@ void main() {
|
||||
),
|
||||
),
|
||||
);
|
||||
}, throwsAssertionError);
|
||||
}, throwsA(isInstanceOf<AssertionError>()));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
|
@ -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));
|
||||
|
@ -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(),
|
||||
|
@ -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",
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 }));
|
||||
});
|
||||
}
|
||||
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
@ -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'));
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
@ -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'
|
||||
|
@ -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 }));
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -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 }));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -196,7 +196,6 @@ void main() {
|
||||
const PageTransitionsTheme pageTransitionTheme = PageTransitionsTheme(
|
||||
builders: <TargetPlatform, PageTransitionsBuilder>{
|
||||
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
||||
TargetPlatform.macOS: CupertinoPageTransitionsBuilder(),
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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', () {
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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)),
|
||||
);
|
||||
|
@ -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'
|
||||
|
@ -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', () {
|
||||
|
@ -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());
|
||||
|
@ -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', () {
|
||||
|
@ -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]));
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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', () {
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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'
|
||||
|
@ -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.');
|
||||
|
@ -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>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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>());
|
||||
});
|
||||
}
|
||||
|
@ -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', () {
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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>());
|
||||
});
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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'
|
||||
|
@ -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>{
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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>()));
|
||||
});
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user