| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // 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/widgets.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| void main() { |
| Widget _boilerplate(VoidCallback onButtonPressed, { |
| int itemCount = 100, |
| double initialChildSize = .5, |
| double maxChildSize = 1.0, |
| double minChildSize = .25, |
| double itemExtent, |
| Key containerKey, |
| NotificationListenerCallback<ScrollNotification> onScrollNotification, |
| }) { |
| return Directionality( |
| textDirection: TextDirection.ltr, |
| child: Stack( |
| children: <Widget>[ |
| FlatButton( |
| child: const Text('TapHere'), |
| onPressed: onButtonPressed, |
| ), |
| DraggableScrollableSheet( |
| maxChildSize: maxChildSize, |
| minChildSize: minChildSize, |
| initialChildSize: initialChildSize, |
| builder: (BuildContext context, ScrollController scrollController) { |
| return NotificationListener<ScrollNotification>( |
| onNotification: onScrollNotification, |
| child: Container( |
| key: containerKey, |
| color: const Color(0xFFABCDEF), |
| child: ListView.builder( |
| controller: scrollController, |
| itemExtent: itemExtent, |
| itemCount: itemCount, |
| itemBuilder: (BuildContext context, int index) => Text('Item $index'), |
| ), |
| ), |
| ); |
| }, |
| ), |
| ], |
| ), |
| ); |
| } |
| |
| testWidgets('Scrolls correct amount when maxChildSize < 1.0', (WidgetTester tester) async { |
| const Key key = ValueKey<String>('container'); |
| await tester.pumpWidget(_boilerplate( |
| null, |
| maxChildSize: .6, |
| initialChildSize: .25, |
| itemExtent: 25.0, |
| containerKey: key, |
| )); |
| |
| expect(tester.getRect(find.byKey(key)), const Rect.fromLTRB(0.0, 450.0, 800.0, 600.0)); |
| await tester.drag(find.text('Item 5'), const Offset(0, -125)); |
| await tester.pumpAndSettle(); |
| expect(tester.getRect(find.byKey(key)), const Rect.fromLTRB(0.0, 325.0, 800.0, 600.0)); |
| }); |
| |
| testWidgets('Scrolls correct amount when maxChildSize == 1.0', (WidgetTester tester) async { |
| const Key key = ValueKey<String>('container'); |
| await tester.pumpWidget(_boilerplate( |
| null, |
| maxChildSize: 1.0, |
| initialChildSize: .25, |
| itemExtent: 25.0, |
| containerKey: key, |
| )); |
| |
| expect(tester.getRect(find.byKey(key)), const Rect.fromLTRB(0.0, 450.0, 800.0, 600.0)); |
| await tester.drag(find.text('Item 5'), const Offset(0, -125)); |
| await tester.pumpAndSettle(); |
| expect(tester.getRect(find.byKey(key)), const Rect.fromLTRB(0.0, 325.0, 800.0, 600.0)); |
| }); |
| |
| for (final TargetPlatform platform in TargetPlatform.values) { |
| group('$platform Scroll Physics', () { |
| debugDefaultTargetPlatformOverride = platform; |
| |
| testWidgets('Can be dragged up without covering its container', (WidgetTester tester) async { |
| int taps = 0; |
| await tester.pumpWidget(_boilerplate(() => taps++)); |
| |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 31'), findsNothing); |
| |
| await tester.drag(find.text('Item 1'), const Offset(0, -200)); |
| await tester.pumpAndSettle(); |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 2); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 31'), findsOneWidget); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| testWidgets('Can be dragged down when not full height', (WidgetTester tester) async { |
| await tester.pumpWidget(_boilerplate(null)); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 36'), findsNothing); |
| |
| await tester.drag(find.text('Item 1'), const Offset(0, 325)); |
| await tester.pumpAndSettle(); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsNothing); |
| expect(find.text('Item 36'), findsNothing); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| testWidgets('Can be dragged down when list is shorter than full height', (WidgetTester tester) async { |
| await tester.pumpWidget(_boilerplate(null, itemCount: 30, initialChildSize: .25)); |
| |
| expect(find.text('Item 1').hitTestable(), findsOneWidget); |
| expect(find.text('Item 29').hitTestable(), findsNothing); |
| |
| await tester.drag(find.text('Item 1'), const Offset(0, -325)); |
| await tester.pumpAndSettle(); |
| expect(find.text('Item 1').hitTestable(), findsOneWidget); |
| expect(find.text('Item 29').hitTestable(), findsOneWidget); |
| |
| await tester.drag(find.text('Item 1'), const Offset(0, 325)); |
| await tester.pumpAndSettle(); |
| expect(find.text('Item 1').hitTestable(), findsOneWidget); |
| expect(find.text('Item 29').hitTestable(), findsNothing); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| 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; |
| await tester.pumpWidget(_boilerplate(() => taps++)); |
| |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 36'), findsNothing); |
| |
| await tester.drag(find.text('Item 1'), const Offset(0, -325)); |
| await tester.pumpAndSettle(); |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 36'), findsOneWidget); |
| |
| await tester.dragFrom(const Offset(20, 20), const Offset(0, 325)); |
| await tester.pumpAndSettle(); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 2); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 18'), findsOneWidget); |
| expect(find.text('Item 36'), findsNothing); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| testWidgets('Can be flung up gently', (WidgetTester tester) async { |
| int taps = 0; |
| await tester.pumpWidget(_boilerplate(() => taps++)); |
| |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 36'), findsNothing); |
| expect(find.text('Item 70'), findsNothing); |
| |
| await tester.fling(find.text('Item 1'), const Offset(0, -200), 350); |
| await tester.pumpAndSettle(); |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 2); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 36'), findsOneWidget); |
| expect(find.text('Item 70'), findsNothing); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| testWidgets('Can be flung up', (WidgetTester tester) async { |
| int taps = 0; |
| await tester.pumpWidget(_boilerplate(() => taps++)); |
| |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 70'), findsNothing); |
| |
| await tester.fling(find.text('Item 1'), const Offset(0, -200), 2000); |
| await tester.pumpAndSettle(); |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsNothing); |
| expect(find.text('Item 21'), findsNothing); |
| expect(find.text('Item 70'), findsOneWidget); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| testWidgets('Can be flung down when not full height', (WidgetTester tester) async { |
| await tester.pumpWidget(_boilerplate(null)); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 36'), findsNothing); |
| |
| await tester.fling(find.text('Item 1'), const Offset(0, 325), 2000); |
| await tester.pumpAndSettle(); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsNothing); |
| expect(find.text('Item 36'), findsNothing); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| testWidgets('Can be flung up and then back down', (WidgetTester tester) async { |
| int taps = 0; |
| await tester.pumpWidget(_boilerplate(() => taps++)); |
| |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 70'), findsNothing); |
| |
| await tester.fling(find.text('Item 1'), const Offset(0, -200), 2000); |
| await tester.pumpAndSettle(); |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsNothing); |
| expect(find.text('Item 21'), findsNothing); |
| expect(find.text('Item 70'), findsOneWidget); |
| |
| await tester.fling(find.text('Item 70'), const Offset(0, 200), 2000); |
| await tester.pumpAndSettle(); |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 1); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsOneWidget); |
| expect(find.text('Item 70'), findsNothing); |
| |
| await tester.fling(find.text('Item 1'), const Offset(0, 200), 2000); |
| await tester.pumpAndSettle(); |
| expect(find.text('TapHere'), findsOneWidget); |
| await tester.tap(find.text('TapHere')); |
| expect(taps, 2); |
| expect(find.text('Item 1'), findsOneWidget); |
| expect(find.text('Item 21'), findsNothing); |
| expect(find.text('Item 70'), findsNothing); |
| }, skip: isBrowser, variant: TargetPlatformVariant.all()); |
| |
| debugDefaultTargetPlatformOverride = null; |
| }); |
| |
| testWidgets('ScrollNotification correctly dispatched when flung without covering its container', (WidgetTester tester) async { |
| final List<Type> notificationTypes = <Type>[]; |
| await tester.pumpWidget(_boilerplate( |
| null, |
| onScrollNotification: (ScrollNotification notification) { |
| notificationTypes.add(notification.runtimeType); |
| return false; |
| }, |
| )); |
| |
| await tester.fling(find.text('Item 1'), const Offset(0, -200), 200); |
| await tester.pumpAndSettle(); |
| |
| // TODO(itome): Make sure UserScrollNotification and ScrollUpdateNotification are called correctly. |
| final List<Type> types = <Type>[ |
| ScrollStartNotification, |
| ScrollEndNotification, |
| ]; |
| expect(notificationTypes, equals(types)); |
| }); |
| |
| testWidgets('ScrollNotification correctly dispatched when flung with contents scroll', (WidgetTester tester) async { |
| final List<Type> notificationTypes = <Type>[]; |
| await tester.pumpWidget(_boilerplate( |
| null, |
| onScrollNotification: (ScrollNotification notification) { |
| notificationTypes.add(notification.runtimeType); |
| return false; |
| }, |
| )); |
| |
| await tester.flingFrom(const Offset(0, 325), const Offset(0, -325), 200); |
| await tester.pumpAndSettle(); |
| |
| final List<Type> types = <Type>[ |
| ScrollStartNotification, |
| UserScrollNotification, |
| ...List<Type>.filled(5, ScrollUpdateNotification), |
| ScrollEndNotification, |
| UserScrollNotification, |
| ]; |
| expect(notificationTypes, types); |
| }); |
| } |
| } |