Skip to content

🧪 Add UI Tests for Gridsplitter #4090

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

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,37 @@

<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="SystemControlSplitterPointerOver" Color="{ThemeResource SystemBaseLowColor}" />
<SolidColorBrush x:Key="SystemControlSplitterPressed" Color="{ThemeResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="SystemControlSplitterPointerOver"
Color="{ThemeResource SystemBaseLowColor}" />
<SolidColorBrush x:Key="SystemControlSplitterPressed"
Color="{ThemeResource SystemBaseHighColor}" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="SystemControlSplitterPointerOver" Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="SystemControlSplitterPressed" Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="SystemControlSplitterPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="SystemControlSplitterPressed"
Color="{ThemeResource SystemColorHighlightColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

<Style TargetType="local:GridSplitter">
<Setter Property="IsTabStop" Value="True"></Setter>
<Setter Property="UseSystemFocusVisuals" Value="True"></Setter>
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
<Setter Property="VerticalAlignment" Value="Stretch"></Setter>
<Setter Property="IsFocusEngagementEnabled" Value="True"></Setter>
<Setter Property="MinWidth" Value="16"></Setter>
<Setter Property="MinHeight" Value="16"></Setter>
<Setter Property="Background" Value="{ThemeResource SystemControlHighlightChromeHighBrush}"></Setter>
<Setter Property="IsTabStop" Value="True" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="IsFocusEngagementEnabled" Value="True" />
<Setter Property="MinWidth" Value="16" />
<Setter Property="MinHeight" Value="16" />
<Setter Property="Background" Value="{ThemeResource SystemControlHighlightChromeHighBrush}" />
<Setter Property="GripperForeground" Value="{ThemeResource SystemControlForegroundAltHighBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:GridSplitter">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<Grid x:Name="RootGrid"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Content="{TemplateBinding Element}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="GridSplitterStates">
<VisualState x:Name="Normal" />
Expand All @@ -42,7 +50,6 @@
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content="{TemplateBinding Element}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
</Grid>
</ControlTemplate>
</Setter.Value>
Expand Down
54 changes: 53 additions & 1 deletion UITests/UITests.App/App.AppService.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Toolkit.Mvvm.Messaging;
using UITests.App.Pages;
Expand Down Expand Up @@ -49,6 +50,8 @@ private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppS
return;
}

Log.Comment("Received Command: {0}", cmd);

switch (cmd)
{
case "OpenPage":
Expand All @@ -65,6 +68,44 @@ private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppS

await args.Request.SendResponseAsync(pageResponse ? OkResult : BadResult);

break;
case "Custom":
if (!TryGetValueAndLog(message, "Id", out var id) || !_customCommands.ContainsKey(id))
{
await args.Request.SendResponseAsync(BadResult);
break;
}

Log.Comment("Received request for custom command: {0}", id);

try
{
ValueSet response = await _customCommands[id].Invoke(message);

if (response != null)
{
response.Add("Status", "OK");
}
else
{
await args.Request.SendResponseAsync(BadResult);
break;
}

await args.Request.SendResponseAsync(response);
}
catch (Exception e)
{
ValueSet errmsg = new() { { "Status", "BAD" }, { "Exception", e.Message }, { "StackTrace", e.StackTrace } };
if (e.InnerException != null)
{
errmsg.Add("InnerException", e.InnerException.Message);
errmsg.Add("InnerExceptionStackTrace", e.InnerException.StackTrace);
}

await args.Request.SendResponseAsync(errmsg);
}

break;
default:
break;
Expand All @@ -77,11 +118,15 @@ private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppS

private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
Log.Error("Background Task Instance Canceled. Reason: {0}", reason.ToString());

_appServiceDeferral.Complete();
}

private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
Log.Error("AppServiceConnection Service Closed. AppServicesClosedStatus: {0}", args.Status.ToString());

_appServiceDeferral.Complete();
}

Expand Down Expand Up @@ -118,5 +163,12 @@ private static bool TryGetValueAndLog(ValueSet message, string key, out string v

return true;
}

private Dictionary<string, Func<ValueSet, Task<ValueSet>>> _customCommands = new();

internal void RegisterCustomCommand(string id, Func<ValueSet, Task<ValueSet>> customCommandFunction)
{
_customCommands.Add(id, customCommandFunction);
}
}
}
}
2 changes: 2 additions & 0 deletions UITests/UITests.App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UITests.App.Commands;
using UITests.App.Pages;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
Expand Down
105 changes: 105 additions & 0 deletions UITests/UITests.App/Commands/VisualTreeHelperCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.Toolkit;
using Microsoft.Toolkit.Uwp;
using Microsoft.Toolkit.Uwp.UI;
using UITests.App.Pages;
using Windows.Foundation.Collections;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace UITests.App.Commands
{
public static class VisualTreeHelperCommands
{
private static DispatcherQueue Queue { get; set; }

private static JsonSerializerOptions SerializerOptions { get; } = new JsonSerializerOptions(JsonSerializerDefaults.General)
{
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
};

public static void Initialize(DispatcherQueue uiThread)
{
Queue = uiThread;

(App.Current as App).RegisterCustomCommand("VisualTreeHelper.FindElementProperty", FindElementProperty);
}

public static async Task<ValueSet> FindElementProperty(ValueSet arguments)
{
ValueSet results = new ValueSet();

if (Queue == null)
{
Log.Error("VisualTreeHelper - Missing UI DispatcherQueue");
return null;
}

await Queue.EnqueueAsync(() =>
{
// Dispatch?
var content = Window.Current.Content as Frame;

if (content == null)
{
Log.Error("VisualTreeHelper.FindElementProperty - Window has no content.");
return;
}

if (arguments.TryGetValue("ElementName", out object value) && value is string name &&
arguments.TryGetValue("Property", out object value2) && value2 is string propertyName)
{
Log.Comment("VisualTreeHelper.FindElementProperty('{0}', '{1}')", name, propertyName);

// 1. Find Element in Visual Tree
var element = content.FindDescendant(name);

try
{
Log.Comment("VisualTreeHelper.FindElementProperty - Found Element? {0}", element != null);

var typeinfo = element.GetType().GetTypeInfo();

Log.Comment("Element Type: {0}", typeinfo.FullName);

var prop = element.GetType().GetTypeInfo().GetProperty(propertyName);

if (prop == null)
{
Log.Error("VisualTreeHelper.FindElementProperty - Couldn't find Property named {0} on type {1}", propertyName, typeinfo.FullName);
return;
}

// 2. Get the property using reflection
var propValue = prop.GetValue(element);

// 3. Serialize and return the result
results.Add("Result", JsonSerializer.Serialize(propValue, SerializerOptions));
}
catch (Exception e)
{
Log.Error("Error {0}", e.Message);
Log.Error("StackTrace:\n{0}", e.StackTrace);
}
}
});

if (results.Count > 0)
{
return results;
}

return null; // Failure
}
}
}
4 changes: 4 additions & 0 deletions UITests/UITests.App/MainTestHost.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading.Tasks;
using Microsoft.Toolkit.Mvvm.Messaging;
using Microsoft.Toolkit.Uwp;
using UITests.App.Commands;
using UITests.App.Pages;
using Windows.System;
using Windows.UI.Xaml;
Expand All @@ -33,6 +34,9 @@ public MainTestHost()
WeakReferenceMessenger.Default.Register<RequestPageMessage>(this);

_queue = DispatcherQueue.GetForCurrentThread();

// Initialize Custom Commands for AppService
VisualTreeHelperCommands.Initialize(_queue);
}

public void Receive(RequestPageMessage message)
Expand Down
5 changes: 4 additions & 1 deletion UITests/UITests.App/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
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">
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp rescap">

<Identity
Name="3568ebdf-5b6b-4ddd-bb17-462d614ba50f"
Expand Down Expand Up @@ -48,5 +49,7 @@

<Capabilities>
<Capability Name="internetClient" />
<!-- Our AppService Background Connection will Timeout after a period of time otherwise. -->
<rescap:Capability Name="extendedBackgroundTaskTime"/>
</Capabilities>
</Package>
2 changes: 2 additions & 0 deletions UITests/UITests.App/Properties/Default.rd.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<Namespace Name="Windows.UI.Xaml.Controls" Dynamic="Required All" />
<Namespace Name="Microsoft.UI.Xaml.Controls" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>
8 changes: 6 additions & 2 deletions UITests/UITests.App/TestInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Diagnostics;
using Windows.UI.Xaml;

namespace UITests.App.Pages
Expand Down Expand Up @@ -37,9 +37,13 @@ private static void LogMessage(string level, string format, object[] args)
format = format.Replace("{", "{{").Replace("}", "}}");
}

var message = string.Format(format, args);

Debug.WriteLine(message);

// Send back to Test Harness via AppService
// TODO: Make this a cleaner connection/pattern
((App)Application.Current).SendLogMessage(level, string.Format(format, args));
_ = ((App)Application.Current).SendLogMessage(level, message);
}
}
}
4 changes: 4 additions & 0 deletions UITests/UITests.App/UITests.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
<Compile Include="App.AppService.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Commands\VisualTreeHelperCommands.cs" />
<Compile Include="HomePage.xaml.cs">
<DependentUpon>HomePage.xaml</DependentUpon>
</Compile>
Expand Down Expand Up @@ -178,6 +179,9 @@
<PackageReference Include="MUXAppTestHelpers">
<Version>0.0.4</Version>
</PackageReference>
<PackageReference Include="System.Text.Json">
<Version>5.0.2</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="UITests.App.pfx" />
Expand Down
1 change: 1 addition & 0 deletions UITests/UITests.Tests.MSTest/UITests.Tests.MSTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.5.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Microsoft.Windows.Apps.Test" Version="1.0.181205002" />
<PackageReference Include="System.Text.Json" Version="5.0.2" />
</ItemGroup>

<Import Project="..\UITests.Tests.Shared\UITests.Tests.Shared.projitems" Label="Shared" />
Expand Down
Loading