Add more UWP automated testing capabilities (#1252)

* Implement Clear(marked) method

* For Windows tests where we need to query a value we can't get, mark inconclusive

* Fix queries for multi-line "marked" values

* Force frames with text in them to be "tappable"

* Actually rerun queries during retry

* Update images for package deployment

* Allow the tests to restart the Control Gallery if it crashes

* UWP tests can now activate context menus

* Make double-tap (really double click) work for UWP desktop

* Get some basic scroll up/down functions working

* ScrollTo functions

* Modify ListViewRenderer automation peer to prevent freezing on ListViews

* Allow automation to find tabs

* Temporarily ignore some of the tests which don't do much

* Make ListViews with string/value type lists work

* Add note about 29257/60478

* Use toggle button for test 30353 for UWP

* Handle getting screen bounds consistently

* Make test for G2414 use ActivateContextMenu extension method

* Simplify UI test for 31330 and make it runnable on Windows

* Add notes on failing tests

* Add query for MoreButton on G2809 test

* Ignore ActivityIndicator IsRunning test for UWP

* Use ScrollDownTo instead of ScrollForElement method on Windows

* CellsGalleryTestCellList now working on UWP

* Cells tests working on UWP

* Re-add Tap to ScrollAndTap

* Get rid of custom automation peer stuff and just fix the tests

* Viewport caching and multi-monitor support for scroll

* Modified scroll values to hopefully get this running correctly on high density screen

* Clear messages so Appearing tests don't freeze up automation on UWP

* Make test for 32230 compatible with UWP

* Make test 32615 compatible with UWP

* Use ActivateContextMenu to simplify 34561 test

* Add notes for 34912 failure

* Make 36171 test compatible with UWP tests

Add directions for running the tests locally

* PR cleanup
This commit is contained in:
E.Z. Hart 2017-11-10 03:52:25 -07:00 коммит произвёл Rui Marinho
Родитель f04d4d2a47
Коммит f00907ea16
52 изменённых файлов: 1475 добавлений и 851 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -43,6 +43,8 @@ Xamarin.Forms.UITest.Validator/UITestCoverage/index.html
!Xamarin.Forms.UITest.TestCloud/test-cloud.exe
Xamarin.Forms.ControlGallery.Windows/AppPackages/
Xamarin.Forms.ControlGallery.WindowsPhone/AppPackages/
Xamarin.Forms.ControlGallery.WindowsUniversal/AppPackages/
Xamarin.Forms.ControlGallery.WindowsUniversal/BundleArtifacts/
Xamarin.Forms.Controls/secrets.txt
Xamarin.Forms.Controls/controlgallery.config
Xamarin.Forms.ControlGallery.Android/Properties/MapsKey.cs

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 801 B

После

Ширина:  |  Высота:  |  Размер: 801 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 222 B

После

Ширина:  |  Высота:  |  Размер: 222 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 2.1 KiB

После

Ширина:  |  Высота:  |  Размер: 2.1 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 429 B

После

Ширина:  |  Высота:  |  Размер: 429 B

Просмотреть файл

@ -0,0 +1,45 @@
using Xamarin.Forms.ControlGallery.WindowsUniversal;
using Xamarin.Forms.Controls;
using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(DisposePage), typeof(DisposePageRenderer))]
[assembly: ExportRenderer(typeof(DisposeLabel), typeof(DisposeLabelRenderer))]
namespace Xamarin.Forms.ControlGallery.WindowsUniversal
{
public class DisposePageRenderer : PageRenderer
{
bool _disposed;
protected override void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
_disposed = true;
if (disposing)
{
((DisposePage)Element).SendRendererDisposed();
}
base.Dispose(disposing);
}
}
public class DisposeLabelRenderer : LabelRenderer
{
protected override void Dispose(bool disposing)
{
if (disposing)
{
((DisposeLabel)Element).SendRendererDisposed();
}
base.Dispose(disposing);
}
}
}

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
<Identity Name="0d4424f6-1e29-4476-ac00-ba22c3789cb6" Publisher="CN=XamarinForms" Version="1.0.0.0" />
<Identity Name="0d4424f6-1e29-4476-ac00-ba22c3789cb6" Publisher="CN=XamarinForms" Version="1.0.2.0" />
<mp:PhoneIdentity PhoneProductId="0d4424f6-1e29-4476-ac00-ba22c3789cb6" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>Xamarin.Forms.ControlGallery.WindowsUniversal</DisplayName>

Просмотреть файл

@ -20,6 +20,9 @@
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>Xamarin.Forms.ControlGallery.WindowsUniversal_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>D160433BDC22781DEAE0558325140B91C02A6A20</PackageCertificateThumbprint>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>x86|x64|arm</AppxBundlePlatforms>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
@ -120,6 +123,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="DisposePageRenderer.cs" />
<Compile Include="_57114Renderer.cs" />
<Compile Include="_58406EffectRenderer.cs" />
<Compile Include="_60122ImageRenderer.cs" />
@ -187,10 +191,10 @@
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Assets\Logo.scale-100.png" />
<Content Include="Assets\SmallLogo.scale-100.png" />
<Content Include="Assets\SplashScreen.scale-100.png" />
<Content Include="Assets\StoreLogo.scale-100.png" />
<Content Include="Assets\Logo.png" />
<Content Include="Assets\SmallLogo.png" />
<Content Include="Assets\SplashScreen.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\WideLogo.scale-100.png" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -22,7 +22,7 @@ namespace Xamarin.Forms.Controls.Issues
{
var listview = new ListView ();
listview.ItemTemplate = new DataTemplate (typeof (ItemTemplate));
listview.ItemsSource = new string[] { "item", "item", "item", "item", "item" };
listview.ItemsSource = new string[] { "item1", "item2", "item3", "item4", "item5" };
var btnBack = new Button { Text = "back", Command = new Command (() => Navigation.PopAsync ()) };
listview.ItemSelected += (s, e) => Navigation.PushAsync (new ContentPage { Content = btnBack });
var btnPush = new Button {

Просмотреть файл

@ -23,6 +23,7 @@ namespace Xamarin.Forms.Controls.Issues
protected override void Init ()
{
s_disposeCount = 0;
s_lbl = new Label { AutomationId = "lblDisposedCound" };
var tab1 = new DisposePage { Title = "Tab1" };
var tab2 = new DisposePage { Title = "Tab2" };
@ -52,7 +53,6 @@ namespace Xamarin.Forms.Controls.Issues
RunningApp.Tap (q => q.Marked ("Tab1"));
RunningApp.Tap (q => q.Marked ("Pop"));
RunningApp.WaitForElement (q => q.Marked (string.Format ("Dispose {0} pages", 2)));
}
#endif
}

Просмотреть файл

@ -10,6 +10,8 @@ using NUnit.Framework;
namespace Xamarin.Forms.Controls.Issues
{
// Note that this test currently fails on UWP because of https://bugzilla.xamarin.com/show_bug.cgi?id=60478
[Preserve (AllMembers = true)]
[Issue (IssueTracker.Bugzilla, 29257, "CarouselPage.CurrentPage Does Not Work Properly When Used Inside a NavigationPage ")]
public class Bugzilla29257 : TestContentPage

Просмотреть файл

@ -116,7 +116,7 @@ namespace Xamarin.Forms.Controls.Issues
void Back()
{
#if __IOS__
#if __IOS__ || __WINDOWS__
RunningApp.Tap (q => q.Marked ("Toggle"));
#else
RunningApp.Back();

Просмотреть файл

@ -6,6 +6,7 @@ using System.Windows.Input;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest.iOS;
using Xamarin.UITest;
using NUnit.Framework;
@ -13,6 +14,8 @@ using NUnit.Framework;
namespace Xamarin.Forms.Controls.Issues
{
// Note that this test fails on UWP due to https://bugzilla.xamarin.com/show_bug.cgi?id=59650
[Preserve (AllMembers = true)]
[Issue (IssueTracker.Bugzilla, 31330, "Disabled context actions appear enabled")]
public class Bugzilla31330 : TestContentPage
@ -132,30 +135,15 @@ namespace Xamarin.Forms.Controls.Issues
public void Bugzilla31330Test ()
{
RunningApp.WaitForElement (c => c.Marked ("Something 2"));
var screenBounds = RunningApp.Query (q => q.Raw ("* index:0"))[0].Rect;
var cell = RunningApp.Query (c => c.Marked ("Something 1")) [0];
var cell2 = RunningApp.Query (c => c.Marked ("Something 2")) [0];
#if __IOS__
RunningApp.DragCoordinates (screenBounds.Width - 10, cell.Rect.CenterY, 0, cell.Rect.CenterY);
RunningApp.WaitForElement (c => c.Marked ("Delete"));
RunningApp.Tap (c => c.Marked ("Delete"));
RunningApp.WaitForElement (c => c.Marked ("Something 1"));
RunningApp.ActivateContextMenu("Something 1");
RunningApp.WaitForElement(c => c.Marked("Delete"));
RunningApp.Tap(c => c.Marked("Delete"));
RunningApp.DismissContextMenu();
RunningApp.Tap (c => c.Marked ("Something 2"));
RunningApp.DragCoordinates (screenBounds.Width - 10, cell2.Rect.CenterY, 0, cell2.Rect.CenterY);
RunningApp.Tap (c => c.Marked ("Delete"));
RunningApp.ActivateContextMenu("Something 2");
RunningApp.WaitForElement(c => c.Marked("Delete"));
RunningApp.Tap(c => c.Marked("Delete"));
RunningApp.WaitForNoElement (c => c.Marked ("Something 2"));
#else
RunningApp.TouchAndHoldCoordinates (cell.Rect.CenterX, cell.Rect.CenterY);
RunningApp.WaitForElement (c => c.Marked ("Delete"));
RunningApp.Tap (c => c.Marked ("Delete"));
RunningApp.Back ();
RunningApp.WaitForElement (c => c.Marked ("Something 1"));
RunningApp.Tap (c => c.Marked ("Something 2"));
RunningApp.TouchAndHoldCoordinates (cell2.Rect.CenterX, cell2.Rect.CenterY);
RunningApp.Tap (c => c.Marked ("Delete"));
RunningApp.WaitForNoElement (c => c.Marked ("Something 2"));
#endif
}
#endif
}

Просмотреть файл

@ -50,10 +50,10 @@ namespace Xamarin.Forms.Controls.Issues
public void Bugzilla32230Test ()
{
RunningApp.Tap (q => q.Marked ("btnOpen"));
Assert.AreEqual ("1", RunningApp.Query (q => q.Marked ("lblCount"))[0].Text);
RunningApp.WaitForElement("1");
RunningApp.Tap (q => q.Marked ("btnClose"));
RunningApp.Tap (q => q.Marked ("btnOpen"));
Assert.AreEqual ("3", RunningApp.Query (q => q.Marked ("lblCount"))[0].Text);
RunningApp.WaitForElement("3");
}
#endif
}

Просмотреть файл

@ -63,8 +63,7 @@ namespace Xamarin.Forms.Controls.Issues
RunningApp.Tap (q => q.Marked ("btnModal"));
RunningApp.Tap (q => q.Marked ("btnPop"));
await Task.Delay (1000);
var lbl = RunningApp.WaitForElement (c => c.Marked("lblCount"));
Assert.AreEqual ("1", lbl [0].Text);
RunningApp.WaitForElement ("1");
}
#endif
}

Просмотреть файл

@ -9,6 +9,7 @@ using Xamarin.Forms.Internals;
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.UITest.iOS;
using Xamarin.Forms.Core.UITests;
#endif
namespace Xamarin.Forms.Controls.Issues
@ -74,13 +75,7 @@ namespace Xamarin.Forms.Controls.Issues
{
RunningApp.WaitForElement (q => q.Marked ("ListViewItem"));
#if __IOS__
var listItem = RunningApp.Query (q => q.Marked ("ListViewItem"))[0].Rect;
RunningApp.DragCoordinates(listItem.CenterX, listItem.CenterY, 0, listItem.CenterY);
#else
RunningApp.TouchAndHold (q => q.Marked ("ListViewItem"));
#endif
RunningApp.ActivateContextMenu("ListViewItem");
RunningApp.WaitForElement (q => q.Marked ("Click"));
RunningApp.Tap (q => q.Marked ("Click"));
RunningApp.WaitForElement (q => q.Marked ("NextPageLabel"));

Просмотреть файл

@ -16,6 +16,8 @@ namespace Xamarin.Forms.Controls.Issues
[Category(UITestCategories.ListView)]
#endif
// Note: Fails on UWP due to https://bugzilla.xamarin.com/show_bug.cgi?id=60521
[Preserve (AllMembers = true)]
[Issue (IssueTracker.Bugzilla, 34912, "ListView.IsEnabled has no effect on iOS")]
public class Bugzilla34912 : TestContentPage // or TestMasterDetailPage, etc ...

Просмотреть файл

@ -16,7 +16,7 @@ namespace Xamarin.Forms.Controls.Issues
{
protected override void Init ()
{
var entry = new Entry ();
var entry = new Entry { AutomationId = "36171Entry" };
var editor = new Editor();
var focuseEntryButton = new Button { Text = "Start Entry" };
var focuseEditorButton = new Button { Text = "Start Editor" };
@ -88,7 +88,7 @@ namespace Xamarin.Forms.Controls.Issues
var entry2 = RunningApp.Query (q => q.Text("1234"));
Assert.That(entry2.Length >= 1);
RunningApp.ClearText();
RunningApp.ClearText("36171Entry");
RunningApp.WaitForElement ("Start Editor");
RunningApp.Tap ("Start Editor");

Просмотреть файл

@ -5,6 +5,7 @@ using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using NUnit.Framework;
using Xamarin.UITest;
#endif
@ -38,7 +39,7 @@ namespace Xamarin.Forms.Controls.Issues
RunningApp.Screenshot ("All elements exist");
#if !__MACOS__
var scrollRect = RunningApp.Query (q => q.Raw ("* index:0"))[0].Rect;
var scrollRect = RunningApp.RootViewRect();
Xamarin.Forms.Core.UITests.Gestures.ScrollForElement (RunningApp, "* marked:'9'", new Xamarin.Forms.Core.UITests.Drag (scrollRect, Xamarin.Forms.Core.UITests.Drag.Direction.BottomToTop, Xamarin.Forms.Core.UITests.Drag.DragLength.Long));
RunningApp.Screenshot ("I see 9");
#endif

Просмотреть файл

@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.CustomAttributes;
using System.Windows.Input;
using System.Diagnostics;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using NUnit.Framework;
using Xamarin.UITest;
using Xamarin.UITest.iOS;
@ -61,7 +62,7 @@ namespace Xamarin.Forms.Controls.Issues
var disable1 = RunningApp.Query (c => c.Marked ("txtCellDisableContextActions1")) [0];
Assert.IsFalse (disable1.Enabled);
var screenBounds = RunningApp.Query (q => q.Raw ("* index:0")) [0].Rect;
var screenBounds = RunningApp.RootViewRect();
RunningApp.DragCoordinates (screenBounds.Width - 10, disable1.Rect.CenterY, 10, disable1.Rect.CenterY);
@ -87,7 +88,7 @@ namespace Xamarin.Forms.Controls.Issues
var disable1 = RunningApp.Query (c => c.Marked ("txtCellEnabledContextActions1")) [0];
Assert.IsTrue (disable1.Enabled);
var screenBounds = RunningApp.Query (q => q.Raw ("* index:0")) [0].Rect;
var screenBounds = RunningApp.RootViewRect();
RunningApp.DragCoordinates (screenBounds.Width - 10, disable1.Rect.CenterY, 10, disable1.Rect.CenterY);

Просмотреть файл

@ -1,5 +1,4 @@
using System;
using Xamarin.Forms;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
@ -7,6 +6,7 @@ using Xamarin.Forms.Internals;
#if UITEST
using NUnit.Framework;
using Xamarin.UITest.iOS;
using Xamarin.Forms.Core.UITests;
#endif
namespace Xamarin.Forms.Controls.Issues
@ -60,48 +60,19 @@ namespace Xamarin.Forms.Controls.Issues
[Test]
public void TestDoesntCrashShowingContextMenu ()
{
RunningApp.WaitForElement(c => c.Marked("Swipe ME"));
var screenBounds = RunningApp.Query (q => q.Raw ("* index:0"))[0].Rect;
var cell = RunningApp.Query(c => c.Marked("Swipe ME")) [0];
#if __IOS__
RunningApp.DragCoordinates (screenBounds.Width - 10, cell.Rect.CenterY, 0, cell.Rect.CenterY);
//TODO: fix this when context menu bug is fixed
RunningApp.WaitForElement (c => c.Marked ("Text4"));
#else
RunningApp.TouchAndHoldCoordinates (cell.Rect.CenterX, cell.Rect.CenterY);
RunningApp.ActivateContextMenu("Swipe ME");
RunningApp.WaitForElement (c => c.Marked ("Text0"));
#endif
RunningApp.Screenshot ("Didn't crash");
RunningApp.TapCoordinates (screenBounds.CenterX, screenBounds.CenterY);
#if __ANDROID__
RunningApp.Tap(c => c.Marked("Text0"));
#endif
}
[Test]
public void TestShowContextMenuItemsInTheRightOrder ()
{
RunningApp.WaitForElement(c => c.Marked("Swipe ME"));
var screenBounds = RunningApp.Query (q => q.Raw ("* index:0"))[0].Rect;
var cell = RunningApp.Query (c => c.Marked ("Swipe ME")) [0];
#if __IOS__
RunningApp.DragCoordinates (screenBounds.Width -10, cell.Rect.CenterY, 0, cell.Rect.CenterY);
#else
RunningApp.TouchAndHoldCoordinates (cell.Rect.CenterX, cell.Rect.CenterY);
#endif
RunningApp.ActivateContextMenu("Swipe ME");
RunningApp.WaitForElement (c => c.Marked ("Text0"));
RunningApp.Screenshot ("Are the menuitems in the right order?");
#if __ANDROID__
RunningApp.Tap(c => c.Marked("Text0"));
#endif
}
#endif

Просмотреть файл

@ -129,5 +129,7 @@ namespace Xamarin.Forms.Controls.Issues
}
#endif
}
// Note: this fails on UWP because we can't currently inspect listview headers
}

Просмотреть файл

@ -41,6 +41,8 @@ namespace Xamarin.Forms.Controls.Issues
#if __ANDROID__
//show secondary menu
RunningApp.Tap (c => c.Class ("OverflowMenuButton"));
#elif __WINDOWS__
RunningApp.Tap ("MoreButton");
#endif
}

Просмотреть файл

@ -88,3 +88,5 @@ namespace Xamarin.Forms.Controls.Issues
#endif
}
}
// Note: this fails on UWP because we can't currently inspect listview headers

Просмотреть файл

@ -6,6 +6,7 @@ using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using NUnit.Framework;
using Xamarin.UITest;
using Xamarin.UITest.iOS;
@ -48,7 +49,7 @@ namespace Xamarin.Forms.Controls.Issues
RunningApp.WaitForElement (q => q.Marked ("Swipe lightly left and right to crash this page"));
System.Threading.Thread.Sleep (3);
var mainBounds = RunningApp.Query (q => q.Raw ("* index:0")) [0].Rect;
var mainBounds = RunningApp.RootViewRect();
Xamarin.Forms.Core.UITests.Gestures.Pan (RunningApp, new Xamarin.Forms.Core.UITests.Drag (mainBounds, 0, 125, 75, 125, Xamarin.Forms.Core.UITests.Drag.Direction.LeftToRight));
System.Threading.Thread.Sleep (3);

Просмотреть файл

@ -15,6 +15,8 @@ namespace Xamarin.Forms.Controls
public AppearingGalleryPage ()
{
App.AppearingMessages.Clear();
var initalPage = new AppearingPage (1);
var initalPage2 = new AppearingPage (2);

Просмотреть файл

@ -29,6 +29,10 @@ namespace Xamarin.Forms.Controls
public class CellTypeList : ListView
{
CellNavigation _last;
public const string CellTestContainerId = "CellTestContainer";
// TODO Add gallerys for ViewCell, ListView and TableView
public CellTypeList ()
{
@ -52,12 +56,23 @@ namespace Xamarin.Forms.Controls
ItemTemplate = template;
ItemSelected += (s, e) => {
if (SelectedItem == null)
return;
var cellNav = (CellNavigation) e.SelectedItem;
if (cellNav == _last)
{
_last = null;
return;
}
Navigation.PushAsync (cellNav.Page);
_last = cellNav;
#if !__WINDOWS__
SelectedItem = null;
#endif
};
}
}

Просмотреть файл

@ -31,6 +31,7 @@ namespace Xamarin.Forms.Controls
};
var listView = new ListView {
AutomationId = CellTypeList.CellTestContainerId,
ItemsSource = Enumerable.Range (0, 100).Select (i => new EntryCellTest {
Label = "Label " + i,
LabelColor = i % 2 == 0 ? Color.Red : Color.Blue,

Просмотреть файл

@ -73,6 +73,7 @@ namespace Xamarin.Forms.Controls
};
var table = new TableView {
AutomationId = CellTypeList.CellTestContainerId,
Root = root
};

Просмотреть файл

@ -48,7 +48,7 @@ namespace Xamarin.Forms.Controls
var label = new Label { Text = "I have not been selected" };
var listView = new ListView {
AutomationId = "ImageCellListView",
AutomationId = CellTypeList.CellTestContainerId,
ItemsSource = Enumerable.Range (0, 100).Select (i => new ImageCellTest {
Text = "Text " + i,
TextColor = i % 2 == 0 ? Color.Red : Color.Blue,

Просмотреть файл

@ -56,6 +56,7 @@ namespace Xamarin.Forms.Controls
};
var table = new TableView {
AutomationId = CellTypeList.CellTestContainerId,
Root = root,
};

Просмотреть файл

@ -29,6 +29,7 @@ namespace Xamarin.Forms.Controls
var label = new Label { Text = "I have not been selected" };
var listView = new ListView {
AutomationId = CellTypeList.CellTestContainerId,
ItemsSource = Enumerable.Range (0, 100).Select (i => new SwitchCellItem {
Label = "Label " + i,
SwitchOn = i % 2 == 0 ? false : true,

Просмотреть файл

@ -53,6 +53,7 @@ namespace Xamarin.Forms.Controls
};
var table = new TableView {
AutomationId = CellTypeList.CellTestContainerId,
Root = root,
};

Просмотреть файл

@ -29,6 +29,7 @@ namespace Xamarin.Forms.Controls
dataTemplate.SetBinding (TextCell.DetailColorProperty, new Binding ("DetailColor"));
var listView = new ListView {
AutomationId = CellTypeList.CellTestContainerId,
ItemsSource = Enumerable.Range (0, 100).Select (i => new TextCellTest {
Text = "Text " + i,
TextColor = i % 2 == 0 ? Color.Red : Color.Blue,

Просмотреть файл

@ -46,6 +46,7 @@ namespace Xamarin.Forms.Controls
};
var table = new TableView {
AutomationId = CellTypeList.CellTestContainerId,
Root = root,
};

Просмотреть файл

@ -93,6 +93,7 @@ namespace Xamarin.Forms.Controls
var label = new Label { Text = "I have not been selected" };
var listView = new ListView {
AutomationId = CellTypeList.CellTestContainerId,
ItemsSource = Enumerable.Range (0, albums.Length).Select (i => new {
Text = "Text " + i,
TextColor = i % 2 == 0 ? Color.Red : Color.Blue,

Просмотреть файл

@ -102,7 +102,7 @@ namespace Xamarin.Forms.Core.UITests
public static AppRect RootViewRect (this IApp app)
{
#if __WINDOWS__
return app.Query("Xamarin.Forms.ControlGallery.WindowsUniversal")[0].Rect;
return app.Query(WinDriverApp.AppName)[0].Rect;
#else
return app.Query (q => q.Raw ("* index:0"))[0].Rect;
#endif

Просмотреть файл

@ -1,4 +1,5 @@
using NUnit.Framework;
using System;
using NUnit.Framework;
using Xamarin.UITest.Queries;
namespace Xamarin.Forms.Core.UITests
@ -156,10 +157,16 @@ namespace Xamarin.Forms.Core.UITests
void ScrollAndTap(string actionSheet)
{
#if !__MACOS__
App.ScrollForElement(string.Format("* text:'{0}'", actionSheet), new Drag(App.Query(q => q.Marked("ActionSheetPage"))[0].Rect, Drag.Direction.BottomToTop, Drag.DragLength.Long));
var queryString = $"* text:'{actionSheet}'";
Func<AppQuery, AppQuery> actionSheetQuery = q => q.Raw (queryString);
#if __WINDOWS__
App.ScrollDownTo(actionSheetQuery);
#elif __MACOS__
App.Tap(actionSheetQuery);
#else
App.ScrollForElement(queryString, new Drag(App.Query(q => q.Marked("ActionSheetPage"))[0].Rect, Drag.Direction.BottomToTop, Drag.DragLength.Long));
#endif
App.Tap(q => q.Raw(string.Format("* text:'{0}'", actionSheet)));
App.Tap(actionSheetQuery);
}
}

Просмотреть файл

@ -54,6 +54,8 @@ namespace Xamarin.Forms.Core.UITests
remote.GoTo();
#if __MACOS__
Assert.Inconclusive("Not tested yet");
#elif __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#else
var isRunning = remote.GetProperty<bool> (ActivityIndicator.IsRunningProperty);
Assert.IsTrue (isRunning);

Просмотреть файл

@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
@ -13,7 +14,9 @@ namespace Xamarin.Forms.Core.UITests
[Category(UITestCategories.Cells)]
internal class CellsGalleryTests : BaseTestFixture
{
// TODO find a way to test individula elements of cells
public const string CellTestContainerId = "CellTestContainer";
// TODO find a way to test individual elements of cells
// TODO port to new framework
protected override void NavigateToGallery()
@ -21,23 +24,39 @@ namespace Xamarin.Forms.Core.UITests
App.NavigateToGallery(GalleryQueries.CellsGalleryLegacy);
}
void SelectTest(string testName)
{
#if __WINDOWS__
App.ScrollDownTo(testName);
#else
App.ScrollForElement($"* marked:'{testName}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.Tap(q => q.Marked(testName));
}
[Test]
[Description("ListView with TextCells, all are present")]
[UiTest(typeof(ListView))]
[UiTest(typeof(TextCell))]
public void CellsGalleryTextCellList()
{
App.ScrollForElement("* marked:'TextCell List'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
App.Tap(q => q.Marked("TextCell List"));
SelectTest("TextCell List");
App.WaitForElement(q => q.Marked("Text 0"), "Timeout : Text 0");
App.Screenshot("At TextCell List Gallery");
App.ScrollForElement("* marked:'Detail 99'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
string target = "Detail 99";
App.WaitForElement(q => q.Marked("Detail 99"), "Timeout : Detail 99");
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(1));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.WaitForElement(q => q.Marked(target), $"Timeout : {target}");
App.Screenshot("All TextCells are present");
}
@ -48,18 +67,22 @@ namespace Xamarin.Forms.Core.UITests
[UiTest(typeof(TextCell))]
public void CellsGalleryTextCellTable()
{
App.ScrollForElement("* marked:'TextCell Table'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("TextCell Table");
App.Tap(q => q.Marked("TextCell Table"));
App.WaitForElement(q => q.Marked("Text 1"), "Timeout : Text 1");
App.Screenshot("At TextCell Table Gallery");
App.ScrollForElement("* marked:'Detail 12'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
string target = "Detail 12";
App.WaitForElement(q => q.Marked("Detail 12"), "Timeout : Detail 12");
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(1));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.WaitForElement(q => q.Marked(target), $"Timeout : {target}");
App.Screenshot("All TextCells are present");
}
@ -72,43 +95,46 @@ namespace Xamarin.Forms.Core.UITests
{
Thread.Sleep(2000);
App.ScrollForElement("* marked:'ImageCell List'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("ImageCell List");
Thread.Sleep(2000);
App.Tap(q => q.Marked("ImageCell List"));
App.WaitForElement(q => q.Marked("Text 0"), "Timeout : Text 0");
App.Screenshot("At ImageCell List Gallery");
var scollBounds = App.Query(q => q.Marked("ImageCellListView")).First().Rect;
App.ScrollForElement("* marked:'Detail 99'",
new Drag(scollBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
string target = "Detail 99";
App.WaitForElement(q => q.Marked("Detail 99"), "Timeout : Detail 99");
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(3));
#else
var scrollBounds = App.Query(q => q.Marked(CellTestContainerId)).First().Rect;
App.ScrollForElement($"* marked:'{target}'",
new Drag(scrollBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.WaitForElement(q => q.Marked(target), $"Timeout : {target}");
App.Screenshot("All ImageCells are present");
#if !__WINDOWS__
var numberOfImages = App.Query(q => q.Raw(PlatformViews.Image)).Length;
// Check that there are images present. In Android,
// have to make sure that there are more than 2 for navigation.
Assert.IsTrue(numberOfImages > 2);
#endif
App.Screenshot("Images are present");
}
[Test]
[Ignore("Ignore because is only failing on iOS10 at XTC")]
[Ignore("Ignore because is only failing on iOS10 at XTC")] // TODO hartez also probably failing because the urls used on the test page are now invalid
[Description("ListView with ImageCells, file access problems")]
[UiTest(typeof(ListView))]
[UiTest(typeof(ImageCell))]
public async Task CellsGalleryImageUrlCellList()
{
App.ScrollForElement("* marked:'ImageCell Url List'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
App.Tap(q => q.Marked("ImageCell Url List"));
SelectTest("ImageCell Url List");
//var scollBounds = App.Query(q => q.Marked("ImageUrlCellListView")).First().Rect;
//App.ScrollForElement("* marked:'Detail 200'", new Drag(scollBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
@ -144,25 +170,31 @@ namespace Xamarin.Forms.Core.UITests
[UiTest(typeof(ImageCell))]
public void CellsGalleryImageCellTable()
{
App.ScrollForElement("* marked:'ImageCell Table'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("ImageCell Table");
App.Tap(q => q.Marked("ImageCell Table"));
App.WaitForElement(q => q.Marked("Text 1"), "Timeout : Text 1");
App.Screenshot("At ImageCell Table Gallery");
App.ScrollForElement("* marked:'Detail 12'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
string target = "Detail 12";
App.WaitForElement(q => q.Marked("Detail 12"), "Timeout : Detail 12");
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(1));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.WaitForElement(q => q.Marked(target), $"Timeout : {target}");
App.Screenshot("All ImageCells are present");
#if !__WINDOWS__
var numberOfImages = App.Query(q => q.Raw(PlatformViews.Image)).Length;
// Check that there are images present. In Android,
// have to make sure that there are more than 2 for navigation.
Assert.IsTrue(numberOfImages > 2);
#endif
App.Screenshot("Images are present");
}
@ -173,19 +205,23 @@ namespace Xamarin.Forms.Core.UITests
[UiTest(typeof(SwitchCell))]
public void CellsGallerySwitchCellList()
{
App.ScrollForElement("* marked:'SwitchCell List'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("SwitchCell List");
App.Tap(q => q.Marked("SwitchCell List"));
App.WaitForElement(q => q.Marked("Label 0"), "Timeout : Label 0");
App.Screenshot("At SwitchCell List Gallery");
App.ScrollForElement("* marked:'Label 99'",
string target = "Label 99";
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(1));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
var numberOfSwitches = App.Query(q => q.Raw(PlatformViews.Switch)).Length;
Assert.IsTrue(numberOfSwitches > 2);
#endif
App.Screenshot("Switches are present");
}
@ -196,18 +232,23 @@ namespace Xamarin.Forms.Core.UITests
[UiTest(typeof(SwitchCell))]
public void CellsGallerySwitchCellTable()
{
App.ScrollForElement("* marked:'SwitchCell Table'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("SwitchCell Table");
App.Tap(q => q.Marked("SwitchCell Table"));
App.WaitForElement(q => q.Marked("text 1"), "Timeout : text 1");
App.Screenshot("At SwitchCell Table Gallery");
App.ScrollForElement("* marked:'text 32'", new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
string target = "text 32";
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(1));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
var numberOfSwitches = App.Query(q => q.Raw(PlatformViews.Switch)).Length;
Assert.IsTrue(numberOfSwitches > 2);
#endif
App.Screenshot("Switches are present");
}
@ -218,16 +259,20 @@ namespace Xamarin.Forms.Core.UITests
[UiTest(typeof(EntryCell))]
public void CellsGalleryEntryCellList()
{
App.ScrollForElement("* marked:'EntryCell List'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("EntryCell List");
App.Tap(q => q.Marked("EntryCell List"));
App.WaitForElement(q => q.Marked("Label 0"), "Timeout : Label 0");
App.Screenshot("At EntryCell List Gallery");
App.ScrollForElement("* marked:'Label 99'",
string target = "Label 99";
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(3));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.Screenshot("All EntryCells are present");
}
@ -238,15 +283,20 @@ namespace Xamarin.Forms.Core.UITests
[UiTest(typeof(EntryCell))]
public void CellsGalleryEntryCellTable()
{
App.ScrollForElement("* marked:'EntryCell Table'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("EntryCell Table");
App.Tap(q => q.Marked("EntryCell Table"));
App.WaitForElement(q => q.Marked("Text 2"), "Timeout : Text 2");
App.Screenshot("At EntryCell Table Gallery");
App.ScrollForElement("* marked:'Text 32'", new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
string target = "Text 32";
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(1));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.Screenshot("All EntryCells are present");
}
@ -257,19 +307,24 @@ namespace Xamarin.Forms.Core.UITests
[UiTest(typeof(EntryCell), "Completed")]
public void CellsGalleryEntryCellCompleted()
{
App.ScrollForElement("* marked:'EntryCell Table'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
SelectTest("EntryCell Table");
App.Tap(q => q.Marked("EntryCell Table"));
App.WaitForElement(q => q.Marked("Text 2"), "Timeout : Text 2");
App.Screenshot("At EntryCell Table Gallery");
App.ScrollForElement("* marked:'Enter text'",
string target = "Enter text";
#if __WINDOWS__
App.ScrollDownTo(target, CellTestContainerId, timeout: TimeSpan.FromMinutes(1));
#else
App.ScrollForElement($"* marked:'{target}'",
new Drag(ScreenBounds, Drag.Direction.BottomToTop, Drag.DragLength.Medium));
#endif
App.Screenshot("Before clicking Entry");
#if !__IOS__
#if !__IOS__ && !__WINDOWS__
App.Tap(PlatformQueries.EntryCellWithPlaceholder("I am a placeholder"));
App.EnterText(PlatformQueries.EntryCellWithPlaceholder("I am a placeholder"), "Hi");
App.Screenshot("Entered Text");

Просмотреть файл

@ -73,9 +73,14 @@ namespace Xamarin.Forms.Core.UITests
{
foreach (var page in rootPages)
{
#if __WINDOWS__
App.ScrollDownTo(page.ButtonId, "ChoosePageScrollView");
#else
var scrollViewArea = App.Query(q => q.Marked("ChoosePageScrollView")).First().Rect;
App.ScrollForElement(string.Format("* marked:'{0}'", page.ButtonId),
new Drag(scrollViewArea, Drag.Direction.BottomToTop, Drag.DragLength.Long));
#endif
App.Tap(q => q.Marked(page.ButtonId));
bool ios = false;

Просмотреть файл

@ -14,6 +14,8 @@ namespace Xamarin.Forms.Core.UITests
[Category("ViewBaseTests")]
internal abstract class _ViewUITests : BaseTestFixture
{
protected const string PleaseInspect = "Test framework cannout currently check this value; please inspect visually";
/* Under score prefixes ensure inherited properties run first in test suite */
//[Test]
//[Category ("View")]
@ -145,6 +147,8 @@ namespace Xamarin.Forms.Core.UITests
remote.GoTo();
#if __MACOS__
Assert.Inconclusive("needs testing");
#elif __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#else
float opacity = -1f;
opacity = remote.GetProperty<float> (View.OpacityProperty);
@ -169,7 +173,10 @@ namespace Xamarin.Forms.Core.UITests
Matrix generatedMatrix = NumericExtensions.CalculateRotationMatrixForDegrees (10, Axis.Z);
Assert.AreEqual (generatedMatrix, rotationMatrix);
#endif
}
#if __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#endif
}
[Test]
[UiTest (typeof (VisualElement), "RotationX")]
@ -186,6 +193,9 @@ namespace Xamarin.Forms.Core.UITests
var rotationXMatrix = remote.GetProperty<Matrix> (View.RotationXProperty);
Matrix matrix = NumericExtensions.CalculateRotationMatrixForDegrees (33.0f, Axis.X);
Assert.AreEqual (matrix, rotationXMatrix);
#endif
#if __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#endif
}
@ -204,6 +214,9 @@ namespace Xamarin.Forms.Core.UITests
var rotationYMatrix = remote.GetProperty<Matrix> (View.RotationYProperty);
Matrix matrix = NumericExtensions.CalculateRotationMatrixForDegrees (10.0f, Axis.Y);
Assert.AreEqual (matrix, rotationYMatrix);
#endif
#if __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#endif
}
@ -216,10 +229,14 @@ namespace Xamarin.Forms.Core.UITests
#if __MACOS__
Assert.Inconclusive("needs testing");
#else
#if __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#endif
var scaleMatrix = remote.GetProperty<Matrix>(View.ScaleProperty);
Matrix generatedMatrix = NumericExtensions.BuildScaleMatrix(0.5f);
Assert.AreEqual(generatedMatrix, scaleMatrix);
#endif
}
[Test]
@ -229,6 +246,9 @@ namespace Xamarin.Forms.Core.UITests
{
var remote = new ViewContainerRemote (App, Test.VisualElement.TranslationX, PlatformViewType);
remote.GoTo ();
#if __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#endif
}
[Test]
@ -238,6 +258,9 @@ namespace Xamarin.Forms.Core.UITests
{
var remote = new ViewContainerRemote (App, Test.VisualElement.TranslationY, PlatformViewType);
remote.GoTo ();
#if __WINDOWS__
Assert.Inconclusive(PleaseInspect);
#endif
}
[Test]

Просмотреть файл

@ -9,12 +9,12 @@ namespace Xamarin.Forms.Core.UITests
{
public static bool ScrollForElement (this IApp app, string query, Drag drag, int maxSteps = 25)
{
Func<AppQuery, AppQuery> elementQuery = q => q.Raw (query);
int count = 0;
int centerTolerance = 50;
Func<AppQuery, AppQuery> elementQuery = q => q.Raw (query);
// Visible elements
if (app.Query (elementQuery).Length > 1) {
throw new UITestQueryMultipleResultsException (query);
@ -117,10 +117,27 @@ namespace Xamarin.Forms.Core.UITests
rect.CenterY,
rect.X + (0.25f * rect.Width),
rect.CenterY);
#else
#elif __ANDROID__
app.TouchAndHold(target);
#elif __WINDOWS__
// Since we know we're on desktop for the moment, just use ContextClick. If we get this running
// on actual touch devices at some point, we'll need to check for that and use TouchAndHold
app.Invoke("ContextClick", target);
#endif
}
public static void DismissContextMenu(this IApp app)
{
#if __IOS__
var screenbounds = app.RootViewRect();
app.TapCoordinates (screenbounds.CenterX, screenbounds.CenterY);
#elif __ANDROID__
app.Back();
#elif __WINDOWS__
var screenbounds = app.RootViewRect();
app.TapCoordinates (screenbounds.CenterX, screenbounds.CenterY);
#endif
}
}
}

Просмотреть файл

@ -0,0 +1,992 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;
using Xamarin.UITest;
using Xamarin.UITest.Queries;
using Xamarin.UITest.Queries.Tokens;
namespace Xamarin.Forms.Core.UITests
{
public class WinDriverApp : IApp
{
public const string AppName = "Xamarin.Forms.ControlGallery.WindowsUniversal";
readonly Dictionary<string, string> _controlNameToTag = new Dictionary<string, string>
{
{ "button", "ControlType.Button" }
};
readonly WindowsDriver<WindowsElement> _session;
readonly Dictionary<string, string> _translatePropertyAccessor = new Dictionary<string, string>
{
{ "getAlpha", "Opacity" }
};
int _scrollBarOffset = 5;
WindowsElement _viewPort;
WindowsElement _window;
public WinDriverApp(WindowsDriver<WindowsElement> session)
{
_session = session;
TestServer = new WindowsTestServer(_session);
}
public void Back()
{
QueryWindows("Back").First().Click();
}
public void ClearText(Func<AppQuery, AppQuery> query)
{
QueryWindows(query).First().Clear();
}
public void ClearText(Func<AppQuery, AppWebQuery> query)
{
throw new NotImplementedException();
}
public void ClearText(string marked)
{
QueryWindows(marked).First().Clear();
}
public void ClearText()
{
throw new NotImplementedException();
}
public IDevice Device { get; }
public void DismissKeyboard()
{
// No-op for Desktop, which is all we're doing right now
}
public void DoubleTap(Func<AppQuery, AppQuery> query)
{
DoubleTap(WinQuery.FromQuery(query));
}
public void DoubleTap(string marked)
{
DoubleTap(WinQuery.FromMarked(marked));
}
public void DoubleTapCoordinates(float x, float y)
{
throw new NotImplementedException();
}
public void DragAndDrop(Func<AppQuery, AppQuery> from, Func<AppQuery, AppQuery> to)
{
throw new NotImplementedException();
}
public void DragAndDrop(string from, string to)
{
throw new NotImplementedException();
}
public void DragCoordinates(float fromX, float fromY, float toX, float toY)
{
throw new NotImplementedException();
}
public void EnterText(string text)
{
_session.Keyboard.SendKeys(text);
}
public void EnterText(Func<AppQuery, AppQuery> query, string text)
{
QueryWindows(query).First().SendKeys(text);
}
public void EnterText(string marked, string text)
{
QueryWindows(marked).First().SendKeys(text);
}
public void EnterText(Func<AppQuery, AppWebQuery> query, string text)
{
throw new NotImplementedException();
}
public AppResult[] Flash(Func<AppQuery, AppQuery> query = null)
{
throw new NotImplementedException();
}
public AppResult[] Flash(string marked)
{
throw new NotImplementedException();
}
public object Invoke(string methodName, object argument = null)
{
return Invoke(methodName, new[] { argument });
}
public object Invoke(string methodName, object[] arguments)
{
if (methodName == "ContextClick")
{
// The IApp interface doesn't have a context click concept, and mapping TouchAndHold to
// context clicking would box us in if we have the option of running these tests on touch
// devices later. So we're going to use the back door.
ContextClick(arguments[0].ToString());
return null;
}
return null;
}
public void PinchToZoomIn(Func<AppQuery, AppQuery> query, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomIn(string marked, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomInCoordinates(float x, float y, TimeSpan? duration)
{
throw new NotImplementedException();
}
public void PinchToZoomOut(Func<AppQuery, AppQuery> query, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomOut(string marked, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomOutCoordinates(float x, float y, TimeSpan? duration)
{
throw new NotImplementedException();
}
public void PressEnter()
{
_session.Keyboard.PressKey(Keys.Enter);
}
public void PressVolumeDown()
{
throw new NotImplementedException();
}
public void PressVolumeUp()
{
throw new NotImplementedException();
}
public AppPrintHelper Print { get; }
public AppResult[] Query(Func<AppQuery, AppQuery> query = null)
{
ReadOnlyCollection<WindowsElement> elements = QueryWindows(WinQuery.FromQuery(query));
return elements.Select(ToAppResult).ToArray();
}
public AppResult[] Query(string marked)
{
ReadOnlyCollection<WindowsElement> elements = QueryWindows(marked);
return elements.Select(ToAppResult).ToArray();
}
public AppWebResult[] Query(Func<AppQuery, AppWebQuery> query)
{
throw new NotImplementedException();
}
public T[] Query<T>(Func<AppQuery, AppTypedSelector<T>> query)
{
AppTypedSelector<T> appTypedSelector = query(new AppQuery(QueryPlatform.iOS));
// Swiss-Army Chainsaw time
// We'll use reflection to dig into the query and get the element selector
// and the property value invocation in text form
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
Type selectorType = appTypedSelector.GetType();
PropertyInfo tokensProperty = selectorType.GetProperties(bindingFlags)
.First(t => t.PropertyType == typeof(IQueryToken[]));
var tokens = (IQueryToken[])tokensProperty.GetValue(appTypedSelector);
string selector = tokens[0].ToQueryString(QueryPlatform.iOS);
string invoke = tokens[1].ToCodeString();
// Now that we have them in text form, we can reinterpret them for Windows
WinQuery winQuery = WinQuery.FromRaw(selector);
// TODO hartez 2017/07/19 17:08:44 Make this a bit more resilient if the translation isn't there
string attribute = _translatePropertyAccessor[invoke.Substring(8).Replace("\")", "")];
ReadOnlyCollection<WindowsElement> elements = QueryWindows(winQuery);
foreach (WindowsElement e in elements)
{
string x = e.GetAttribute(attribute);
Debug.WriteLine($">>>>> WinDriverApp Query 261: {x}");
}
// TODO hartez 2017/07/19 17:09:14 Alas, for now this simply doesn't work. Waiting for WinAppDriver to implement it
return elements.Select(e => (T)Convert.ChangeType(e.GetAttribute(attribute), typeof(T))).ToArray();
}
public string[] Query(Func<AppQuery, InvokeJSAppQuery> query)
{
throw new NotImplementedException();
}
public void Repl()
{
throw new NotImplementedException();
}
public FileInfo Screenshot(string title)
{
// TODO hartez 2017/07/18 10:16:56 Verify that this is working; seems a bit too simple
string filename = $"{title}.png";
Screenshot screenshot = _session.GetScreenshot();
screenshot.SaveAsFile(filename, ImageFormat.Png);
return new FileInfo(filename);
}
public void ScrollDown(Func<AppQuery, AppQuery> withinQuery = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true)
{
if (withinQuery == null)
{
Scroll(null, true);
return;
}
WinQuery winQuery = WinQuery.FromQuery(withinQuery);
Scroll(winQuery, true);
}
public void ScrollDown(string withinMarked, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true)
{
WinQuery winQuery = WinQuery.FromMarked(withinMarked);
Scroll(winQuery, true);
}
public void ScrollDownTo(string toMarked, string withinMarked = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
ScrollTo(WinQuery.FromMarked(toMarked), withinMarked == null ? null : WinQuery.FromMarked(withinMarked), timeout);
}
public void ScrollDownTo(Func<AppQuery, AppWebQuery> toQuery, string withinMarked,
ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollDownTo(Func<AppQuery, AppQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null,
ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
ScrollTo(WinQuery.FromQuery(toQuery), withinQuery == null ? null : WinQuery.FromQuery(withinQuery), timeout);
}
public void ScrollDownTo(Func<AppQuery, AppWebQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null,
ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollTo(string toMarked, string withinMarked = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollUp(Func<AppQuery, AppQuery> query = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
if (query == null)
{
Scroll(null, false);
return;
}
WinQuery winQuery = WinQuery.FromQuery(query);
Scroll(winQuery, false);
}
public void ScrollUp(string withinMarked, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
WinQuery winQuery = WinQuery.FromMarked(withinMarked);
Scroll(winQuery, false);
}
public void ScrollUpTo(string toMarked, string withinMarked = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
ScrollTo(WinQuery.FromMarked(toMarked), withinMarked == null ? null : WinQuery.FromMarked(withinMarked), timeout,
down: false);
}
public void ScrollUpTo(Func<AppQuery, AppWebQuery> toQuery, string withinMarked,
ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollUpTo(Func<AppQuery, AppQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null,
ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
ScrollTo(WinQuery.FromQuery(toQuery), withinQuery == null ? null : WinQuery.FromQuery(withinQuery), timeout,
down: false);
}
public void ScrollUpTo(Func<AppQuery, AppWebQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null,
ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void SetOrientationLandscape()
{
// Deliberately leaving this as a no-op for now
// Trying to set the orientation on the Desktop (the only version of UWP we're testing for the moment)
// gives us a 405 Method Not Allowed, which makes sense. Haven't figured out how to determine
// whether we're in a mode which allows orientation, but if we were, the next line is probably how to set it.
//_session.Orientation = ScreenOrientation.Landscape;
}
public void SetOrientationPortrait()
{
// Deliberately leaving this as a no-op for now
// Trying to set the orientation on the Desktop (the only version of UWP we're testing for the moment)
// gives us a 405 Method Not Allowed, which makes sense. Haven't figured out how to determine
// whether we're in a mode which allows orientation, but if we were, the next line is probably how to set it.
//_session.Orientation = ScreenOrientation.Portrait;
}
public void SetSliderValue(string marked, double value)
{
throw new NotImplementedException();
}
public void SetSliderValue(Func<AppQuery, AppQuery> query, double value)
{
throw new NotImplementedException();
}
public void SwipeLeft()
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(string marked, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(Func<AppQuery, AppQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(Func<AppQuery, AppWebQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeRight()
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(string marked, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(Func<AppQuery, AppQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(Func<AppQuery, AppWebQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void Tap(Func<AppQuery, AppQuery> query)
{
WinQuery winQuery = WinQuery.FromQuery(query);
Tap(winQuery);
}
public void Tap(string marked)
{
WinQuery winQuery = WinQuery.FromMarked(marked);
Tap(winQuery);
}
public void Tap(Func<AppQuery, AppWebQuery> query)
{
throw new NotImplementedException();
}
public void TapCoordinates(float x, float y)
{
// Okay, this one's a bit complicated. For some reason, _session.Tap() with coordinates does not work
// (Filed https://github.com/Microsoft/WinAppDriver/issues/229 for that)
// But we can do the equivalent by manipulating the mouse. The mouse methods all take an ICoordinates
// object, and you'd think that the "coordinates" part of ICoordinates would have something do with
// where the mouse clicks. You'd be wrong. The coordinates parts of that object are ignored and it just
// clicks the center of whatever WindowsElement the ICoordinates refers to in 'AuxiliaryLocator'
// If we could just use the element, we wouldn't be tapping at specific coordinates, so that's not
// very helpful.
// Instead, we'll use MouseClickAt
MouseClickAt(x, y);
}
public ITestServer TestServer { get; }
public void TouchAndHold(Func<AppQuery, AppQuery> query)
{
throw new NotImplementedException();
}
public void TouchAndHold(string marked)
{
throw new NotImplementedException();
}
public void TouchAndHoldCoordinates(float x, float y)
{
throw new NotImplementedException();
}
public void WaitFor(Func<bool> predicate, string timeoutMessage = "Timed out waiting...", TimeSpan? timeout = null,
TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
throw new NotImplementedException();
}
public AppResult[] WaitForElement(Func<AppQuery, AppQuery> query,
string timeoutMessage = "Timed out waiting for element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(query);
return WaitForAtLeastOne(result, timeoutMessage, timeout, retryFrequency).Select(ToAppResult).ToArray();
}
public AppResult[] WaitForElement(string marked, string timeoutMessage = "Timed out waiting for element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(marked);
return WaitForAtLeastOne(result, timeoutMessage, timeout, retryFrequency).Select(ToAppResult).ToArray();
}
public AppWebResult[] WaitForElement(Func<AppQuery, AppWebQuery> query,
string timeoutMessage = "Timed out waiting for element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
throw new NotImplementedException();
}
public void WaitForNoElement(Func<AppQuery, AppQuery> query,
string timeoutMessage = "Timed out waiting for no element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(query);
WaitForNone(result, timeoutMessage, timeout, retryFrequency);
}
public void WaitForNoElement(string marked, string timeoutMessage = "Timed out waiting for no element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(marked);
WaitForNone(result, timeoutMessage, timeout, retryFrequency);
}
public void WaitForNoElement(Func<AppQuery, AppWebQuery> query,
string timeoutMessage = "Timed out waiting for no element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
throw new NotImplementedException();
}
public void ContextClick(string marked)
{
WindowsElement element = QueryWindows(marked).First();
PointF point = ElementToClickablePoint(element);
MouseClickAt(point.X, point.Y, ClickType.ContextClick);
}
internal void MouseClickAt(float x, float y, ClickType clickType = ClickType.SingleClick)
{
// Mouse clicking with ICoordinates doesn't work the way we'd like (see TapCoordinates comments),
// so we have to do some math on our own to get the mouse in the right spot
// So here's how we're working around it for the moment:
// 1. Get the Window viewport (which is a known-to-exist element)
// 2. Using the Window's ICoordinates and the MouseMove() overload with x/y offsets, move the pointer
// to the location we care about
// 3. Use the (undocumented, except in https://github.com/Microsoft/WinAppDriver/issues/118#issuecomment-269404335)
// null parameter for Mouse.Click() to click at the current pointer location
WindowsElement viewPort = GetViewPort();
int xOffset = viewPort.Coordinates.LocationInViewport.X;
int yOffset = viewPort.Coordinates.LocationInViewport.Y;
_session.Mouse.MouseMove(viewPort.Coordinates, (int)x - xOffset, (int)y - yOffset);
switch (clickType)
{
case ClickType.DoubleClick:
_session.Mouse.DoubleClick(null);
break;
case ClickType.ContextClick:
_session.Mouse.ContextClick(null);
break;
case ClickType.SingleClick:
default:
_session.Mouse.Click(null);
break;
}
}
void ClickOrTapElement(WindowsElement element)
{
try
{
// For most stuff, a simple click will work
element.Click();
}
catch (InvalidOperationException)
{
// Some elements aren't "clickable" from an automation perspective (e.g., Frame renders as a Border
// with content in it; if the content is just a TextBlock, we'll end up here)
// All is not lost; we can figure out the location of the element in in the application window
// and Tap in that spot
PointF p = ElementToClickablePoint(element);
TapCoordinates(p.X, p.Y);
}
}
void DoubleClickElement(WindowsElement element)
{
PointF point = ElementToClickablePoint(element);
MouseClickAt(point.X, point.Y, clickType: ClickType.DoubleClick);
}
void DoubleTap(WinQuery query)
{
WindowsElement element = FindFirstElement(query);
if (element == null)
{
return;
}
DoubleClickElement(element);
}
PointF ElementToClickablePoint(WindowsElement element)
{
PointF clickablePoint = GetClickablePoint(element);
WindowsElement window = GetWindow();
PointF origin = GetOriginOfBoundingRectangle(window);
// Use the coordinates in the app window's viewport relative to the window's origin
return new PointF(clickablePoint.X - origin.X, clickablePoint.Y - origin.Y);
}
ReadOnlyCollection<WindowsElement> FilterControlType(IEnumerable<WindowsElement> elements, string controlType)
{
string tag = controlType;
if (tag == "*")
{
return new ReadOnlyCollection<WindowsElement>(elements.ToList());
}
if (_controlNameToTag.ContainsKey(controlType))
{
tag = _controlNameToTag[controlType];
}
return new ReadOnlyCollection<WindowsElement>(elements.Where(element => element.TagName == tag).ToList());
}
WindowsElement FindFirstElement(WinQuery query)
{
Func<ReadOnlyCollection<WindowsElement>> fquery = () => QueryWindows(query);
string timeoutMessage = $"Timed out waiting for element: {query.Raw}";
ReadOnlyCollection<WindowsElement> results = WaitForAtLeastOne(fquery, timeoutMessage);
WindowsElement element = results.FirstOrDefault();
return element;
}
static PointF GetBottomRightOfBoundingRectangle(WindowsElement element)
{
string vpcpString = element.GetAttribute("BoundingRectangle");
// returned string format looks like:
// Left:-1868 Top:382 Width:1013 Height:680
string[] vpparts = vpcpString.Split(new[] { ':', ' ' }, StringSplitOptions.RemoveEmptyEntries);
float vpx = float.Parse(vpparts[1]);
float vpy = float.Parse(vpparts[3]);
float vpw = float.Parse(vpparts[5]);
float vph = float.Parse(vpparts[7]);
return new PointF(vpx + vpw, vpy + vph);
}
static PointF GetClickablePoint(WindowsElement element)
{
string cpString = element.GetAttribute("ClickablePoint");
string[] parts = cpString.Split(',');
float x = float.Parse(parts[0]);
float y = float.Parse(parts[1]);
return new PointF(x, y);
}
static PointF GetOriginOfBoundingRectangle(WindowsElement element)
{
string vpcpString = element.GetAttribute("BoundingRectangle");
// returned string format looks like:
// Left:-1868 Top:382 Width:1013 Height:680
string[] vpparts = vpcpString.Split(new[] { ':', ' ' }, StringSplitOptions.RemoveEmptyEntries);
float vpx = float.Parse(vpparts[1]);
float vpy = float.Parse(vpparts[3]);
return new PointF(vpx, vpy);
}
static PointF GetTopRightOfBoundingRectangle(WindowsElement element)
{
string vpcpString = element.GetAttribute("BoundingRectangle");
// returned string format looks like:
// Left:-1868 Top:382 Width:1013 Height:680
string[] vpparts = vpcpString.Split(new[] { ':', ' ' }, StringSplitOptions.RemoveEmptyEntries);
float vpx = float.Parse(vpparts[1]);
float vpy = float.Parse(vpparts[3]);
float vpw = float.Parse(vpparts[5]);
return new PointF(vpx + vpw, vpy);
}
WindowsElement GetViewPort()
{
if (_viewPort != null)
{
return _viewPort;
}
ReadOnlyCollection<WindowsElement> candidates = QueryWindows(AppName);
_viewPort = candidates[3]; // We really just want the viewport; skip the full window, title bar, min/max buttons...
int xOffset = _viewPort.Coordinates.LocationInViewport.X;
if (xOffset > 1) // Everything having to do with scrolling right now is a horrid kludge
{
// This makes the scrolling stuff work correctly on a higher density screen (e.g. MBP running Windows)
_scrollBarOffset = -70;
}
return _viewPort;
}
WindowsElement GetWindow()
{
if (_window != null)
{
return _window;
}
_window = QueryWindows(AppName)[0];
return _window;
}
void OriginMouse()
{
WindowsElement viewPort = GetViewPort();
int xOffset = viewPort.Coordinates.LocationInViewport.X;
int yOffset = viewPort.Coordinates.LocationInViewport.Y;
_session.Mouse.MouseMove(viewPort.Coordinates, xOffset, yOffset);
}
ReadOnlyCollection<WindowsElement> QueryWindows(WinQuery query)
{
ReadOnlyCollection<WindowsElement> resultByAccessibilityId = _session.FindElementsByAccessibilityId(query.Marked);
ReadOnlyCollection<WindowsElement> resultByName = _session.FindElementsByName(query.Marked);
IEnumerable<WindowsElement> result = resultByAccessibilityId.Concat(resultByName);
// TODO hartez 2017/10/30 09:47:44 Should this be == "*" || == "TextBox"?
// what about other controls where we might be looking by content? TextBlock?
if (query.ControlType == "*")
{
IEnumerable<WindowsElement> textBoxesByContent =
_session.FindElementsByClassName("TextBox").Where(e => e.Text == query.Marked);
result = result.Concat(textBoxesByContent);
}
return FilterControlType(result, query.ControlType);
}
ReadOnlyCollection<WindowsElement> QueryWindows(string marked)
{
WinQuery winQuery = WinQuery.FromMarked(marked);
return QueryWindows(winQuery);
}
ReadOnlyCollection<WindowsElement> QueryWindows(Func<AppQuery, AppQuery> query)
{
WinQuery winQuery = WinQuery.FromQuery(query);
return QueryWindows(winQuery);
}
void Scroll(WinQuery query, bool down)
{
if (query == null)
{
ScrollClick(GetWindow(), down);
return;
}
WindowsElement element = FindFirstElement(query);
ScrollClick(element, down);
}
void ScrollClick(WindowsElement element, bool down = true)
{
PointF point = down ? GetBottomRightOfBoundingRectangle(element) : GetTopRightOfBoundingRectangle(element);
PointF origin = GetOriginOfBoundingRectangle(GetWindow());
var realPoint = new PointF(point.X - origin.X, point.Y - origin.Y);
int xOffset = _scrollBarOffset;
if (origin.X < 0)
{
// The scrollbar's in a slightly different place relative to the window bounds
// if we're running on the left monitor (which I like to do)
xOffset = xOffset * 3;
}
float finalX = realPoint.X - xOffset;
float finalY = realPoint.Y - (down ? 15 : -15);
OriginMouse();
MouseClickAt(finalX, finalY, ClickType.SingleClick);
}
void ScrollTo(WinQuery toQuery, WinQuery withinQuery, TimeSpan? timeout = null, bool down = true)
{
timeout = timeout ?? TimeSpan.FromSeconds(5);
DateTime start = DateTime.Now;
while (true)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(toQuery);
TimeSpan iterationTimeout = TimeSpan.FromMilliseconds(0);
TimeSpan retryFrequency = TimeSpan.FromMilliseconds(0);
try
{
ReadOnlyCollection<WindowsElement> found = WaitForAtLeastOne(result, timeoutMessage: null,
timeout: iterationTimeout, retryFrequency: retryFrequency);
if (found.Count > 0)
{
// Success
return;
}
}
catch (TimeoutException ex)
{
// Haven't found it yet, keep scrolling
}
long elapsed = DateTime.Now.Subtract(start).Ticks;
if (elapsed >= timeout.Value.Ticks)
{
Debug.WriteLine($">>>>> {elapsed} ticks elapsed, timeout value is {timeout.Value.Ticks}");
throw new TimeoutException($"Timed out scrolling to {toQuery}");
}
Scroll(withinQuery, down);
}
}
void Tap(WinQuery query)
{
WindowsElement element = FindFirstElement(query);
if (element == null)
{
return;
}
ClickOrTapElement(element);
}
static AppRect ToAppRect(WindowsElement windowsElement)
{
try
{
var result = new AppRect
{
X = windowsElement.Location.X,
Y = windowsElement.Location.Y,
Height = windowsElement.Size.Height,
Width = windowsElement.Size.Width
};
result.CenterX = result.X + result.Width / 2;
result.CenterY = result.Y + result.Height / 2;
return result;
}
catch (Exception ex)
{
Debug.WriteLine(
$"Warning: error determining AppRect for {windowsElement}; "
+ $"if this is a Label with a modified Text value, it might be confusing Windows automation. " +
$"{ex}");
}
return null;
}
static AppResult ToAppResult(WindowsElement windowsElement)
{
return new AppResult
{
Rect = ToAppRect(windowsElement),
Label = windowsElement.Id, // Not entirely sure about this one
Description = windowsElement.Text, // or this one
Enabled = windowsElement.Enabled,
Id = windowsElement.Id
};
}
static ReadOnlyCollection<WindowsElement> Wait(Func<ReadOnlyCollection<WindowsElement>> query,
Func<int, bool> satisfactory,
string timeoutMessage = null,
TimeSpan? timeout = null, TimeSpan? retryFrequency = null)
{
timeout = timeout ?? TimeSpan.FromSeconds(5);
retryFrequency = retryFrequency ?? TimeSpan.FromMilliseconds(500);
timeoutMessage = timeoutMessage ?? "Timed out on query.";
DateTime start = DateTime.Now;
ReadOnlyCollection<WindowsElement> result = query();
while (!satisfactory(result.Count))
{
long elapsed = DateTime.Now.Subtract(start).Ticks;
if (elapsed >= timeout.Value.Ticks)
{
Debug.WriteLine($">>>>> {elapsed} ticks elapsed, timeout value is {timeout.Value.Ticks}");
throw new TimeoutException(timeoutMessage);
}
Task.Delay(retryFrequency.Value.Milliseconds).Wait();
result = query();
}
return result;
}
static ReadOnlyCollection<WindowsElement> WaitForAtLeastOne(Func<ReadOnlyCollection<WindowsElement>> query,
string timeoutMessage = null,
TimeSpan? timeout = null, TimeSpan? retryFrequency = null)
{
return Wait(query, i => i > 0, timeoutMessage, timeout, retryFrequency);
}
void WaitForNone(Func<ReadOnlyCollection<WindowsElement>> query,
string timeoutMessage = null,
TimeSpan? timeout = null, TimeSpan? retryFrequency = null)
{
Wait(query, i => i == 0, timeoutMessage, timeout, retryFrequency);
}
internal enum ClickType
{
SingleClick,
DoubleClick,
ContextClick
}
}
}

Просмотреть файл

@ -0,0 +1,67 @@
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Xamarin.UITest.Queries;
namespace Xamarin.Forms.Core.UITests
{
internal class WinQuery
{
public static WinQuery FromQuery(Func<AppQuery, AppQuery> query)
{
var raw = GetRawQuery(query);
return FromRaw(raw);
}
public static WinQuery FromMarked(string marked)
{
return new WinQuery("*", marked, $"* '{marked}'");
}
public static WinQuery FromRaw(string raw)
{
Debug.WriteLine($">>>>> Converting raw query '{raw}' to {nameof(WinQuery)}");
var match = Regex.Match(raw, @"(.*)\s(marked|text):'((.|\n)*)'");
var controlType = match.Groups[1].Captures[0].Value;
var marked = match.Groups[3].Captures[0].Value;
// Just ignoring everything else for now (parent, index statements, etc)
var result = new WinQuery(controlType, marked, raw);
Debug.WriteLine($">>>>> WinQuery is: {result}");
return result;
}
static string GetRawQuery(Func<AppQuery, AppQuery> query = null)
{
if (query == null)
{
return string.Empty;
}
// When we pull out the iOS query it's got any instances of "'" escaped with "\", need to fix that up
return query(new AppQuery(QueryPlatform.iOS)).ToString().Replace("\\'", "'");
}
WinQuery(string controlType, string marked, string raw)
{
ControlType = controlType;
Marked = marked;
Raw = raw;
}
public string ControlType { get; }
public string Marked { get; }
public string Raw { get; }
public override string ToString()
{
return $"{nameof(ControlType)}: {ControlType}, {nameof(Marked)}: {Marked}";
}
}
}

Просмотреть файл

@ -1,14 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Resources;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium.MultiTouch;
@ -17,7 +10,6 @@ using OpenQA.Selenium.Interactions.Internal;
using OpenQA.Selenium.Remote;
using Xamarin.Forms.Xaml;
using Xamarin.UITest;
using Xamarin.UITest.Queries;
namespace Xamarin.Forms.Core.UITests
{
@ -35,13 +27,21 @@ namespace Xamarin.Forms.Core.UITests
appCapabilities.SetCapability("deviceName", "WindowsPC");
Session = new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), appCapabilities);
Assert.IsNotNull(Session);
Session.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(2));
Session.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(1));
Reset();
}
return new WinDriverApp(Session);
}
internal static void HandleAppClosed(Exception ex)
{
if (ex is InvalidOperationException && ex.Message == "Currently selected window has been closed")
{
Session = null;
}
}
public static void Reset()
{
try
@ -50,706 +50,10 @@ namespace Xamarin.Forms.Core.UITests
}
catch (Exception ex)
{
HandleAppClosed(ex);
Debug.WriteLine($">>>>> WindowsTestBase ConfigureApp 49: {ex}");
throw;
}
}
}
public class WinDriverApp : IApp
{
readonly WindowsDriver<WindowsElement> _session;
protected static RemoteTouchScreen _touchScreen;
public WinDriverApp(WindowsDriver<WindowsElement> session)
{
_session = session;
_touchScreen = new RemoteTouchScreen(session);
}
readonly Dictionary<string, string> _controlNameToTag = new Dictionary<string, string>
{
{"button", "ControlType.Button"}
};
ReadOnlyCollection<WindowsElement> FilterControlType(IEnumerable<WindowsElement> elements, string controlType)
{
var tag = controlType;
if (tag == "*")
{
return new ReadOnlyCollection<WindowsElement>(elements.ToList());
}
if (_controlNameToTag.ContainsKey(controlType))
{
tag = _controlNameToTag[controlType];
}
return new ReadOnlyCollection<WindowsElement>(elements.Where(element => element.TagName == tag).ToList());
}
class WinQuery
{
public static WinQuery FromQuery(Func<AppQuery, AppQuery> query)
{
var raw = GetRawQuery(query);
return FromRaw(raw);
}
public static WinQuery FromMarked(string marked)
{
return new WinQuery("*", marked, $"* '{marked}'");
}
public static WinQuery FromRaw(string raw)
{
Debug.WriteLine($">>>>> Converting raw query '{raw}' to {nameof(WinQuery)}");
var match = Regex.Match(raw, @"(.*)\s(marked|text):'(.*)'");
var controlType = match.Groups[1].Captures[0].Value;
var marked = match.Groups[3].Captures[0].Value;
// Just ignoring everything else for now (parent, index statements, etc)
return new WinQuery(controlType, marked, raw);
}
static string GetRawQuery(Func<AppQuery, AppQuery> query = null)
{
if (query == null)
{
return string.Empty;
}
return query(new AppQuery(QueryPlatform.iOS)).ToString();
}
WinQuery(string controlType, string marked, string raw)
{
ControlType = controlType;
Marked = marked;
Raw = raw;
}
public string ControlType { get; }
public string Marked { get; }
public string Raw { get; }
public override string ToString()
{
return $"{nameof(ControlType)}: {ControlType}, {nameof(Marked)}: {Marked}";
}
}
ReadOnlyCollection<WindowsElement> QueryWindows(WinQuery query)
{
var resultByName = _session.FindElementsByName(query.Marked);
var resultByAccessibilityId = _session.FindElementsByAccessibilityId(query.Marked);
var result = resultByName
.Concat(resultByAccessibilityId);
if (query.ControlType == "*")
{
var textBoxesByContent = _session.FindElementsByClassName("TextBox").Where(e => e.Text == query.Marked);
result = result.Concat(textBoxesByContent);
}
return FilterControlType(result, query.ControlType);
}
ReadOnlyCollection<WindowsElement> QueryWindows(string marked)
{
var winQuery = WinQuery.FromMarked(marked);
return QueryWindows(winQuery);
}
ReadOnlyCollection<WindowsElement> QueryWindows(Func<AppQuery, AppQuery> query)
{
var winQuery = WinQuery.FromQuery(query);
return QueryWindows(winQuery);
}
static AppRect ToAppRect(WindowsElement windowsElement)
{
var result = new AppRect
{
X = windowsElement.Location.X,
Y = windowsElement.Location.Y,
Height = windowsElement.Size.Height,
Width = windowsElement.Size.Width
};
result.CenterX = result.X + result.Width / 2;
result.CenterY = result.Y + result.Height / 2;
return result;
}
static AppResult ToAppResult(WindowsElement windowsElement)
{
return new AppResult
{
Rect = ToAppRect(windowsElement),
Label = windowsElement.Id, // Not entirely sure about this one
Description = windowsElement.Text, // or this one
Enabled = windowsElement.Enabled,
Id = windowsElement.Id
};
}
public AppResult[] Query(Func<AppQuery, AppQuery> query = null)
{
var elements = QueryWindows(WinQuery.FromQuery(query));
return elements.Select(ToAppResult).ToArray();
}
public AppResult[] Query(string marked)
{
var elements = QueryWindows(marked);
return elements.Select(ToAppResult).ToArray();
}
public AppWebResult[] Query(Func<AppQuery, AppWebQuery> query)
{
throw new NotImplementedException();
}
readonly Dictionary<string, string> _translatePropertyAccessor = new Dictionary<string, string>
{
{"getAlpha", "Opacity"}
};
public T[] Query<T>(Func<AppQuery, AppTypedSelector<T>> query)
{
var appTypedSelector = query(new AppQuery(QueryPlatform.iOS));
// Swiss-Army Chainsaw time
// We'll use reflection to dig into the query and get the element selector
// and the property value invocation in text form
var bindingFlags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;
var selectorType = appTypedSelector.GetType();
var tokensProperty = selectorType.GetProperties(bindingFlags)
.First(t => t.PropertyType == typeof(Xamarin.UITest.Queries.Tokens.IQueryToken[]));
var tokens = (Xamarin.UITest.Queries.Tokens.IQueryToken[])tokensProperty.GetValue(appTypedSelector);
// Output some debugging info
//foreach (var t in tokens)
//{
// Debug.WriteLine($">>>>> WinDriverApp Query 208: {t.ToQueryString(QueryPlatform.iOS)}");
// Debug.WriteLine($">>>>> WinDriverApp Query 208: {t.ToCodeString()}");
//}
var selector = tokens[0].ToQueryString(QueryPlatform.iOS);
var invoke = tokens[1].ToCodeString();
// Now that we have them in text form, we can reinterpret them for Windows
var winQuery = WinQuery.FromRaw(selector);
// TODO hartez 2017/07/19 17:08:44 Make this a bit more resilient if the translation isn't there
var attribute = _translatePropertyAccessor[invoke.Substring(8).Replace("\")", "")];
var elements = QueryWindows(winQuery);
// TODO hartez 2017/07/19 17:09:14 Alas, for now this simply doesn't work. Waiting for WinAppDrive to implement it
return elements.Select(e => (T)Convert.ChangeType(e.GetAttribute(attribute), typeof(T))).ToArray();
}
public string[] Query(Func<AppQuery, InvokeJSAppQuery> query)
{
throw new NotImplementedException();
}
public AppResult[] Flash(Func<AppQuery, AppQuery> query = null)
{
throw new NotImplementedException();
}
public AppResult[] Flash(string marked)
{
throw new NotImplementedException();
}
public void EnterText(string text)
{
_session.Keyboard.SendKeys(text);
}
public void EnterText(Func<AppQuery, AppQuery> query, string text)
{
QueryWindows(query).First().SendKeys(text);
}
public void EnterText(string marked, string text)
{
QueryWindows(marked).First().SendKeys(text);
}
public void EnterText(Func<AppQuery, AppWebQuery> query, string text)
{
throw new NotImplementedException();
}
public void ClearText(Func<AppQuery, AppQuery> query)
{
throw new NotImplementedException();
}
public void ClearText(Func<AppQuery, AppWebQuery> query)
{
throw new NotImplementedException();
}
public void ClearText(string marked)
{
throw new NotImplementedException();
}
public void ClearText()
{
throw new NotImplementedException();
}
public void PressEnter()
{
_session.Keyboard.PressKey(Keys.Enter);
}
public void DismissKeyboard()
{
// No-op for Desktop, which is all we're doing right now
}
public void Tap(Func<AppQuery, AppQuery> query)
{
var winQuery = WinQuery.FromQuery(query);
Tap(winQuery);
}
public void Tap(string marked)
{
var winQuery = WinQuery.FromMarked(marked);
Tap(winQuery);
}
void Tap(WinQuery query, int taps = 1)
{
Func<ReadOnlyCollection<WindowsElement>> fquery = () => QueryWindows(query);
var timeoutMessage = $"Timed out waiting for element: {query.Raw}";
var results = WaitForAtLeastOne(fquery, timeoutMessage);
if (results.Any())
{
var element = results.First();
for (int n = 0; n < taps; n++)
{
element.Click();
}
}
}
public void Tap(Func<AppQuery, AppWebQuery> query)
{
throw new NotImplementedException();
}
public void TapCoordinates(float x, float y)
{
// Okay, this one's a bit complicated. For some reason, _session.Tap() with coordinates does not work
// (Filed https://github.com/Microsoft/WinAppDriver/issues/229 for that)
// But we can do the equivalent by manipulating the mouse. The mouse methods all take an ICoordinates
// object, and you'd think that the "coordinates" part of ICoordinates would have something do with
// where the mouse clicks. You'd be wrong. The coordinates parts of that object are ignored and it just
// clicks the center of whatever WindowsElement the ICoordinates refers to in 'AuxiliaryLocator'
// If we could just use the element, we wouldn't be tapping at specific coordinates, so that's not
// very helpful.
// So here's how we're working around it for the moment:
// 1. Get the Window viewport (which is a known-to-exist element)
// 2. Using the Window's ICoordinates and the MouseMove() overload with x/y offsets, move the pointer
// to the location we care about
// 3. Use the (undocumented, except in https://github.com/Microsoft/WinAppDriver/issues/118#issuecomment-269404335)
// null parameter for Mouse.Click() to click at the current pointer location
var candidates = QueryWindows("Xamarin.Forms.ControlGallery.WindowsUniversal");
var viewPort = candidates[3]; // We really just want the viewport; skip the full window, title bar, min/max buttons...
var xOffset = viewPort.Coordinates.LocationInViewport.X;
var yOffset = viewPort.Coordinates.LocationInViewport.Y;
_session.Mouse.MouseMove(viewPort.Coordinates, (int)x - xOffset, (int)y - yOffset);
_session.Mouse.Click(null);
}
public void TouchAndHold(Func<AppQuery, AppQuery> query)
{
throw new NotImplementedException();
}
public void TouchAndHold(string marked)
{
throw new NotImplementedException();
}
public void TouchAndHoldCoordinates(float x, float y)
{
throw new NotImplementedException();
}
public void DoubleTap(Func<AppQuery, AppQuery> query)
{
var winQuery = WinQuery.FromQuery(query);
Tap(winQuery, 2);
}
public void DoubleTap(string marked)
{
var winQuery = WinQuery.FromMarked(marked);
Tap(winQuery, 2);
}
public void DoubleTapCoordinates(float x, float y)
{
throw new NotImplementedException();
}
public void PinchToZoomIn(Func<AppQuery, AppQuery> query, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomIn(string marked, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomInCoordinates(float x, float y, TimeSpan? duration)
{
throw new NotImplementedException();
}
public void PinchToZoomOut(Func<AppQuery, AppQuery> query, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomOut(string marked, TimeSpan? duration = null)
{
throw new NotImplementedException();
}
public void PinchToZoomOutCoordinates(float x, float y, TimeSpan? duration)
{
throw new NotImplementedException();
}
public void WaitFor(Func<bool> predicate, string timeoutMessage = "Timed out waiting...", TimeSpan? timeout = null,
TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
throw new NotImplementedException();
}
ReadOnlyCollection<WindowsElement> WaitForAtLeastOne(Func<ReadOnlyCollection<WindowsElement>> query,
string timeoutMessage = null,
TimeSpan? timeout = null, TimeSpan? retryFrequency = null)
{
return Wait(query, i => i > 0, timeoutMessage, timeout, retryFrequency);
}
void WaitForNone(Func<ReadOnlyCollection<WindowsElement>> query,
string timeoutMessage = null,
TimeSpan? timeout = null, TimeSpan? retryFrequency = null)
{
Wait(query, i => i == 0, timeoutMessage, timeout, retryFrequency);
}
ReadOnlyCollection<WindowsElement> Wait(Func<ReadOnlyCollection<WindowsElement>> query,
Func<int, bool> satisfactory,
string timeoutMessage = null,
TimeSpan? timeout = null, TimeSpan? retryFrequency = null)
{
timeout = timeout ?? TimeSpan.FromSeconds(5);
retryFrequency = retryFrequency ?? TimeSpan.FromMilliseconds(500);
timeoutMessage = timeoutMessage ?? "Timed out on query.";
var start = DateTime.Now;
var result = query();
while (!satisfactory(result.Count))
{
if (DateTime.Now.Subtract(start).Ticks >= timeout.Value.Ticks)
{
throw new TimeoutException(timeoutMessage);
}
Task.Delay(retryFrequency.Value.Milliseconds).Wait();
}
return result;
}
public AppResult[] WaitForElement(Func<AppQuery, AppQuery> query, string timeoutMessage = "Timed out waiting for element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(query);
return WaitForAtLeastOne(result, timeoutMessage, timeout, retryFrequency).Select(ToAppResult).ToArray();
}
public AppResult[] WaitForElement(string marked, string timeoutMessage = "Timed out waiting for element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(marked);
return WaitForAtLeastOne(result, timeoutMessage, timeout, retryFrequency).Select(ToAppResult).ToArray();
}
public AppWebResult[] WaitForElement(Func<AppQuery, AppWebQuery> query, string timeoutMessage = "Timed out waiting for element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
throw new NotImplementedException();
}
public void WaitForNoElement(Func<AppQuery, AppQuery> query, string timeoutMessage = "Timed out waiting for no element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(query);
WaitForNone(result, timeoutMessage, timeout, retryFrequency);
}
public void WaitForNoElement(string marked, string timeoutMessage = "Timed out waiting for no element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
Func<ReadOnlyCollection<WindowsElement>> result = () => QueryWindows(marked);
WaitForNone(result, timeoutMessage, timeout, retryFrequency);
}
public void WaitForNoElement(Func<AppQuery, AppWebQuery> query, string timeoutMessage = "Timed out waiting for no element...",
TimeSpan? timeout = null, TimeSpan? retryFrequency = null, TimeSpan? postTimeout = null)
{
throw new NotImplementedException();
}
public FileInfo Screenshot(string title)
{
// TODO hartez 2017/07/18 10:16:56 Verify that this is working; seems a bit too simple
var filename = $"{title}.png";
var screenshot = _session.GetScreenshot();
screenshot.SaveAsFile(filename, ImageFormat.Png);
return new FileInfo(filename);
}
public void SwipeRight()
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(string marked, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeLeft()
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(string marked, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(Func<AppQuery, AppQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeLeftToRight(Func<AppQuery, AppWebQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(Func<AppQuery, AppQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void SwipeRightToLeft(Func<AppQuery, AppWebQuery> query, double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void ScrollUp(Func<AppQuery, AppQuery> query = null, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void ScrollUp(string withinMarked, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67, int swipeSpeed = 500,
bool withInertia = true)
{
throw new NotImplementedException();
}
public void ScrollDown(Func<AppQuery, AppQuery> withinQuery = null, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void ScrollDown(string withinMarked, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true)
{
throw new NotImplementedException();
}
public void ScrollTo(string toMarked, string withinMarked = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollUpTo(string toMarked, string withinMarked = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollUpTo(Func<AppQuery, AppWebQuery> toQuery, string withinMarked, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollDownTo(string toMarked, string withinMarked = null, ScrollStrategy strategy = ScrollStrategy.Auto,
double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollDownTo(Func<AppQuery, AppWebQuery> toQuery, string withinMarked, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollUpTo(Func<AppQuery, AppQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollUpTo(Func<AppQuery, AppWebQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollDownTo(Func<AppQuery, AppQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void ScrollDownTo(Func<AppQuery, AppWebQuery> toQuery, Func<AppQuery, AppQuery> withinQuery = null, ScrollStrategy strategy = ScrollStrategy.Auto, double swipePercentage = 0.67,
int swipeSpeed = 500, bool withInertia = true, TimeSpan? timeout = null)
{
throw new NotImplementedException();
}
public void SetOrientationPortrait()
{
// Deliberately leaving this as a no-op for now
// Trying to set the orientation on the Desktop (the only version of UWP we're testing for the moment)
// gives us a 405 Method Not Allowed, which makes sense. Haven't figured out how to determine
// whether we're in a mode which allows orientation, but if we were, the next line is probably how to set it.
//_session.Orientation = ScreenOrientation.Portrait;
}
public void SetOrientationLandscape()
{
// Deliberately leaving this as a no-op for now
// Trying to set the orientation on the Desktop (the only version of UWP we're testing for the moment)
// gives us a 405 Method Not Allowed, which makes sense. Haven't figured out how to determine
// whether we're in a mode which allows orientation, but if we were, the next line is probably how to set it.
//_session.Orientation = ScreenOrientation.Landscape;
}
public void Repl()
{
throw new NotImplementedException();
}
public void Back()
{
QueryWindows("Back").First().Click();
}
public void PressVolumeUp()
{
throw new NotImplementedException();
}
public void PressVolumeDown()
{
throw new NotImplementedException();
}
public object Invoke(string methodName, object argument = null)
{
throw new NotImplementedException();
}
public object Invoke(string methodName, object[] arguments)
{
throw new NotImplementedException();
}
public void DragCoordinates(float fromX, float fromY, float toX, float toY)
{
throw new NotImplementedException();
}
public void DragAndDrop(Func<AppQuery, AppQuery> @from, Func<AppQuery, AppQuery> to)
{
throw new NotImplementedException();
}
public void DragAndDrop(string @from, string to)
{
throw new NotImplementedException();
}
public void SetSliderValue(string marked, double value)
{
throw new NotImplementedException();
}
public void SetSliderValue(Func<AppQuery, AppQuery> query, double value)
{
throw new NotImplementedException();
}
public AppPrintHelper Print { get; }
public IDevice Device { get; }
public ITestServer TestServer { get; }
}
}

Просмотреть файл

@ -0,0 +1,44 @@
using System;
using OpenQA.Selenium.Appium.Windows;
using Xamarin.UITest;
namespace Xamarin.Forms.Core.UITests
{
internal class WindowsTestServer : ITestServer
{
readonly WindowsDriver<WindowsElement> _session;
public WindowsTestServer(WindowsDriver<WindowsElement> session)
{
_session = session;
}
public string Post(string endpoint, object arguments = null)
{
throw new NotImplementedException();
}
public string Put(string endpoint, byte[] data)
{
throw new NotImplementedException();
}
public string Get(string endpoint)
{
if (endpoint == "version")
{
try
{
return _session.CurrentWindowHandle;
}
catch (Exception exception)
{
WindowsTestBase.HandleAppClosed(exception);
throw;
}
}
return endpoint;
}
}
}

Просмотреть файл

@ -74,6 +74,9 @@
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WindowsTestBase.cs" />
<Compile Include="WindowsTestServer.cs" />
<Compile Include="WinDriverApp.cs" />
<Compile Include="WinQuery.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

Просмотреть файл

@ -0,0 +1,12 @@
# Running the UI Tests on UWP
To run the tests you'll need to install the latest release of [WinAppDriver](https://github.com/Microsoft/WinAppDriver).
Make sure you've built and deployed the UWP version of ControlGallery on the machine where you're running the tests. Run WinAppDriver.exe (if you installed it in the default location, it will be "C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe").
With WinAppDriver running, start the tests with whatever test runner you normally use. The tests will take care of launching ControlGallery.
Now just sit back and watch the tests run. At the moment, WinAppDriver and our implementation of IApp for UWP have to take control of the mouse and keyboard to run these tests, so interacting with the test machine will probably interfere with the tests. (You may be able to work around this by running the tests in the Simulator; I've had mixed results and some blue screens when trying this, but good luck.)
Currently we can only run the tests against the desktop UWP application.

Просмотреть файл

@ -1,5 +1,8 @@
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Xamarin.Forms.PlatformConfiguration.WindowsSpecific;
@ -85,7 +88,35 @@ namespace Xamarin.Forms.Platform.WinRT
#endif
TaskCompletionSource<CommandBar> tcs = _commandBarTcs;
tcs?.SetResult(_commandBar);
tcs?.SetResult(_commandBar);
}
protected override DependencyObject GetContainerForItemOverride()
{
var containerItem = base.GetContainerForItemOverride();
var pivotItem = containerItem as PivotItem;
if (pivotItem != null)
{
// We need to know when the data context changes so we can set the automation name to the page title
pivotItem.DataContextChanged += SetPivotItemAutomationName;
}
return containerItem;
}
static void SetPivotItemAutomationName(FrameworkElement frameworkElement,
DataContextChangedEventArgs dataContextChangedEventArgs)
{
var pivotItem = frameworkElement as PivotItem;
var page = dataContextChangedEventArgs.NewValue as Page;
if (pivotItem != null && page?.Title != null)
{
// This way we can find tabs with automation (for testing, etc.)
Windows.UI.Xaml.Automation.AutomationProperties.SetName(pivotItem, page.Title);
}
}
}
}

Просмотреть файл

@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.ComponentModel;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
@ -320,6 +321,11 @@ namespace Xamarin.Forms.Platform.WinRT
((FrameworkElement)Content).DataContext = newCell;
}
protected override AutomationPeer OnCreateAutomationPeer()
{
return new FrameworkElementAutomationPeer(this);
}
void UpdateFlowDirection(Cell newCell)
{
if (newCell is ViewCell)

Просмотреть файл

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
@ -692,5 +695,16 @@ namespace Xamarin.Forms.Platform.WinRT
bool _deferSelection = false;
Tuple<object, SelectedItemChangedEventArgs> _deferredSelectedItemChangedEvent;
#if WINDOWS_UWP
protected override AutomationPeer OnCreateAutomationPeer()
{
return List == null
? new FrameworkElementAutomationPeer(this)
: new ListViewAutomationPeer(List);
}
#endif
}
}