Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup WinUI to run window scoped tests in new window #7308

Merged
merged 4 commits into from May 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -15,6 +15,7 @@
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Handlers;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Maui.DeviceTests.Stubs;

namespace Microsoft.Maui.DeviceTests
{
Expand Down
Expand Up @@ -7,6 +7,7 @@
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Handlers;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform;
Expand Down
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Hosting;
using Xunit;
Expand Down
Expand Up @@ -7,6 +7,7 @@
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Handlers;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Platform;
using Xunit;

Expand Down
Expand Up @@ -5,6 +5,7 @@
using System.Text;
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Hosting;
using Xunit;
Expand Down
Expand Up @@ -13,6 +13,7 @@
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.DeviceTests.Stubs;

namespace Microsoft.Maui.DeviceTests
{
Expand Down
Expand Up @@ -11,6 +11,7 @@
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.DeviceTests.Stubs;

#if ANDROID || IOS
using ShellHandler = Microsoft.Maui.Controls.Handlers.Compatibility.ShellRenderer;
Expand Down
15 changes: 2 additions & 13 deletions src/Controls/tests/DeviceTests/HandlerTestBase.Android.cs
Expand Up @@ -37,7 +37,7 @@ public AView GetSemanticPlatformElement(IViewHandler viewHandler)
}

static Drawable _decorDrawable;
Task RunWindowTest<THandler>(IWindow window, Func<THandler, Task> action)
Task SetupWindowForTests<THandler>(IWindow window, Func<Task> runTests)
where THandler : class, IElementHandler
{
return InvokeOnMainThreadAsync(async () =>
Expand All @@ -60,18 +60,7 @@ Task RunWindowTest<THandler>(IWindow window, Func<THandler, Task> action)
.Commit();

await viewFragment.FinishedLoading;

if (window.Content is Shell shell)
await OnLoadedAsync(shell.CurrentPage);

if (typeof(THandler).IsAssignableFrom(window.Handler.GetType()))
await action((THandler)window.Handler);
else if (typeof(THandler).IsAssignableFrom(window.Content.Handler.GetType()))
await action((THandler)window.Content.Handler);
else if (window.Content is ContentPage cp && typeof(THandler).IsAssignableFrom(cp.Content.Handler.GetType()))
await action((THandler)cp.Content.Handler);
else
throw new Exception($"I can't work with {typeof(THandler)}");
await runTests.Invoke();
}
finally
{
Expand Down
72 changes: 16 additions & 56 deletions src/Controls/tests/DeviceTests/HandlerTestBase.Windows.cs
@@ -1,23 +1,19 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation.Peers;
using NativeAutomationProperties = Microsoft.UI.Xaml.Automation.AutomationProperties;
using WPanel = Microsoft.UI.Xaml.Controls.Panel;
using WNavigationViewItem = Microsoft.UI.Xaml.Controls.NavigationViewItem;
using WFrameworkElement = Microsoft.UI.Xaml.FrameworkElement;
using WWindow = Microsoft.UI.Xaml.Window;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Handlers;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Handlers;
using Microsoft.Maui.Platform;
using System.Threading.Tasks;
using System;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using WPoint = Windows.Foundation.Point;
using WAppBarButton = Microsoft.UI.Xaml.Controls.AppBarButton;
using Xunit;
using Microsoft.Maui.DeviceTests.Stubs;

namespace Microsoft.Maui.DeviceTests
{
Expand All @@ -27,65 +23,29 @@ public partial class HandlerTestBase
((AccessibilityView)((DependencyObject)viewHandler.PlatformView).GetValue(NativeAutomationProperties.AccessibilityViewProperty))
== AccessibilityView.Content;

Task RunWindowTest<THandler>(IWindow window, Func<THandler, Task> action)

Task SetupWindowForTests<THandler>(IWindow window, Func<Task> runTests)
where THandler : class, IElementHandler
{
return InvokeOnMainThreadAsync(async () =>
{
var testingRootPanel = (WPanel)MauiProgram.CurrentWindow.Content;
IElementHandler newWindowHandler = null;
NavigationRootManager navigationRootManager = null;
var applicationContext = MauiContext.MakeApplicationScope(UI.Xaml.Application.Current);

var appStub = new MauiAppNewWindowStub(window);
UI.Xaml.Application.Current.SetApplicationHandler(appStub, applicationContext);
WWindow newWindow = null;
try
{
var scopedContext = new MauiContext(MauiContext.Services);
scopedContext.AddWeakSpecific(MauiProgram.CurrentWindow);
var mauiContext = scopedContext.MakeScoped(true);
navigationRootManager = mauiContext.GetNavigationRootManager();

MauiContext
.Services
.GetRequiredService<WWindow>()
.SetWindowHandler(window, mauiContext);

newWindowHandler = window.Handler;
var content = window.Content.Handler.ToPlatform();
await content.OnLoadedAsync();
await Task.Delay(10);

if (typeof(THandler).IsAssignableFrom(newWindowHandler.GetType()))
await action((THandler)newWindowHandler);
else if (typeof(THandler).IsAssignableFrom(window.Content.Handler.GetType()))
await action((THandler)window.Content.Handler);
else if (window.Content is ContentPage cp && typeof(THandler).IsAssignableFrom(cp.Content.Handler.GetType()))
await action((THandler)cp.Content.Handler);
else
throw new Exception($"I can't work with {typeof(THandler)}");

ApplicationExtensions.CreatePlatformWindow(UI.Xaml.Application.Current, appStub, new Handlers.OpenWindowRequest());
newWindow = window.Handler.PlatformView as WWindow;
await runTests.Invoke();
}
finally
{
if (navigationRootManager != null)
navigationRootManager.Disconnect();

if (newWindowHandler != null)
newWindowHandler.DisconnectHandler();

// Set the root window panel back to the testing panel
if (testingRootPanel != null && MauiProgram.CurrentWindow.Content != testingRootPanel)
{
MauiProgram.CurrentWindow.Content = testingRootPanel;
await testingRootPanel.OnLoadedAsync();
await Task.Delay(10);
}

// reset the appbar title to our test runner
MauiProgram
.CurrentWindow
.GetWindow()
.Handler
.MauiContext
.GetNavigationRootManager()
.UpdateAppTitleBar(true);
window.Handler.DisconnectHandler();
await Task.Delay(10);
newWindow?.Close();
appStub.Handler.DisconnectHandler();
}
});
}
Expand Down Expand Up @@ -176,7 +136,7 @@ protected MauiToolbar GetPlatformToolbar(IElementHandler handler)

return true;
}

protected object GetTitleView(IElementHandler handler)
{
var toolbar = GetPlatformToolbar(handler);
Expand Down
41 changes: 37 additions & 4 deletions src/Controls/tests/DeviceTests/HandlerTestBase.cs
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui.Controls;
Expand Down Expand Up @@ -68,6 +69,7 @@ public void EnsureHandlerCreated(Action<MauiAppBuilder> additionalCreationAction
handlers.AddHandler(typeof(VerticalStackLayout), typeof(LayoutHandler));
handlers.AddHandler(typeof(Controls.Window), typeof(WindowHandlerStub));
handlers.AddHandler(typeof(Controls.ContentPage), typeof(PageHandler));
handlers.AddHandler(typeof(MauiAppNewWindowStub), typeof(ApplicationHandler));
});

appBuilder.Services.AddSingleton<IDispatcherProvider>(svc => TestDispatcher.Provider);
Expand All @@ -82,7 +84,7 @@ public void EnsureHandlerCreated(Action<MauiAppBuilder> additionalCreationAction

public void Dispose()
{
((IDisposable)_mauiApp).Dispose();
((IDisposable)_mauiApp)?.Dispose();

_mauiApp = null;
_mauiContext = null;
Expand Down Expand Up @@ -141,8 +143,8 @@ protected THandler CreateHandler<THandler>(IElement element, IMauiContext mauiCo
#else
// Windows cannot measure without the view being loaded
// iOS needs more love when I get an IDE again
var w = view.Width;
var h = view.Height;
var w = view.Width.Equals(double.NaN) ? -1 : view.Width;
var h = view.Height.Equals(double.NaN) ? -1 : view.Height;
#endif

view.Arrange(new Rect(0, 0, w, h));
Expand Down Expand Up @@ -174,6 +176,7 @@ protected Task CreateHandlerAndAddToWindow<THandler>(IElement view, Action<THand
});
}

static SemaphoreSlim _takeOverMainContentSempahore = new SemaphoreSlim(1);
protected Task CreateHandlerAndAddToWindow<THandler>(IElement view, Func<THandler, Task> action)
where THandler : class, IElementHandler
{
Expand All @@ -194,7 +197,37 @@ protected Task CreateHandlerAndAddToWindow<THandler>(IElement view, Func<THandle
window = new Controls.Window(new ContentPage() { Content = (View)view });
}

await RunWindowTest<THandler>(window, (handler) => action(handler as THandler));
try
{
await _takeOverMainContentSempahore.WaitAsync();

await SetupWindowForTests<THandler>(window, async () =>
{
IView content = window.Content;

if (content is IPageContainer<Page> pc)
content = pc.CurrentPage;

await OnLoadedAsync(content as VisualElement);
#if WINDOWS

await Task.Delay(10);
#endif

if (typeof(THandler).IsAssignableFrom(window.Handler.GetType()))
await action((THandler)window.Handler);
else if (typeof(THandler).IsAssignableFrom(window.Content.Handler.GetType()))
await action((THandler)window.Content.Handler);
else if (window.Content is ContentPage cp && typeof(THandler).IsAssignableFrom(cp.Content.Handler.GetType()))
await action((THandler)cp.Content.Handler);
else
throw new Exception($"I can't work with {typeof(THandler)}");
});
}
finally
{
_takeOverMainContentSempahore.Release();
}
});
}

Expand Down
21 changes: 4 additions & 17 deletions src/Controls/tests/DeviceTests/HandlerTestBase.iOS.cs
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Maui.Controls.Handlers.Compatibility;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Controls.Platform.Compatibility;
using Microsoft.Maui.DeviceTests.Stubs;
using Microsoft.Maui.Platform;
using UIKit;

Expand All @@ -23,29 +24,15 @@ protected bool GetExcludedWithChildren(IViewHandler viewHandler)
return platformView.AccessibilityElementsHidden;
}

Task RunWindowTest<THandler>(IWindow window, Func<THandler, Task> action)
Task SetupWindowForTests<THandler>(IWindow window, Func<Task> runTests)
where THandler : class, IElementHandler
{
return InvokeOnMainThreadAsync(async () =>
{
try
{
_ = window.ToHandler(MauiContext);
IView content = window.Content;

if (content is IPageContainer<Page> pc)
content = pc.CurrentPage;

await OnLoadedAsync(content as VisualElement);

if (typeof(THandler).IsAssignableFrom(window.Handler.GetType()))
await action((THandler)window.Handler);
else if (typeof(THandler).IsAssignableFrom(window.Content.Handler.GetType()))
await action((THandler)window.Content.Handler);
else if (window.Content is ContentPage cp && typeof(THandler).IsAssignableFrom(cp.Content.Handler.GetType()))
await action((THandler)cp.Content.Handler);
else
throw new Exception($"I can't work with {typeof(THandler)}");
await runTests.Invoke();
}
finally
{
Expand Down Expand Up @@ -91,7 +78,7 @@ protected bool IsBackButtonVisible(IElementHandler handler)
protected object GetTitleView(IElementHandler handler)
{
var activeVC = GetVisibleViewController(handler);
if ( activeVC.NavigationItem.TitleView is
if (activeVC.NavigationItem.TitleView is
ShellPageRendererTracker.TitleViewContainer tvc)
{
return tvc.View.Handler.PlatformView;
Expand Down
41 changes: 41 additions & 0 deletions src/Controls/tests/DeviceTests/Stubs/MauiAppNewWindowStub.cs
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;

namespace Microsoft.Maui.DeviceTests.Stubs
{
class MauiAppNewWindowStub : IApplication
{
readonly IWindow _window;

public MauiAppNewWindowStub(IWindow window)
{
_window = window;
}

public IReadOnlyList<IWindow> Windows => new List<IWindow>() { _window };

public IElementHandler Handler { get; set; }

public IElement Parent => null;

public void CloseWindow(IWindow window)
{
Handler?.Invoke(nameof(IApplication.CloseWindow), window);
}

public IWindow CreateWindow(IActivationState activationState)
{
return _window;
}

public void OpenWindow(IWindow window)
{
throw new NotImplementedException();
}

public void ThemeChanged()
{
throw new NotImplementedException();
}
}
}
Expand Up @@ -5,7 +5,7 @@
using static Microsoft.Maui.DeviceTests.HandlerTestBase;
using AActivity = Android.App.Activity;

namespace Microsoft.Maui.DeviceTests
namespace Microsoft.Maui.DeviceTests.Stubs
{
public class WindowHandlerStub : ElementHandler<IWindow, AActivity>, IWindowHandler
{
Expand Down