Browse Source

Merge 24948939e6 into 3068850405

pull/17841/merge
StefanKoell 3 days ago
committed by GitHub
parent
commit
32492e5940
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      samples/IntegrationTestApp/MainWindow.axaml.cs
  2. 69
      samples/IntegrationTestApp/Pages/PopupsPage.axaml
  3. 48
      samples/IntegrationTestApp/Pages/PopupsPage.axaml.cs
  4. 4
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  5. 6
      src/Windows/Avalonia.Win32/PopupImpl.cs
  6. 63
      tests/Avalonia.IntegrationTests.Appium/MenuTests.cs
  7. 199
      tests/Avalonia.IntegrationTests.Appium/PopupsTests.cs

1
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -89,6 +89,7 @@ namespace IntegrationTestApp
new("ListBox", () => new ListBoxPage()),
new("Menu", () => new MenuPage()),
new("Pointer", () => new PointerPage()),
new("Popups", () => new PopupsPage()),
new("RadioButton", () => new RadioButtonPage()),
new("Screens", () => new ScreensPage()),
new("ScrollBar", () => new ScrollBarPage()),

69
samples/IntegrationTestApp/Pages/PopupsPage.axaml

@ -0,0 +1,69 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="IntegrationTestApp.Pages.PopupsPage">
<StackPanel Orientation="Vertical" Spacing="10">
<Button x:Name="DismissButton"
Content="Dismiss Button" />
<TextBlock Text="'Light Dismiss' Popup" />
<Button x:Name="ShowLightDismissPopup"
Content="Show Popup" Click="ButtonLightDismiss_OnClick" />
<Popup x:Name="LightDismissPopup"
PlacementTarget="ShowLightDismissPopup"
Placement="Bottom"
IsLightDismissEnabled="True">
<Panel Background="Gray"
Margin="10"
MinWidth="100"
MinHeight="30">
<TextBox Text="Popup Content"
Name="LightDismissPopupContent" />
</Panel>
</Popup>
<TextBlock Text="Popup that stays open" />
<Button x:Name="ShowStaysOpenPopup"
Content="Show Popup" Click="ButtonPopupStaysOpen_OnClick" />
<Popup x:Name="StaysOpenPopup"
PlacementTarget="ShowStaysOpenPopup"
Placement="Bottom"
IsLightDismissEnabled="False">
<StackPanel Background="Gray"
MinWidth="100"
MinHeight="30"
Spacing="20"
Orientation="Vertical">
<TextBox Name="StaysOpenTextBox"
Width="100"
Text="Some text" />
<Button Name="StaysOpenPopupCloseButton"
Click="StaysOpenPopupCloseButton_OnClick"
Content="Click to Close" />
</StackPanel>
</Popup>
<TextBlock Text="TopMost popup that stays open" />
<Button x:Name="ShowTopMostPopup"
Content="Show Popup" Click="ButtonTopMostPopupStaysOpen" />
<Popup x:Name="TopMostPopup"
Placement="Top"
PlacementTarget="ShowTopMostPopup"
IsLightDismissEnabled="False"
Topmost="True">
<Panel MinWidth="100"
MinHeight="30">
<Button Name="TopMostPopupCloseButton"
Click="TopMostPopupCloseButton_OnClick"
Content="Click to Close" />
</Panel>
</Popup>
<Button x:Name="OpenNewWindowButton"
Content="Open Regular New Window"
Click="OpenRegularNewWindow_Click" />
</StackPanel>
</UserControl>

48
samples/IntegrationTestApp/Pages/PopupsPage.axaml.cs

@ -0,0 +1,48 @@
using Avalonia;
using Avalonia.Automation;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace IntegrationTestApp.Pages;
public partial class PopupsPage : UserControl
{
public PopupsPage()
{
InitializeComponent();
}
private void ButtonLightDismiss_OnClick(object sender, RoutedEventArgs e)
{
LightDismissPopup.Open();
}
private void ButtonPopupStaysOpen_OnClick(object sender, RoutedEventArgs e)
{
StaysOpenPopup.Open();
}
private void StaysOpenPopupCloseButton_OnClick(object? sender, RoutedEventArgs e)
{
StaysOpenPopup.Close();
}
private void ButtonTopMostPopupStaysOpen(object sender, RoutedEventArgs e)
{
TopMostPopup.Open();
}
private void TopMostPopupCloseButton_OnClick(object? sender, RoutedEventArgs e)
{
TopMostPopup.Close();
}
private void OpenRegularNewWindow_Click(object? sender, RoutedEventArgs e)
{
var newWindow = new ShowWindowTest();
newWindow.Show((Window)TopLevel.GetTopLevel(this)!);
}
}

4
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -215,6 +215,10 @@ namespace Avalonia.Controls.Primitives
{
PlatformImpl?.SetWindowManagerAddShadowHint(change.GetNewValue<bool>());
}
else if (change.Property == TopmostProperty)
{
PlatformImpl?.SetTopmost(change.GetNewValue<bool>());
}
}
}
}

6
src/Windows/Avalonia.Win32/PopupImpl.cs

@ -1,7 +1,10 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Threading;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32
@ -53,8 +56,7 @@ namespace Avalonia.Win32
UnmanagedMethods.WindowStyles.WS_CLIPCHILDREN;
UnmanagedMethods.WindowStyles exStyle =
UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW |
UnmanagedMethods.WindowStyles.WS_EX_TOPMOST;
UnmanagedMethods.WindowStyles.WS_EX_TOOLWINDOW;
var result = UnmanagedMethods.CreateWindowEx(
(int)exStyle,

63
tests/Avalonia.IntegrationTests.Appium/MenuTests.cs

@ -1,11 +1,13 @@
using OpenQA.Selenium;
using System;
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;
using Xunit;
namespace Avalonia.IntegrationTests.Appium
{
[Collection("Default")]
public abstract class MenuTests : TestBase
public abstract class MenuTests : TestBase, IDisposable
{
public MenuTests(DefaultAppFixture fixture)
: base(fixture, "Menu")
@ -17,11 +19,18 @@ namespace Avalonia.IntegrationTests.Appium
Assert.Equal("None", clickedMenuItem.Text);
}
public void Dispose()
{
// Click the reset button so that any menu still open gets closed
var reset = Session.FindElementByAccessibilityId("MenuClickedMenuItemReset");
reset?.Click();
}
[Fact]
public void Click_Child()
{
var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem");
rootMenuItem.SendClick();
var childMenuItem = Session.FindElementByAccessibilityId("Child1MenuItem");
@ -35,7 +44,7 @@ namespace Avalonia.IntegrationTests.Appium
public void Click_Grandchild()
{
var rootMenuItem = Session.FindElementByAccessibilityId("RootMenuItem");
rootMenuItem.SendClick();
var childMenuItem = Session.FindElementByAccessibilityId("Child2MenuItem");
@ -53,10 +62,12 @@ namespace Avalonia.IntegrationTests.Appium
{
MovePointerOutOfTheWay();
new Actions(Session)
.KeyDown(Keys.Alt).KeyUp(Keys.Alt)
.SendKeys(Keys.Down + Keys.Enter)
.Perform();
var window = Session.FindElementByAccessibilityId("MainWindow");
window.Click();
window.SendKeys(Keys.LeftAlt);
Thread.Sleep(150);
window.SendKeys(Keys.Down + Keys.Enter);
var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem");
Assert.Equal("_Child 1", clickedMenuItem.Text);
@ -67,10 +78,12 @@ namespace Avalonia.IntegrationTests.Appium
{
MovePointerOutOfTheWay();
new Actions(Session)
.KeyDown(Keys.Alt).KeyUp(Keys.Alt)
.SendKeys(Keys.Down + Keys.Down + Keys.Right + Keys.Enter)
.Perform();
var window = Session.FindElementByAccessibilityId("MainWindow");
window.Click();
window.SendKeys(Keys.LeftAlt);
Thread.Sleep(150);
window.SendKeys(Keys.Down + Keys.Down + Keys.Right + Keys.Enter);
var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem");
Assert.Equal("_Grandchild", clickedMenuItem.Text);
@ -81,10 +94,14 @@ namespace Avalonia.IntegrationTests.Appium
{
MovePointerOutOfTheWay();
new Actions(Session)
.KeyDown(Keys.Alt).KeyUp(Keys.Alt)
.SendKeys("rc")
.Perform();
var window = Session.FindElementByAccessibilityId("MainWindow");
window.Click();
window.SendKeys(Keys.LeftAlt);
Thread.Sleep(150);
window.SendKeys("r");
Thread.Sleep(75);
window.SendKeys("c");
var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem");
Assert.Equal("_Child 1", clickedMenuItem.Text);
@ -95,10 +112,16 @@ namespace Avalonia.IntegrationTests.Appium
{
MovePointerOutOfTheWay();
new Actions(Session)
.KeyDown(Keys.Alt).KeyUp(Keys.Alt)
.SendKeys("rhg")
.Perform();
var window = Session.FindElementByAccessibilityId("MainWindow");
window.Click();
window.SendKeys(Keys.LeftAlt);
Thread.Sleep(150);
window.SendKeys("r");
Thread.Sleep(75);
window.SendKeys("h");
Thread.Sleep(75);
window.SendKeys("g");
var clickedMenuItem = Session.FindElementByAccessibilityId("ClickedMenuItem");
Assert.Equal("_Grandchild", clickedMenuItem.Text);

199
tests/Avalonia.IntegrationTests.Appium/PopupsTests.cs

@ -0,0 +1,199 @@
using System.Threading;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;
using Xunit;
namespace Avalonia.IntegrationTests.Appium;
[Collection("Default")]
public abstract class PopupsTests : TestBase
{
private readonly bool _isOverlayPopups;
protected PopupsTests(bool isOverlayPopups, DefaultAppFixture fixture) : base(fixture, "Popups")
{
_isOverlayPopups = isOverlayPopups;
}
[PlatformFact(TestPlatforms.Windows)]
public void LightDismiss_Popup_Should_Open_And_Close()
{
// Open popup
var button = Session.FindElementByAccessibilityId("ShowLightDismissPopup");
button.Click();
Thread.Sleep(500);
// Assert - Popup is visible
Assert.NotNull(Session.FindElementByAccessibilityId("LightDismissPopupContent"));
// Act - Click outside to dismiss
var dismissBorder = Session.FindElementByAccessibilityId("DismissButton");
dismissBorder.Click();
Thread.Sleep(500);
// Assert - Popup is closed
Assert.Throws<WebDriverException>(() =>
Session.FindElementByAccessibilityId("LightDismissPopupContent"));
}
[PlatformFact(TestPlatforms.Windows)]
public void StaysOpen_Popup_Should_Stay_Open()
{
// Open popup
var button = Session.FindElementByAccessibilityId("ShowStaysOpenPopup");
button.Click();
Thread.Sleep(500);
try
{
// Assert - Popup is visible
Assert.NotNull(Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton"));
// Act - Click outside
var dismissBorder = Session.FindElementByAccessibilityId("DismissButton");
dismissBorder.Click();
Thread.Sleep(500);
// Assert - Popup is still visible
Assert.NotNull(Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton"));
}
finally
{
// Act - Close popup with button
Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton").Click();
Thread.Sleep(400);
// Assert - Popup is closed
Assert.Throws<WebDriverException>(() =>
Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton"));
}
}
[PlatformFact(TestPlatforms.Windows)]
public void StaysOpen_Popup_TextBox_Should_Be_Editable()
{
// Open popup
var button = Session.FindElementByAccessibilityId("ShowStaysOpenPopup");
button.Click();
Thread.Sleep(500);
try
{
// Find and edit the TextBox
var textBox = Session.FindElementByAccessibilityId("StaysOpenTextBox");
textBox.Clear();
textBox.SendKeys("New text value");
Thread.Sleep(500);
// Verify text was changed
Assert.Equal("New text value", textBox.Text);
}
finally
{
// Cleanup - close popup
Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton").Click();
}
}
[PlatformFact(TestPlatforms.Windows)]
public void TopMost_Popup_Should_Stay_Above_Other_Windows()
{
// It's not possible to test overlay topmost with other windows.
if (_isOverlayPopups)
{
return;
}
var staysOpenPopup = Session.FindElementByAccessibilityId("ShowTopMostPopup");
var mainWindowHandle = Session.CurrentWindowHandle;
// Show topmost popup.
staysOpenPopup.Click();
Assert.NotNull(Session.FindElementByAccessibilityId("TopMostPopupCloseButton"));
var hasClosedPopup = false;
try
{
// Open a child window.
using var _ = Session.FindElementByAccessibilityId("OpenNewWindowButton").OpenWindowWithClick();
Thread.Sleep(500);
// Force window to front by maximizing child window.
Session.FindElementByAccessibilityId("CurrentWindowState").SendClick();
Session.FindElementByAccessibilityId("WindowStateMaximized").SendClick();
// Switch back to the mainwindow context and verify tooltip is still accessible.
Session.SwitchTo().Window(mainWindowHandle);
Assert.NotNull(Session.FindElementByAccessibilityId("TopMostPopupCloseButton"));
// Verify we can still interact with the popup by closing it via button.
Session.FindElementByAccessibilityId("TopMostPopupCloseButton").Click();
// Verify popup closed
Assert.Throws<WebDriverException>(() =>
Session.FindElementByAccessibilityId("TopMostPopupCloseButton"));
hasClosedPopup = true;
}
finally
{
if (!hasClosedPopup)
{
Session.FindElementByAccessibilityId("TopMostPopupCloseButton").Click();
}
}
}
[PlatformFact(TestPlatforms.Windows)]
public void Non_TopMost_Popup_Does_Not_Stay_Above_Other_Windows()
{
var topmostButton = Session.FindElementByAccessibilityId("ShowStaysOpenPopup");
var mainWindowHandle = Session.CurrentWindowHandle;
// Show topmost popup.
topmostButton.Click();
Assert.NotNull(Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton"));
try
{
// Open a child window.
var newWindowButton = Session.FindElementByAccessibilityId("OpenNewWindowButton");
using var _ = newWindowButton.OpenWindowWithClick();
// Force window to front by maximizing child window.
Session.FindElementByAccessibilityId("CurrentWindowState").SendClick();
Session.FindElementByAccessibilityId("WindowStateMaximized").SendClick();
// Switch back to the mainwindow context and verify tooltip is still accessible.
Session.SwitchTo().Window(mainWindowHandle);
Assert.NotNull(Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton"));
// Verify we cannot interact with the popup by attempting closing it via button.
Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton").Click();
// Verify popup is still accessible.
Assert.NotNull(Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton"));
}
finally
{
// At this point secondary window should be already closed. And safe to close the popup.
Session.FindElementByAccessibilityId("StaysOpenPopupCloseButton").Click();
}
}
[Collection("Default")]
public class Default : PopupsTests
{
public Default(DefaultAppFixture fixture) : base(false, fixture) { }
}
[Collection("OverlayPopups")]
public class OverlayPopups : PopupsTests
{
public OverlayPopups(OverlayPopupsAppFixture fixture) : base(true, fixture) { }
}
}
Loading…
Cancel
Save