Skip to content

Commit

Permalink
Add support for drag and drop (#10)
Browse files Browse the repository at this point in the history
* add pumpAndTrySettle instead of pumpAndTry

* Added support for drag and drop and also use pumpAndTrySettle
  • Loading branch information
saikrishna321 authored Jun 27, 2024
1 parent 2767ded commit c49f37a
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 7 deletions.
1 change: 1 addition & 0 deletions demo-app/lib/screens/loader_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class _LoaderScreenState extends State<LoaderScreen> {
),
child: const Text(
"Login",
key: ValueKey("loader_login_button"),
style: TextStyle(color: Colors.white),
),
),
Expand Down
19 changes: 19 additions & 0 deletions server/lib/src/handler/gesture/drag_drop.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:appium_flutter_server/src/handler/request/request_handler.dart';
import 'package:appium_flutter_server/src/models/api/appium_response.dart';
import 'package:appium_flutter_server/src/utils/element_helper.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shelf_plus/shelf_plus.dart';
import 'package:appium_flutter_server/src/models/api/drag_drop.dart';

class DragAndDrop extends RequestHandler {
DragAndDrop(super.route);

@override
Future<AppiumResponse> handle(Request request) async {
var sessionId = getSessionId(request);
DragAndDropModel model =
DragAndDropModel.fromJson(await request.body.asJson);
await ElementHelper.dragAndDrop(model);
return AppiumResponse(sessionId, null);
}
}
22 changes: 22 additions & 0 deletions server/lib/src/models/api/drag_drop.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:appium_flutter_server/src/models/api/find_element.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:appium_flutter_server/src/models/api/element.dart';

part 'generated/drag_drop.g.dart';

@JsonSerializable()
class DragAndDropModel {
ElementModel source;
ElementModel target;
int? dragDuration;

DragAndDropModel(
{required this.source,
required this.target,
this.dragDuration});

factory DragAndDropModel.fromJson(Map<String, dynamic> json) =>
_$DragAndDropModelFromJson(json);

Map<String, dynamic> toJson() => _$DragAndDropModelToJson(this);
}
21 changes: 21 additions & 0 deletions server/lib/src/models/api/generated/drag_drop.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/lib/src/runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void initializeTest({Widget? app, Function? callback}) async {
var appInfo = await PackageInfo.fromPlatform();
// Need a better way to fetch this for automated release, this needs to be updated along with version bump
// Can stay for now as it is not a breaking change
var serverVersion = '0.0.11';
var serverVersion = '0.0.12';
FlutterDriver.instance
.initialize(tester: tester, binding: binding, appInfo: appInfo, serverVersion: serverVersion);
//await tester.pumpWidget(app);
Expand Down
3 changes: 3 additions & 0 deletions server/lib/src/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import 'package:shelf_plus/shelf_plus.dart' as shelf_plus;

import 'package:appium_flutter_server/src/handler/clear.dart';

import 'handler/gesture/drag_drop.dart';
import 'handler/long_press.dart';

enum HttpMethod { GET, POST, DELETE, PUT, PATCH }
Expand Down Expand Up @@ -77,6 +78,8 @@ class FlutterServer {
"/session/<sessionId>/appium/gestures/double_click"));
_registerPost(ScrollTillVisibleHandler(
"/session/<sessionId>/appium/gestures/scroll_till_visible"));
_registerPost(DragAndDrop(
"/session/<sessionId>/appium/gestures/drag_drop"));

/* Wait handlers */
_registerPost(
Expand Down
50 changes: 45 additions & 5 deletions server/lib/src/utils/element_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:appium_flutter_server/src/exceptions/flutter_automation_error.da
import 'package:appium_flutter_server/src/internal/element_lookup_strategy.dart';
import 'package:appium_flutter_server/src/internal/flutter_element.dart';
import 'package:appium_flutter_server/src/logger.dart';
import 'package:appium_flutter_server/src/models/api/drag_drop.dart';
import 'package:appium_flutter_server/src/models/api/gesture.dart';
import 'package:appium_flutter_server/src/models/api/find_element.dart';
import 'package:appium_flutter_server/src/models/session.dart';
Expand Down Expand Up @@ -71,7 +72,7 @@ class ElementHelper {
static Future<void> click(FlutterElement element) async {
WidgetTester tester = _getTester();
await tester.tap(element.by);
await tester.pumpAndSettle();
await pumpAndTrySettle();
}

static Future<void> setText(FlutterElement element, String text) async {
Expand Down Expand Up @@ -117,7 +118,7 @@ class ElementHelper {
await tester.pump(kDoubleTapMinTime);
await tester.tapAt(Offset(bounds.left + doubleClickModel.offset!.x,
bounds.top + doubleClickModel.offset!.y));
await tester.pumpAndSettle();
await pumpAndTrySettle();
}
}
});
Expand All @@ -128,7 +129,7 @@ class ElementHelper {
await tester.tap(element.by);
await tester.pump(kDoubleTapMinTime);
await tester.tap(element.by);
await tester.pumpAndSettle();
await pumpAndTrySettle();
}

static Future<void> longPress(GestureModel longPressModel) async {
Expand Down Expand Up @@ -162,7 +163,7 @@ class ElementHelper {
log("Click by offset $bounds");
await tester.longPressAt(
Offset(longPressModel.offset!.x, longPressModel.offset!.y));
await tester.pumpAndSettle();
await pumpAndTrySettle();
}
}
});
Expand Down Expand Up @@ -444,12 +445,30 @@ class ElementHelper {
: 'Timed out waiting for condition');
}
if (Platform.isAndroid) {
await tester.pumpAndSettle();
await pumpAndTrySettle(timeout: const Duration(milliseconds: 200));
}
await Future.delayed(const Duration(milliseconds: 100));
} while (!(await predicate()));
}

static Future<void> dragAndDrop(DragAndDropModel model) async {
return TestAsyncUtils.guard(() async {
WidgetTester tester = _getTester();
final String sourceElementId = model.source.id;
final String targetElementId = model.target.id;
Session session = FlutterDriver.instance.getSessionOrThrow()!;
FlutterElement sourceEl = await session.elementsCache.get(sourceElementId);
FlutterElement targetEl = await session.elementsCache.get(targetElementId);
final Offset sourceElementLocation = tester.getCenter(sourceEl.by);
final Offset targetElementLocation = tester.getCenter(targetEl.by);
final TestGesture gesture = await tester.startGesture(sourceElementLocation, pointer: 7);
await gesture.moveTo(targetElementLocation);
await tester.pump();
await gesture.up();
await tester.pump();
});
}

static Future<Finder> scrollUntilVisible({
required FindElementModel finder,
FindElementModel? scrollView,
Expand Down Expand Up @@ -540,4 +559,25 @@ class ElementHelper {
return const Uuid().v4();
}
}
static Future<void> pumpAndTrySettle({
Duration duration = const Duration(milliseconds: 100),
EnginePhase phase = EnginePhase.sendSemanticsUpdate,
Duration timeout = const Duration(milliseconds: 200),
}) async {
try {
WidgetTester tester = _getTester();
await tester.pumpAndSettle(
duration,
phase,
timeout,
);
} on FlutterError catch (err) {
if (err.message == 'pumpAndSettle timed out') {
//This method ignores pumpAndSettle timeouts on purpose
} else {
rethrow;
}
}
}

}
2 changes: 1 addition & 1 deletion server/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: appium_flutter_server
description: "Appium Flutter server using Integration Test package for testing Flutter apps with Appium"
version: 0.0.11
version: 0.0.12
homepage: "https://github.com/AppiumTestDistribution/appium-flutter-server"

environment:
Expand Down

0 comments on commit c49f37a

Please sign in to comment.