Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2084,6 +2084,8 @@ wifi
wikimedia
wikipedia
winapi
winapp
winappcli
winappsdk
windir
WINDOWCREATED
Expand Down
30 changes: 21 additions & 9 deletions PowerToys.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/Common.UI/Common.UI.csproj">
<Project Path="src/common/Common.UI.Controls/Common.UI.Controls.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/Common.UI.Controls/Common.UI.Controls.csproj">
<Project Path="src/common/Common.UI/Common.UI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
Expand Down Expand Up @@ -54,10 +54,14 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/UITestAutomation.Next/UITestAutomation.Next.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/UnitTests-CommonLib/UnitTests-CommonLib.vcxproj" Id="1a066c63-64b3-45f8-92fe-664e1cce8077" />
<Project Path="src/common/UnitTests-CommonUtils/UnitTests-CommonUtils.vcxproj" Id="8b5cfb38-ccba-40a8-ad7a-89c57b070884" />
<Project Path="src/common/updating/updating.vcxproj" Id="17da04df-e393-4397-9cf0-84dabe11032e" />
<Project Path="src/common/updating/UnitTests/UpdatingUnitTests.vcxproj" Id="a1b2c3d4-e5f6-7890-abcd-ef1234567890" />
<Project Path="src/common/updating/updating.vcxproj" Id="17da04df-e393-4397-9cf0-84dabe11032e" />
<Project Path="src/common/version/version.vcxproj" Id="cc6e41ac-8174-4e8a-8d22-85dd7f4851df" />
</Folder>
<Folder Name="/common/interop/">
Expand Down Expand Up @@ -190,6 +194,10 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/colorPicker/ColorPicker.UITests/ColorPicker.UITests.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/modules/CommandPalette/">
<Project Path="src/modules/cmdpal/CmdPalKeyboardService/CmdPalKeyboardService.vcxproj" Id="5f63c743-f6ce-4dba-a200-2b3f8a14e8c2" />
Expand All @@ -200,11 +208,11 @@
</Project>
</Folder>
<Folder Name="/modules/CommandPalette/Built-in Extensions/">
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Microsoft.CmdPal.Ext.Apps.csproj">
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Actions/Microsoft.CmdPal.Ext.Actions.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Actions/Microsoft.CmdPal.Ext.Actions.csproj">
<Project Path="src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.Apps/Microsoft.CmdPal.Ext.Apps.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
Expand Down Expand Up @@ -715,11 +723,11 @@
</Project>
</Folder>
<Folder Name="/modules/PowerDisplay/">
<Project Path="src/modules/powerdisplay/PowerDisplay.Models/PowerDisplay.Models.csproj">
<Project Path="src/modules/powerdisplay/PowerDisplay.Lib/PowerDisplay.Lib.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/modules/powerdisplay/PowerDisplay.Lib/PowerDisplay.Lib.csproj">
<Project Path="src/modules/powerdisplay/PowerDisplay.Models/PowerDisplay.Models.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
Expand Down Expand Up @@ -1088,6 +1096,10 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/settings-ui/UITest-Settings.Next/UITest-Settings.Next.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
</Folder>
<Folder Name="/Solution Items/">
<File Path=".vsconfig" />
Expand Down Expand Up @@ -1119,14 +1131,14 @@
<BuildDependency Project="src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj" />
<BuildDependency Project="src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj" />
<BuildDependency Project="src/modules/fancyzones/FancyZonesModuleInterface/FancyZonesModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/imageresizer/dll/ImageResizerExt.vcxproj" />
<BuildDependency Project="src/modules/imageresizer/ui/ImageResizerUI.csproj" />
<BuildDependency Project="src/modules/keyboardmanager/dll/KeyboardManager.vcxproj" />
<BuildDependency Project="src/modules/launcher/Microsoft.Launcher/Microsoft.Launcher.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" />
<BuildDependency Project="src/modules/powerrename/dll/PowerRenameExt.vcxproj" />
<BuildDependency Project="src/modules/powerrename/lib/PowerRenameLib.vcxproj" />
<BuildDependency Project="src/modules/previewpane/Common/PreviewHandlerCommon.csproj" />
Expand Down
49 changes: 49 additions & 0 deletions src/common/UITestAutomation.Next/By.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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 Microsoft.PowerToys.UITest.Next;

/// <summary>
/// Selector used to locate elements via winappcli. winappcli has its own selector grammar
/// (semantic slugs, plain text search) so this type maps onto the CLI's argument shape
/// rather than mimicking Selenium's <c>By</c>.
/// </summary>
public sealed class By
{
public enum Kind
{
/// <summary>Plain-text search against Name or AutomationId (case-insensitive substring).</summary>
Text,

/// <summary>Stable AutomationId, when the developer set one.</summary>
AutomationId,

/// <summary>A semantic slug (e.g., <c>btn-close-d1a0</c>) printed by <c>inspect</c>/<c>search</c>.</summary>
Slug,
}

public Kind Selector { get; }

public string Value { get; }

private By(Kind kind, string value)
{
Selector = kind;
Value = value;
}

/// <summary>Plain-text search; what you'd type into <c>winapp ui search "&lt;text&gt;"</c>.</summary>
public static By Name(string name) => new(Kind.Text, name);

/// <summary>Look up by stable AutomationId (winappcli also accepts these as selectors).</summary>
public static By AccessibilityId(string id) => new(Kind.AutomationId, id);

/// <inheritdoc cref="AccessibilityId(string)"/>
public static By Id(string id) => new(Kind.AutomationId, id);

/// <summary>Direct slug selector (e.g., <c>btn-colorpicker-b415</c>) as printed by inspect/search.</summary>
public static By Slug(string slug) => new(Kind.Slug, slug);

public override string ToString() => $"{Selector}={Value}";
}
75 changes: 75 additions & 0 deletions src/common/UITestAutomation.Next/ClipboardHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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 FormsClipboard = System.Windows.Forms.Clipboard;

namespace Microsoft.PowerToys.UITest.Next;

/// <summary>
/// Clipboard helpers that always execute on an STA thread (<see cref="FormsClipboard"/>
/// requires it). Tolerant — every method swallows clipboard errors and returns a default,
/// so callers can use them in test <c>finally</c> blocks without worrying about masking
/// the real failure.
/// </summary>
public static class ClipboardHelper
{
/// <summary>Return the current clipboard text, or <see cref="string.Empty"/> if none / on error.</summary>
public static string GetText() => RunSTA(() => FormsClipboard.ContainsText() ? FormsClipboard.GetText() : string.Empty) ?? string.Empty;

/// <summary>Clear the clipboard. Returns true on success, false on error.</summary>
public static bool Clear() => RunSTA(() => { FormsClipboard.Clear(); return true; });

/// <summary>Set the clipboard text. Returns true on success, false on error.</summary>
public static bool SetText(string value) => RunSTA(() => { FormsClipboard.SetText(value); return true; });

/// <summary>
/// Poll the clipboard up to <paramref name="timeoutMS"/> for the first non-empty text
/// different from <paramref name="ignoredValue"/>. Returns <see cref="string.Empty"/> on
/// timeout. Use when you've just cleared the clipboard and are waiting for an external
/// app (e.g. ColorPicker on click) to write into it.
/// </summary>
public static string WaitForText(string ignoredValue = "", int timeoutMS = 3_000, int pollIntervalMS = 100)
{
var deadline = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeoutMS);
while (DateTime.UtcNow < deadline)
{
var text = GetText();
if (!string.IsNullOrEmpty(text) && text != ignoredValue)
{
return text;
}

Thread.Sleep(pollIntervalMS);
}

return string.Empty;
}

private static T? RunSTA<T>(Func<T> body)
{
T? result = default;
try
{
var thread = new Thread(() =>
{
try
{
result = body();
}
catch
{
// Best effort — clipboard can throw under contention (OpenClipboard failures).
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join(TimeSpan.FromSeconds(5));
}
catch
{
}

return result;
}
}
13 changes: 13 additions & 0 deletions src/common/UITestAutomation.Next/Element/Button.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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 Microsoft.PowerToys.UITest.Next;

public class Button : Element
{
public Button()
{
TargetControlType = "Button";
}
}
Loading
Loading