[FancyZones]UI testing that works in CI (#29453)

* added test project

* run fz test

* rename proj

* editor test project

* check if FZ is running

* rename

* added assert messages

* spelling

* dev docs

* spelling

* update to latest stable

* exclude ui tests deps

* update packages list in notice.md

* added sample tests

* added file for tests run

* removed unrecognized

* removed run

* fix test configuration

* rename job

* change dependance

* run test template

* removed condition

* tabulation fix

* removed arg

* removed dependance

* removed log

* removed parameters

* test

* test

* added parameters

* pool

* pool

* vs test

* dependance

* download artifact

* publish artifact

* artifact publish conditions

* artifact name, default download path

* set folders

* prepare dotnet and vstest platform

* copy all

* target dotnet8

* test build agents

* set vs test version

* spellcheck

* set test platform version

* package feed selector

* hardcoded vstest location

* are other tests running?

* location

* vstest.console

* upd command

* script path

* search vstest.console

* vs path

* tools dir

* check files

* try full path

* try vstest task

* try full path in vstest task

* change path, remove unnecessary

* test with full vsconsole path

* winappdriver task

* changed args and condition

* default address

* added start operation type

* task name

* remove resolution

* Update run-ui-tests-ci.yml

* Update run-ui-tests-ci.yml

* Update run-ui-tests-ci.yml

* Update run-ui-tests-ci.yml

* AgentResolution should be a string

* Update run-ui-tests-ci.yml

testing against what WinUI gallery has for agent

* Update run-ui-tests-ci.yml

* Update run-ui-tests-ci.yml

* added WinAppDriver.exe

* spellcheck

* remove task

* checkout

* path

* src dir variable

* added init to the second project

* set longer timeout

* try waiting

* rerun

* log session info

* exclude WinAppDriver files from spell-check

* split io class: editor params

* remove unnecessary

* move data to the common project

* io test helper

* write retry

* Moved constants

* file utils

* prepare editor files before launch

* remove unused file

* spellcheck

* create directory

* fixed cleaning up

* remove WinAppDriver from deps

* start WinAppDriver from the default installation path

* installation script

* Revert "spellcheck"

This reverts commit 4bdc395730.

* Revert "exclude WinAppDriver files from spell-check"

This reverts commit 21ee6db3f5.

* install

* installation argument

* spellcheck

* change winappdriver path in fz tests

* delete iohelper

* update docs

* deleted obsolete winappdriver tests

* net version

* try without vstest location

* spellcheck

* Revert "try without vstest location"

This reverts commit 7cd39f3ae6.

* moved json tag constants to the common project
This commit is contained in:
Seraphima Zykova
2024-03-22 13:10:10 +01:00
committed by GitHub
parent c39e306784
commit f6e7635a4e
57 changed files with 1692 additions and 4172 deletions

View File

@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace FancyZonesEditorCommon.Data
{
public class AppliedLayouts : EditorData<AppliedLayouts.AppliedLayoutsListWrapper>
{
public string File
{
get
{
return GetDataFolder() + "\\Microsoft\\PowerToys\\FancyZones\\applied-layouts.json";
}
}
public struct AppliedLayoutWrapper
{
public struct DeviceIdWrapper
{
public string Monitor { get; set; }
public string MonitorInstance { get; set; }
public int MonitorNumber { get; set; }
public string SerialNumber { get; set; }
public string VirtualDesktop { get; set; }
}
public struct LayoutWrapper
{
public string Uuid { get; set; }
public string Type { get; set; }
public bool ShowSpacing { get; set; }
public int Spacing { get; set; }
public int ZoneCount { get; set; }
public int SensitivityRadius { get; set; }
}
public DeviceIdWrapper Device { get; set; }
public LayoutWrapper AppliedLayout { get; set; }
}
public struct AppliedLayoutsListWrapper
{
public List<AppliedLayoutWrapper> AppliedLayouts { get; set; }
}
}
}

View File

@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace FancyZonesEditorCommon.Data
{
public static class Constants
{
public enum TemplateLayout
{
Empty,
Focus,
Rows,
Columns,
Grid,
PriorityGrid,
}
public static readonly ReadOnlyDictionary<TemplateLayout, string> TemplateLayoutJsonTags = new ReadOnlyDictionary<TemplateLayout, string>(
new Dictionary<TemplateLayout, string>()
{
{ TemplateLayout.Empty, "blank" },
{ TemplateLayout.Focus, "focus" },
{ TemplateLayout.Rows, "rows" },
{ TemplateLayout.Columns, "columns" },
{ TemplateLayout.Grid, "grid" },
{ TemplateLayout.PriorityGrid, "priority-grid" },
});
public const string CustomLayoutJsonTag = "custom";
}
}

View File

@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Text.Json;
using static FancyZonesEditorCommon.Data.CustomLayouts;
namespace FancyZonesEditorCommon.Data
{
public class CustomLayouts : EditorData<CustomLayoutListWrapper>
{
public string File
{
get
{
return GetDataFolder() + "\\Microsoft\\PowerToys\\FancyZones\\custom-layouts.json";
}
}
public sealed class CanvasInfoWrapper
{
public struct CanvasZoneWrapper
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
public int RefWidth { get; set; }
public int RefHeight { get; set; }
public List<CanvasZoneWrapper> Zones { get; set; }
public int SensitivityRadius { get; set; } = LayoutDefaultSettings.DefaultSensitivityRadius;
}
public sealed class GridInfoWrapper
{
public int Rows { get; set; }
public int Columns { get; set; }
public List<int> RowsPercentage { get; set; }
public List<int> ColumnsPercentage { get; set; }
public int[][] CellChildMap { get; set; }
public bool ShowSpacing { get; set; } = LayoutDefaultSettings.DefaultShowSpacing;
public int Spacing { get; set; } = LayoutDefaultSettings.DefaultSpacing;
public int SensitivityRadius { get; set; } = LayoutDefaultSettings.DefaultSensitivityRadius;
}
public struct CustomLayoutWrapper
{
public string Uuid { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public JsonElement Info { get; set; } // CanvasInfoWrapper or GridInfoWrapper
}
public struct CustomLayoutListWrapper
{
public List<CustomLayoutWrapper> CustomLayouts { get; set; }
}
public JsonElement ToJsonElement(CanvasInfoWrapper info)
{
string json = JsonSerializer.Serialize(info, this.JsonOptions);
return JsonSerializer.Deserialize<JsonElement>(json);
}
public JsonElement ToJsonElement(GridInfoWrapper info)
{
string json = JsonSerializer.Serialize(info, this.JsonOptions);
return JsonSerializer.Deserialize<JsonElement>(json);
}
public CanvasInfoWrapper CanvasFromJsonElement(string json)
{
return JsonSerializer.Deserialize<CanvasInfoWrapper>(json, this.JsonOptions);
}
public GridInfoWrapper GridFromJsonElement(string json)
{
return JsonSerializer.Deserialize<GridInfoWrapper>(json, this.JsonOptions);
}
}
}

View File

@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using static FancyZonesEditorCommon.Data.DefaultLayouts;
namespace FancyZonesEditorCommon.Data
{
public class DefaultLayouts : EditorData<DefaultLayoutsListWrapper>
{
public string File
{
get
{
return GetDataFolder() + "\\Microsoft\\PowerToys\\FancyZones\\default-layouts.json";
}
}
public struct DefaultLayoutWrapper
{
public struct LayoutWrapper
{
public string Uuid { get; set; }
public string Type { get; set; }
public bool ShowSpacing { get; set; }
public int Spacing { get; set; }
public int ZoneCount { get; set; }
public int SensitivityRadius { get; set; }
}
public string MonitorConfiguration { get; set; }
public LayoutWrapper Layout { get; set; }
}
public struct DefaultLayoutsListWrapper
{
public List<DefaultLayoutWrapper> DefaultLayouts { get; set; }
}
}
}

View File

@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text.Json;
using FancyZonesEditorCommon.Utils;
namespace FancyZonesEditorCommon.Data
{
public class EditorData<T>
{
public string GetDataFolder()
{
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
}
protected JsonSerializerOptions JsonOptions
{
get
{
return new JsonSerializerOptions
{
PropertyNamingPolicy = new DashCaseNamingPolicy(),
WriteIndented = true,
};
}
}
public T Read(string file)
{
IOUtils ioUtils = new IOUtils();
string data = ioUtils.ReadFile(file);
return JsonSerializer.Deserialize<T>(data, JsonOptions);
}
public string Serialize(T data)
{
return JsonSerializer.Serialize(data, JsonOptions);
}
}
}

View File

@@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace FancyZonesEditorCommon.Data
{
public class EditorParameters : EditorData<EditorParameters.ParamsWrapper>
{
public string File
{
get
{
return GetDataFolder() + "\\Microsoft\\PowerToys\\FancyZones\\editor-parameters.json";
}
}
public struct NativeMonitorDataWrapper
{
public string Monitor { get; set; }
public string MonitorInstanceId { get; set; }
public string MonitorSerialNumber { get; set; }
public int MonitorNumber { get; set; }
public string VirtualDesktop { get; set; }
public int Dpi { get; set; }
public int LeftCoordinate { get; set; }
public int TopCoordinate { get; set; }
public int WorkAreaWidth { get; set; }
public int WorkAreaHeight { get; set; }
public int MonitorWidth { get; set; }
public int MonitorHeight { get; set; }
public bool IsSelected { get; set; }
public override string ToString()
{
var sb = new StringBuilder();
// using CultureInfo.InvariantCulture since this is internal data
sb.Append("Monitor: ");
sb.AppendLine(Monitor);
sb.Append("Virtual desktop: ");
sb.AppendLine(VirtualDesktop);
sb.Append("DPI: ");
sb.AppendLine(Dpi.ToString(CultureInfo.InvariantCulture));
sb.Append("X: ");
sb.AppendLine(LeftCoordinate.ToString(CultureInfo.InvariantCulture));
sb.Append("Y: ");
sb.AppendLine(TopCoordinate.ToString(CultureInfo.InvariantCulture));
sb.Append("Width: ");
sb.AppendLine(MonitorWidth.ToString(CultureInfo.InvariantCulture));
sb.Append("Height: ");
sb.AppendLine(MonitorHeight.ToString(CultureInfo.InvariantCulture));
return sb.ToString();
}
}
public struct ParamsWrapper
{
public int ProcessId { get; set; }
public bool SpanZonesAcrossMonitors { get; set; }
public List<NativeMonitorDataWrapper> Monitors { get; set; }
}
public EditorParameters()
: base()
{
}
}
}

View File

@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace FancyZonesEditorCommon.Data
{
public class LayoutDefaultSettings
{
// TODO: share the constants b/w C# Editor and FancyZoneLib
public const bool DefaultShowSpacing = true;
public const int DefaultSpacing = 16;
public const int DefaultZoneCount = 3;
public const int DefaultSensitivityRadius = 20;
public const int MaxZones = 128;
}
}

View File

@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using static FancyZonesEditorCommon.Data.LayoutHotkeys;
namespace FancyZonesEditorCommon.Data
{
public class LayoutHotkeys : EditorData<LayoutHotkeysWrapper>
{
public string File
{
get
{
return GetDataFolder() + "\\Microsoft\\PowerToys\\FancyZones\\layout-hotkeys.json";
}
}
public struct LayoutHotkeyWrapper
{
public int Key { get; set; }
public string LayoutId { get; set; }
}
public struct LayoutHotkeysWrapper
{
public List<LayoutHotkeyWrapper> LayoutHotkeys { get; set; }
}
}
}

View File

@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using static FancyZonesEditorCommon.Data.LayoutTemplates;
namespace FancyZonesEditorCommon.Data
{
public class LayoutTemplates : EditorData<TemplateLayoutsListWrapper>
{
public string File
{
get
{
return GetDataFolder() + "\\Microsoft\\PowerToys\\FancyZones\\layout-templates.json";
}
}
public struct TemplateLayoutWrapper
{
public string Type { get; set; }
public bool ShowSpacing { get; set; }
public int Spacing { get; set; }
public int ZoneCount { get; set; }
public int SensitivityRadius { get; set; }
}
public struct TemplateLayoutsListWrapper
{
public List<TemplateLayoutWrapper> LayoutTemplates { get; set; }
}
}
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<Version>$(Version).0</Version>
<Authors>Microsoft Corporation</Authors>
<Product>PowerToys</Product>
<Description>PowerToys FancyZonesEditorCommon</Description>
<AssemblyName>PowerToys.FancyZonesEditorCommon</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.IO.Abstractions" />
</ItemGroup>
<PropertyGroup>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\FancyZonesEditorCommon\</OutputPath>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
namespace FancyZonesEditorCommon.Utils
{
public class DashCaseNamingPolicy : JsonNamingPolicy
{
public static DashCaseNamingPolicy Instance { get; } = new DashCaseNamingPolicy();
public override string ConvertName(string name)
{
return name.UpperCamelCaseToDashCase();
}
}
}

View File

@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.IO.Abstractions;
using System.Threading.Tasks;
namespace FancyZonesEditorCommon.Utils
{
public class IOUtils
{
private readonly IFileSystem _fileSystem = new FileSystem();
public IOUtils()
{
}
public void WriteFile(string fileName, string data)
{
_fileSystem.File.WriteAllText(fileName, data);
}
public string ReadFile(string fileName)
{
if (_fileSystem.File.Exists(fileName))
{
var attempts = 0;
while (attempts < 10)
{
try
{
using (Stream inputStream = _fileSystem.File.Open(fileName, FileMode.Open))
using (StreamReader reader = new StreamReader(inputStream))
{
string data = reader.ReadToEnd();
inputStream.Close();
return data;
}
}
catch (Exception)
{
Task.Delay(10).Wait();
}
attempts++;
}
}
return string.Empty;
}
}
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Linq;
namespace FancyZonesEditorCommon.Utils
{
public static class StringUtils
{
public static string UpperCamelCaseToDashCase(this string str)
{
// If it's single letter variable, leave it as it is
if (str.Length == 1)
{
return str;
}
return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "-" + x.ToString() : x.ToString())).ToLowerInvariant();
}
}
}