Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ public DoubleTapGallery()
{
HeightRequest = 200,
WidthRequest = 200,
BackgroundColor = Microsoft.Maui.Graphics.Colors.AliceBlue,
AutomationId = "DoubleTapSurface"
BackgroundColor = Microsoft.Maui.Graphics.Colors.AliceBlue
};

var dtLabel = new Label { Text = "DoubleTapSurface", AutomationId = "DoubleTapSurface" };
tapSurface.Add(dtLabel);

var doubleTapRecognizer = new TapGestureRecognizer() { NumberOfTapsRequired = 2 };
doubleTapRecognizer.Tapped += (sender, args) => { result.Text = "Success"; };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
x:Class="Maui.Controls.Sample.Issues.Issue16561">
<StackLayout>

<Grid x:Name="TapArea"
AutomationId="TapArea"
BackgroundColor="LightBlue"
<Grid BackgroundColor="LightBlue"
Margin="10"
x:Name="TapArea"
HeightRequest="300">
<Label HorizontalOptions="Center"
VerticalOptions="Center"
<Label HorizontalOptions="Start" VerticalOptions="Start"
TextColor="Black"
Text="Tap In This Grid" />
AutomationId="TapArea"
Text="Tap In This Grid. This label needs to be long so the Windows test will work." />
</Grid>

<Label HeightRequest="100"
Expand Down
77 changes: 67 additions & 10 deletions src/Controls/tests/UITests/Tests/Issues/Issue16561.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using System.Drawing;
using Microsoft.Maui.Appium;
using NUnit.Framework;
using OpenQA.Selenium.Appium.MultiTouch;
using OpenQA.Selenium.Appium.Interactions;
using OpenQA.Selenium.Appium.iOS;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Interactions;
using TestUtils.Appium.UITests;
using PointerInputDevice = OpenQA.Selenium.Appium.Interactions.PointerInputDevice;

namespace Microsoft.Maui.AppiumTests.Issues
{
Expand All @@ -24,7 +28,7 @@ public void TapTwoPlacesQuickly()
throw new InvalidOperationException("Cannot run test. Missing driver to run quick tap actions.");
}

var tapAreaResult = App.WaitForElement(_tapAreaId);
var tapAreaResult = App.WaitForElement(_tapAreaId, $"Timed out waiting for {_tapAreaId}");
var tapArea = tapAreaResult[0].Rect;

// The test harness coordinates are absolute
Expand All @@ -41,22 +45,75 @@ public void TapTwoPlacesQuickly()
var expectedX1 = point1.X - tapArea.X;
var expectedX2 = point2.X - tapArea.X;

// Just calling Tap twice will be too slow; we need to queue up the actions so they happen quickly
var actionsList = new TouchAction(app2.Driver);

// Tap the first point, then the second point
actionsList.Tap(point1.X, point1.Y).Tap(point2.X, point2.Y);
app2.Driver.PerformTouchAction(actionsList);
TapTwice(app2, point1, point2);

// The results for each tap should show up in the labels on the screen; find the text
// of each tap result and check to see that it meets the expected values
var result = App.WaitForElement("Tap1Label");
var result = App.WaitForElement("Tap1Label", $"Timed out waiting for Tap1Label");
AssertCorrectTapLocation(result[0].Text, expectedX1, expectedY, "First");

result = App.WaitForElement("Tap2Label");
result = App.WaitForElement("Tap2Label", $"Timed out waiting for Tap2Label");
AssertCorrectTapLocation(result[0].Text, expectedX2, expectedY, "Second");
}

static void TapTwice(IApp2 app, PointF point1, PointF point2)
{
var driver = app.Driver ?? throw new InvalidOperationException("The Appium driver is null; cannot perform taps.");

if (driver is WindowsDriver)
{
// Windows will throw an error if we try to execute Taps with a TouchAction
// or if we try to use ExecuteScript, so we'll just use TapCoordinates instead
app.TapCoordinates(point1.X, point1.Y);
app.TapCoordinates(point2.X, point2.Y);
}
else if (driver is IOSDriver)
{
// iOS, on the other hand, will allow us to use ExecuteScript to run two taps quickly
// It will not work with an ActionSequence, though; one of the taps will simply never
// happen. No errors, but no second tap.

driver.ExecuteScript("mobile: tap", new Dictionary<string, object> {
{ "x", point1.X },
{ "y", point1.Y }
});

driver.ExecuteScript("mobile: tap", new Dictionary<string, object> {
{ "x", point2.X },
{ "y", point2.Y }
});
}
else
{
// For Android, TapCoordinates won't work (it's far too slow), and ExecuteScript
// throws an error. So we'll use an ActionSequence, which is what we wanted in
// the first place.

PointerInputDevice touchDevice = new PointerInputDevice(PointerKind.Touch);
var sequence = new ActionSequence(touchDevice, 0);

// Move to the first location and tap
sequence.AddAction(touchDevice.CreatePointerMove(CoordinateOrigin.Viewport,
(int)point1.X, (int)point1.Y, TimeSpan.FromMilliseconds(250)));
sequence.AddAction(touchDevice.CreatePointerDown(PointerButton.TouchContact));
sequence.AddAction(touchDevice.CreatePointerUp(PointerButton.TouchContact));

// If we don't put some kind of pause between the taps, Appium will throw an exception
// We'll use a pause that's shorter than the default time for a double-tap on Android,
// so we're very clearly simulating two different taps on two different locations
sequence.AddAction(touchDevice.CreatePause(TimeSpan.FromMilliseconds(250)));

// Move to the second location and tap
sequence.AddAction(touchDevice.CreatePointerMove(CoordinateOrigin.Viewport,
(int)point2.X, (int)point2.Y, TimeSpan.FromMilliseconds(0)));
sequence.AddAction(touchDevice.CreatePointerDown(PointerButton.TouchContact));
sequence.AddAction(touchDevice.CreatePointerUp(PointerButton.TouchContact));

// Run the sequence we just built
driver.PerformActions(new List<ActionSequence> { sequence });
}
}

static void AssertCorrectTapLocation(string tapData, float expectedX, float expectedY, string which)
{
// Turn the text values into numbers so we can compare with a tolerance
Expand Down