Unverified Commit 0629030a authored by Ming Lyu (CareF)'s avatar Ming Lyu (CareF) Committed by GitHub

WidgetTester.drag with time duration (#63410)

parent 4ad90c4d
// 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/gestures.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:macrobenchmarks/common.dart';
import 'util.dart';
void main() {
macroPerfTestE2E(
'picture_cache_perf',
kPictureCacheRouteName,
pageDelay: const Duration(seconds: 1),
body: (WidgetController controller) async {
final Finder nestedScroll = find.byKey(const ValueKey<String>('tabbar_view'));
expect(nestedScroll, findsOneWidget);
Future<void> _scrollOnce(double offset) async {
await controller.timedDrag(
nestedScroll,
Offset(-offset, 0.0),
const Duration(milliseconds: 300),
);
await Future<void>.delayed(const Duration(milliseconds: 500));
}
for (int i = 0; i < 3; i += 1) {
await _scrollOnce(-300.0);
await _scrollOnce(-300.0);
await _scrollOnce(300.0);
await _scrollOnce(300.0);
}
},
);
}
// 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 'dart:async';
import 'package:flutter_devicelab/tasks/perf_tests.dart';
import 'package:flutter_devicelab/framework/adb.dart';
import 'package:flutter_devicelab/framework/framework.dart';
Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.android;
await task(createPictureCachePerfE2ETest());
}
......@@ -158,6 +158,13 @@ TaskFunction createPictureCachePerfTest() {
).run;
}
TaskFunction createPictureCachePerfE2ETest() {
return E2EPerfTest(
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
'test/picture_cache_perf_e2e.dart',
).run;
}
TaskFunction createFlutterGalleryStartupTest() {
return StartupTest(
'${flutterDirectory.path}/dev/integration_tests/flutter_gallery',
......
......@@ -190,6 +190,13 @@ tasks:
stage: devicelab
required_agent_capabilities: ["mac/android"]
picture_cache_perf__e2e_summary:
description: >
Measures the runtime performance of raster caching many pictures on Android.
stage: devicelab
required_agent_capabilities: ["linux/android"]
flaky: true
cubic_bezier_perf__timeline_summary:
description: >
Measures the runtime performance of cubic bezier animations on Android.
......
......@@ -476,6 +476,9 @@ abstract class WidgetController {
/// If you want the drag to end with a speed so that the gesture recognition
/// system identifies the gesture as a fling, consider using [fling] instead.
///
/// The operation happens at once. If you want the drag to last for a period
/// of time, consider using [timedDrag].
///
/// {@template flutter.flutter_test.drag}
/// By default, if the x or y component of offset is greater than
/// [kDragSlopDefault], the gesture is broken up into two separate moves
......@@ -501,7 +504,6 @@ abstract class WidgetController {
double touchSlopX = kDragSlopDefault,
double touchSlopY = kDragSlopDefault,
}) {
assert(kDragSlopDefault > kTouchSlop);
return dragFrom(
getCenter(finder),
offset,
......@@ -519,6 +521,9 @@ abstract class WidgetController {
/// system identifies the gesture as a fling, consider using [flingFrom]
/// instead.
///
/// The operation happens at once. If you want the drag to last for a period
/// of time, consider using [timedDragFrom].
///
/// {@macro flutter.flutter_test.drag}
Future<void> dragFrom(
Offset startLocation,
......@@ -601,6 +606,113 @@ abstract class WidgetController {
});
}
/// Attempts to drag the given widget by the given offset in the `duration`
/// time, starting in the middle of the widget.
///
/// If the middle of the widget is not exposed, this might send
/// events to another object.
///
/// This is the timed version of [drag]. This may or may not result in a
/// [fling] or ballistic animation, depending on the speed from
/// `offset/duration`.
///
/// {@template flutter.flutter_test.timeddrag}
/// The move events are sent at a given `frequency` in Hz (or events per
/// second). It defaults to 60Hz.
///
/// The movement is linear in time.
///
/// See also [LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive] for
/// more accurate time control.
/// {@endtemplate}
Future<void> timedDrag(
Finder finder,
Offset offset,
Duration duration, {
int pointer,
int buttons = kPrimaryButton,
double frequency = 60.0,
}) {
return timedDragFrom(
getCenter(finder),
offset,
duration,
pointer: pointer,
buttons: buttons,
frequency: frequency,
);
}
/// Attempts a series of [PointerEvent]s to simulate a drag operation in the
/// `duration` time.
///
/// This is the timed version of [dragFrom]. This may or may not result in a
/// [flingFrom] or ballistic animation, depending on the speed from
/// `offset/duration`.
///
/// {@macro flutter.flutter_test.timeddrag}
Future<void> timedDragFrom(
Offset startLocation,
Offset offset,
Duration duration, {
int pointer,
int buttons = kPrimaryButton,
double frequency = 60.0,
}) {
assert(frequency > 0);
final int intervals = duration.inMicroseconds * frequency ~/ 1E6;
assert(intervals > 1);
final List<Duration> timeStamps = <Duration>[
for (int t = 0; t <= intervals; t += 1)
duration * t ~/ intervals,
];
final List<Offset> offsets = <Offset>[
startLocation,
for (int t = 0; t <= intervals; t += 1)
startLocation + offset * (t / intervals),
];
final List<PointerEventRecord> records = <PointerEventRecord>[
PointerEventRecord(Duration.zero, <PointerEvent>[
PointerAddedEvent(
timeStamp: Duration.zero,
position: startLocation,
),
PointerDownEvent(
timeStamp: Duration.zero,
position: startLocation,
pointer: pointer,
buttons: buttons,
),
]),
...<PointerEventRecord>[
for(int t = 0; t <= intervals; t += 1)
PointerEventRecord(timeStamps[t], <PointerEvent>[
PointerMoveEvent(
timeStamp: timeStamps[t],
position: offsets[t+1],
delta: offsets[t+1] - offsets[t],
pointer: pointer,
buttons: buttons,
)
]),
],
PointerEventRecord(duration, <PointerEvent>[
PointerUpEvent(
timeStamp: duration,
position: offsets.last,
pointer: pointer,
// The PointerData recieved from the engine with
// chagne = PointerChnage.up, which translates to PointerUpEvent,
// doesn't provide the button field.
// buttons: buttons,
)
]),
];
return TestAsyncUtils.guard<void>(() async {
return handlePointerEventRecord(records);
});
}
/// The next available pointer identifier.
///
/// This is the default pointer identifier that will be used the next time the
......
......@@ -577,6 +577,43 @@ void main() {
}
});
testWidgets(
'WidgetTester.timedDrag must respect buttons',
(WidgetTester tester) async {
final List<String> logs = <String>[];
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Listener(
onPointerDown: (PointerDownEvent event) => logs.add('down ${event.buttons}'),
onPointerMove: (PointerMoveEvent event) => logs.add('move ${event.buttons}'),
onPointerUp: (PointerUpEvent event) => logs.add('up ${event.buttons}'),
child: const Text('test'),
),
),
);
await tester.timedDrag(
find.text('test'),
const Offset(-200.0, 0.0),
const Duration(seconds: 1),
buttons: kSecondaryMouseButton,
);
await tester.pumpAndSettle();
const String b = '$kSecondaryMouseButton';
for(int i = 0; i < logs.length; i++) {
if (i == 0)
expect(logs[i], 'down $b');
else if (i != logs.length - 1)
expect(logs[i], 'move $b');
else
expect(logs[i], 'up 0');
}
},
);
testWidgets(
'ensureVisible: scrolls to make widget visible',
(WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment