maui-linux/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issu.../TestPages/TestPages.cs

797 строки
16 KiB
C#

using System;
using System.Reflection;
using Xamarin.Forms.CustomAttributes;
using System.IO;
#if UITEST
using Xamarin.Forms.Core.UITests;
using NUnit.Framework;
using Xamarin.UITest;
// Apply the default category of "Issues" to all of the tests in this assembly
// We use this as a catch-all for tests which haven't been individually categorized
[assembly: Category("Issues")]
#endif
namespace Xamarin.Forms.Controls
{
internal static class AppPaths
{
public static string ApkPath = "../../../Xamarin.Forms.ControlGallery.Android/bin/Debug/AndroidControlGallery.AndroidControlGallery-Signed.apk";
public static string MacOSPath = "../../../Xamarin.Forms.ControlGallery.MacOS/bin/Debug/Xamarin.Forms.ControlGallery.MacOS.app";
// Have to continue using the old BundleId for now; Test Cloud doesn't like
// when you change the BundleId
public static string BundleId = "com.xamarin.quickui.controlgallery";
// Have to continue using the old BundleId for now; Test Cloud doesn't like
// when you change the BundleId
public static string MacOSBundleId = "com.xamarin.xamarin-forms-controlgallery-macos";
}
#if UITEST
internal static class AppSetup
{
static IApp InitializeApp()
{
IApp app = null;
#if __ANDROID__
app = InitializeAndroidApp();
#elif __IOS__
app = InitializeiOSApp();
#elif __MACOS__
Xamarin.UITest.Desktop.TestAgent.Start();
app = InitializeMacOSApp();
#elif __WINDOWS__
app = InitializeUWPApp();
#endif
if (app == null)
throw new NullReferenceException("App was not initialized.");
// Wrap the app in ScreenshotConditional so it only takes screenshots if the SCREENSHOTS symbol is specified
return new ScreenshotConditionalApp(app);
}
#if __ANDROID__
static IApp InitializeAndroidApp()
{
var fullApkPath = Path.Combine(TestContext.CurrentContext.TestDirectory, AppPaths.ApkPath);
var app = ConfigureApp.Android.ApkFile(fullApkPath).Debug().StartApp(UITest.Configuration.AppDataMode.DoNotClear);
if (bool.Parse((string)app.Invoke("IsPreAppCompat")))
{
IsFormsApplicationActivity = true;
}
return app;
}
public static bool IsFormsApplicationActivity { get; private set; }
#endif
#if __IOS__
static IApp InitializeiOSApp()
{
// Running on a device
var app = ConfigureApp.iOS.InstalledApp(AppPaths.BundleId).Debug()
//Uncomment to run from a specific iOS SIM, get the ID from XCode -> Devices
.StartApp(Xamarin.UITest.Configuration.AppDataMode.DoNotClear);
int _iosVersion;
if (int.TryParse(app.Invoke("iOSVersion").ToString(), out _iosVersion))
{
iOSVersion = _iosVersion;
}
// Running on the simulator
//var app = ConfigureApp.iOS
// .PreferIdeSettings()
// .AppBundle("../../../Xamarin.Forms.ControlGallery.iOS/bin/iPhoneSimulator/Debug/XamarinFormsControlGalleryiOS.app")
// .Debug()
// .StartApp();
return app;
}
public static int iOSVersion { get; private set; }
#endif
#if __MACOS__
static IApp InitializeMacOSApp()
{
// Running on a device
var configurator = new Xamarin.UITest.Desktop.CocoaAppConfigurator();
var app = configurator
//.AppBundle("/Users/rmarinho/Xamarin/Xamarin.Forms/Xamarin.Forms.ControlGallery.MacOS/bin/Debug/Xamarin.Forms.ControlGallery.MacOS.app")
.AppBundle(AppPaths.MacOSPath)
.BundleId(AppPaths.MacOSBundleId)
.StartApp();
return new Xamarin.Forms.Core.macOS.UITests.MacOSApp(app);
}
#endif
#if __WINDOWS__
static IApp InitializeUWPApp()
{
return WindowsTestBase.ConfigureApp();
}
#endif
public static void NavigateToIssue(Type type, IApp app)
{
var typeIssueAttribute = type.GetTypeInfo().GetCustomAttribute<IssueAttribute>();
string cellName = "";
if (typeIssueAttribute.IssueTracker.ToString() != "None" &&
typeIssueAttribute.IssueNumber != 1461 &&
typeIssueAttribute.IssueNumber != 342)
{
cellName = typeIssueAttribute.DisplayName;
}
else
{
cellName = typeIssueAttribute.Description;
}
int maxAttempts = 2;
int attempts = 0;
while (attempts < maxAttempts)
{
attempts += 1;
try
{
// Attempt the direct way of navigating to the test page
#if __ANDROID__
if (bool.Parse((string)app.Invoke("NavigateToTest", cellName)))
{
return;
}
#endif
#if __IOS__
if (bool.Parse(app.Invoke("navigateToTest:", cellName).ToString()))
{
return;
}
#endif
#if __WINDOWS__
// Windows doens't have an 'invoke' option right now for us to do the more direct navigation
// we're using for Android/iOS
// So we're just going to use the 'Reset' method to bounce the app to the opening screen
// and then fall back to the old manual navigation
WindowsTestBase.Reset();
#endif
}
catch (Exception ex)
{
var debugMessage = $"Could not directly invoke test; using UI navigation instead. {ex}";
System.Diagnostics.Debug.WriteLine(debugMessage);
Console.WriteLine(debugMessage);
}
try
{
// Fall back to the "manual" navigation method
app.Tap(q => q.Button("Go to Test Cases"));
app.WaitForElement(q => q.Raw("* marked:'TestCasesIssueList'"));
app.EnterText(q => q.Raw("* marked:'SearchBarGo'"), cellName);
app.WaitForElement(q => q.Raw("* marked:'SearchButton'"));
app.Tap(q => q.Raw("* marked:'SearchButton'"));
return;
}
catch (Exception ex)
{
var debugMessage = $"Both navigation methods failed. {ex}";
System.Diagnostics.Debug.WriteLine(debugMessage);
Console.WriteLine(debugMessage);
if (attempts < maxAttempts)
{
// Something has failed and we're stuck in a place where we can't navigate
// to the test. Usually this is because we're getting network/HTTP errors
// communicating with the server on the device. So we'll try restarting the app.
RunningApp = InitializeApp();
}
else
{
// But if it's still not working after [maxAttempts], we've got assume this is a legit
// problem that restarting won't fix
throw;
}
}
}
}
public static IApp Setup(Type pageType = null)
{
IApp runningApp = null;
try
{
// Issue 7207 - if current culture of the current thread is not set to the invariant culture
// then initializing the app causes a "NUnit.Framework.InconclusiveException" with the exception-
// message "App did not start for some reason. System.Argument.Exception: 1 is not supported code page.
// Parameter name: codepage."
if(System.Threading.Thread.CurrentThread.CurrentCulture != System.Globalization.CultureInfo.InvariantCulture)
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
runningApp = InitializeApp();
}
catch (Exception e)
{
Assert.Inconclusive($"App did not start for some reason: {e}");
}
if (pageType != null)
NavigateToIssue(pageType, runningApp);
return runningApp;
}
// Make sure the server on the device is still up and running;
// if not, restart the app
public static void EnsureConnection()
{
if (RunningApp != null)
{
try
{
RunningApp.TestServer.Get("version");
return;
}
catch
{
}
RunningApp = InitializeApp();
}
}
static int s_testsrun;
const int ConsecutiveTestLimit = 20;
// Until we get more of our memory leak issues worked out, restart the app
// after a specified number of tests so we don't get bogged down in GC
// (or booted by jetsam)
public static void EnsureMemory()
{
if (RunningApp != null)
{
s_testsrun += 1;
if (s_testsrun >= ConsecutiveTestLimit)
{
s_testsrun = 0;
RunningApp = InitializeApp();
}
}
}
// For tests which just don't play well with others, we can ensure
// that they run in their own instance of the application
public static void BeginIsolate()
{
if (RunningApp != null && s_testsrun > 0)
{
s_testsrun = 0;
RunningApp = InitializeApp();
}
}
public static void EndIsolate()
{
s_testsrun = ConsecutiveTestLimit;
}
public static IApp RunningApp { get; set; }
}
#endif
public abstract class TestPage : Page
{
#if UITEST
public IApp RunningApp => AppSetup.RunningApp;
protected virtual bool Isolate => false;
#endif
protected TestPage()
{
#if APP
Init();
#endif
}
#if UITEST
[SetUp]
public void Setup()
{
if (Isolate)
{
AppSetup.BeginIsolate();
}
else
{
AppSetup.EnsureMemory();
AppSetup.EnsureConnection();
}
AppSetup.NavigateToIssue(GetType(), RunningApp);
}
[TearDown]
public void TearDown()
{
if (Isolate)
{
AppSetup.EndIsolate();
}
}
#endif
protected abstract void Init();
}
public abstract class TestContentPage : ContentPage
{
#if UITEST
public IApp RunningApp => AppSetup.RunningApp;
protected virtual bool Isolate => false;
#endif
protected TestContentPage()
{
#if APP
Init();
#endif
}
#if UITEST
[SetUp]
public void Setup()
{
if (Isolate)
{
AppSetup.BeginIsolate();
}
else
{
AppSetup.EnsureMemory();
AppSetup.EnsureConnection();
}
AppSetup.NavigateToIssue(GetType(), RunningApp);
}
[TearDown]
public virtual void TearDown()
{
if (Isolate)
{
AppSetup.EndIsolate();
}
}
#endif
protected abstract void Init();
}
public abstract class TestCarouselPage : CarouselPage
{
#if UITEST
public IApp RunningApp => AppSetup.RunningApp;
protected virtual bool Isolate => false;
IDispatcher _dispatcher = new FallbackDispatcher();
public override IDispatcher Dispatcher { get => _dispatcher; }
#endif
protected TestCarouselPage()
{
#if APP
Init();
#endif
}
#if UITEST
[SetUp]
public void Setup()
{
if (Isolate)
{
AppSetup.BeginIsolate();
}
else
{
AppSetup.EnsureMemory();
AppSetup.EnsureConnection();
}
AppSetup.NavigateToIssue(GetType(), RunningApp);
}
[TearDown]
public void TearDown()
{
if (Isolate)
{
AppSetup.EndIsolate();
}
}
#endif
protected abstract void Init();
}
#if UITEST
[Category(Core.UITests.UITestCategories.MasterDetailPage)]
#endif
public abstract class TestMasterDetailPage : MasterDetailPage
{
#if UITEST
public IApp RunningApp => AppSetup.RunningApp;
protected virtual bool Isolate => false;
#endif
protected TestMasterDetailPage()
{
#if APP
Init();
#endif
}
#if UITEST
[SetUp]
public void Setup()
{
if (Isolate)
{
AppSetup.BeginIsolate();
}
else
{
AppSetup.EnsureMemory();
AppSetup.EnsureConnection();
}
AppSetup.NavigateToIssue(GetType(), RunningApp);
}
[TearDown]
public virtual void TearDown()
{
if (Isolate)
{
AppSetup.EndIsolate();
}
}
#endif
protected abstract void Init();
}
public abstract class TestNavigationPage : NavigationPage
{
#if UITEST
public IApp RunningApp => AppSetup.RunningApp;
protected virtual bool Isolate => false;
#endif
protected TestNavigationPage()
{
#if APP
Init();
#endif
}
#if UITEST
[SetUp]
public void Setup()
{
if (Isolate)
{
AppSetup.BeginIsolate();
}
else
{
AppSetup.EnsureMemory();
AppSetup.EnsureConnection();
}
AppSetup.NavigateToIssue(GetType(), RunningApp);
}
[TearDown]
public void TearDown()
{
if (Isolate)
{
AppSetup.EndIsolate();
}
}
#endif
protected abstract void Init();
}
#if UITEST
[Category(UITestCategories.TabbedPage)]
#endif
public abstract class TestTabbedPage : TabbedPage
{
#if UITEST
public IApp RunningApp => AppSetup.RunningApp;
protected virtual bool Isolate => false;
IDispatcher _dispatcher = new FallbackDispatcher();
public override IDispatcher Dispatcher { get => _dispatcher; }
#endif
protected TestTabbedPage()
{
#if APP
Init();
#endif
}
#if UITEST
[SetUp]
public void Setup()
{
if (Isolate)
{
AppSetup.BeginIsolate();
}
else
{
AppSetup.EnsureMemory();
AppSetup.EnsureConnection();
}
AppSetup.NavigateToIssue(GetType(), RunningApp);
}
[TearDown]
public virtual void TearDown()
{
if (Isolate)
{
AppSetup.EndIsolate();
}
}
#endif
protected abstract void Init();
}
#if UITEST
[NUnit.Framework.Category(UITestCategories.Shell)]
#endif
public abstract class TestShell : Shell
{
protected const string FlyoutIconAutomationId = "OK";
#if UITEST
public IApp RunningApp => AppSetup.RunningApp;
protected virtual bool Isolate => true;
#endif
protected TestShell() : base()
{
#if APP
Init();
#endif
}
public ContentPage AddTopTab(string title)
{
var page = new ContentPage();
AddTopTab(page, title);
return page;
}
public void AddTopTab(ContentPage page, string title = null)
{
if(Items.Count == 0)
{
var item = AddContentPage(page);
item.Items[0].Items[0].Title = title ?? page.Title;
return;
}
Items[0].Items[0].Items.Add(new ShellContent()
{
Title = title ?? page.Title,
Content = page
});
}
public ContentPage AddBottomTab(string title)
{
ContentPage page = new ContentPage();
Items[0].Items.Add(new ShellSection()
{
Items =
{
new ShellContent()
{
Content = page,
Title = title
}
}
});
return page;
}
public TabBar CreateTabBar(string shellItemTitle)
{
shellItemTitle = shellItemTitle ?? $"Item: {Items.Count}";
ContentPage page = new ContentPage();
TabBar item = new TabBar()
{
Title = shellItemTitle,
Items =
{
new ShellSection()
{
Items =
{
new ShellContent()
{
Content = page
}
}
}
}
};
Items.Add(item);
return item;
}
public ContentPage CreateContentPage(string shellItemTitle = null)
=> CreateContentPage<ShellItem, ShellSection>(shellItemTitle);
public ContentPage CreateContentPage<TShellItem, TShellSection>(string shellItemTitle = null)
where TShellItem : ShellItem
where TShellSection : ShellSection
{
shellItemTitle = shellItemTitle ?? $"Item: {Items.Count}";
ContentPage page = new ContentPage();
TShellItem item = Activator.CreateInstance<TShellItem>();
item.Title = shellItemTitle;
TShellSection shellSection = Activator.CreateInstance<TShellSection>();
shellSection.Items.Add(new ShellContent()
{
Content = page
});
item.Items.Add(shellSection);
Items.Add(item);
return page;
}
public ShellItem AddContentPage(ContentPage contentPage = null)
=> AddContentPage<ShellItem, ShellSection>(contentPage);
public TShellItem AddContentPage<TShellItem, TShellSection>(ContentPage contentPage = null)
where TShellItem : ShellItem
where TShellSection : ShellSection
{
contentPage = contentPage ?? new ContentPage();
TShellItem item = Activator.CreateInstance<TShellItem>();
item.Title = contentPage.Title;
TShellSection shellSection = Activator.CreateInstance<TShellSection>();
Items.Add(item);
item.Items.Add(shellSection);
shellSection.Items.Add(new ShellContent()
{
Content = contentPage
});
return item;
}
#if UITEST
[SetUp]
public void Setup()
{
if (Isolate)
{
AppSetup.BeginIsolate();
}
else
{
AppSetup.EnsureMemory();
AppSetup.EnsureConnection();
}
AppSetup.NavigateToIssue(GetType(), RunningApp);
}
[TearDown]
public virtual void TearDown()
{
if (Isolate)
{
AppSetup.EndIsolate();
}
}
public void ShowFlyout(string flyoutIcon = FlyoutIconAutomationId, bool usingSwipe = false, bool testForFlyoutIcon = true, string timeoutMessage = null)
{
if(testForFlyoutIcon)
RunningApp.WaitForElement(flyoutIcon, timeoutMessage);
if (usingSwipe)
{
var rect = RunningApp.ScreenBounds();
RunningApp.DragCoordinates(10, rect.CenterY, rect.CenterX, rect.CenterY);
}
else
{
RunningApp.Tap(flyoutIcon);
}
}
public void TapInFlyout(string text, string flyoutIcon = FlyoutIconAutomationId, bool usingSwipe = false, string timeoutMessage = null)
{
timeoutMessage = timeoutMessage ?? text;
ShowFlyout(flyoutIcon, usingSwipe, timeoutMessage: timeoutMessage);
RunningApp.WaitForElement(text, timeoutMessage);
RunningApp.Tap(text);
}
#endif
protected abstract void Init();
}
}
#if UITEST
namespace Xamarin.Forms.Controls.Issues
{
using System;
using NUnit.Framework;
// Run setup once for all tests in the Xamarin.Forms.Controls.Issues namespace
// (instead of once for each test)
[SetUpFixture]
public class IssuesSetup
{
[OneTimeSetUp]
public void RunBeforeAnyTests()
{
AppSetup.RunningApp = AppSetup.Setup(null);
}
}
}
#endif