You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
6.4 KiB
196 lines
6.4 KiB
using Avalonia.Controls; |
|
using Avalonia.Controls.Primitives; |
|
using Avalonia.Media.Imaging; |
|
using Avalonia.Threading; |
|
using Avalonia.VisualTree; |
|
using FluentAvalonia.UI.Controls; |
|
using FluentAvalonia.UI.Windowing; |
|
using Microsoft.Extensions.DependencyInjection; |
|
using StabilityMatrix.Avalonia; |
|
using StabilityMatrix.Avalonia.Controls; |
|
using StabilityMatrix.Avalonia.Languages; |
|
using StabilityMatrix.Avalonia.ViewModels; |
|
using StabilityMatrix.Avalonia.ViewModels.Dialogs; |
|
using StabilityMatrix.Avalonia.Views; |
|
using StabilityMatrix.Avalonia.Views.Dialogs; |
|
using StabilityMatrix.UITests.Extensions; |
|
|
|
namespace StabilityMatrix.UITests; |
|
|
|
public class TestBase |
|
{ |
|
internal static IServiceProvider Services => App.Services; |
|
|
|
internal static (AppWindow, MainWindowViewModel)? currentMainWindow; |
|
|
|
internal virtual VerifySettings Settings |
|
{ |
|
get |
|
{ |
|
var settings = new VerifySettings(); |
|
settings.IgnoreMembers<MainWindowViewModel>( |
|
vm => vm.Pages, |
|
vm => vm.FooterPages, |
|
vm => vm.CurrentPage |
|
); |
|
settings.IgnoreMember<UpdateViewModel>(vm => vm.CurrentVersionText); |
|
settings.DisableDiff(); |
|
return settings; |
|
} |
|
} |
|
|
|
internal static (AppWindow, MainWindowViewModel) GetMainWindow() |
|
{ |
|
if (currentMainWindow is not null) |
|
{ |
|
return currentMainWindow.Value; |
|
} |
|
|
|
var window = Services.GetRequiredService<MainWindow>(); |
|
var viewModel = Services.GetRequiredService<MainWindowViewModel>(); |
|
window.DataContext = viewModel; |
|
|
|
window.SetDefaultFonts(); |
|
window.Width = 1400; |
|
window.Height = 900; |
|
|
|
App.VisualRoot = window; |
|
App.StorageProvider = window.StorageProvider; |
|
App.Clipboard = window.Clipboard ?? throw new NullReferenceException("Clipboard is null"); |
|
|
|
currentMainWindow = (window, viewModel); |
|
return currentMainWindow.Value; |
|
} |
|
|
|
internal static async Task DoInitialSetup() |
|
{ |
|
var (window, _) = GetMainWindow(); |
|
|
|
if (!window.IsVisible) |
|
{ |
|
window.Show(); |
|
await Task.Delay(300); |
|
Dispatcher.UIThread.RunJobs(); |
|
} |
|
|
|
try |
|
{ |
|
var dialog = await WaitHelper.WaitForNotNullAsync(() => GetWindowDialog(window)); |
|
|
|
if (dialog.Content is SelectDataDirectoryDialog selectDataDirectoryDialog) |
|
{ |
|
// Click continue button |
|
var continueButton = selectDataDirectoryDialog |
|
.GetVisualDescendants() |
|
.OfType<Button>() |
|
.First(b => b.Content as string == "Continue"); |
|
|
|
await window.ClickTargetAsync(continueButton); |
|
await Task.Delay(300); |
|
Dispatcher.UIThread.RunJobs(); |
|
|
|
// Find the one click install dialog |
|
var oneClickDialog = await WaitHelper.WaitForConditionAsync( |
|
() => GetWindowDialog(window), |
|
d => d?.Content is OneClickInstallDialog |
|
); |
|
Assert.NotNull(oneClickDialog); |
|
|
|
var skipButton = oneClickDialog |
|
.GetVisualDescendants() |
|
.OfType<Button>() |
|
.First(b => b.Content as string == Resources.Label_SkipSetup); |
|
|
|
await window.ClickTargetAsync(skipButton); |
|
await Task.Delay(300); |
|
Dispatcher.UIThread.RunJobs(); |
|
} |
|
else if (dialog.Content is OneClickInstallDialog) |
|
{ |
|
var skipButton = dialog |
|
.GetVisualDescendants() |
|
.OfType<Button>() |
|
.First(b => b.Content as string == Resources.Label_SkipSetup); |
|
|
|
await window.ClickTargetAsync(skipButton); |
|
await Task.Delay(300); |
|
Dispatcher.UIThread.RunJobs(); |
|
} |
|
} |
|
catch (TimeoutException) |
|
{ |
|
// ignored |
|
} |
|
} |
|
|
|
internal static async Task CloseUpdateDialog() |
|
{ |
|
var (window, _) = GetMainWindow(); |
|
|
|
var updateTip = window.FindControl<TeachingTip>("UpdateAvailableTeachingTip"); |
|
await window.ClickTargetAsync(updateTip); |
|
|
|
await Task.Delay(300); |
|
Dispatcher.UIThread.RunJobs(); |
|
} |
|
|
|
internal static BetterContentDialog? GetWindowDialog(Visual window) |
|
{ |
|
return window |
|
.FindDescendantOfType<VisualLayerManager>() |
|
?.FindDescendantOfType<OverlayLayer>() |
|
?.FindDescendantOfType<DialogHost>() |
|
?.FindDescendantOfType<LayoutTransformControl>() |
|
?.FindDescendantOfType<VisualLayerManager>() |
|
?.FindDescendantOfType<BetterContentDialog>(); |
|
} |
|
|
|
internal static IEnumerable<BetterContentDialog> EnumerateWindowDialogs(Visual window) |
|
{ |
|
return window |
|
.FindDescendantOfType<VisualLayerManager>() |
|
?.FindDescendantOfType<OverlayLayer>() |
|
?.FindDescendantOfType<DialogHost>() |
|
?.FindDescendantOfType<LayoutTransformControl>() |
|
?.FindDescendantOfType<VisualLayerManager>() |
|
?.GetVisualDescendants() |
|
.OfType<BetterContentDialog>() ?? Enumerable.Empty<BetterContentDialog>(); |
|
} |
|
|
|
internal async Task<(BetterContentDialog, T)> WaitForDialog<T>(Visual window) |
|
where T : Control |
|
{ |
|
var dialogs = await WaitHelper.WaitForConditionAsync( |
|
() => EnumerateWindowDialogs(window).ToList(), |
|
list => list.Any(dialog => dialog.Content is T) |
|
); |
|
|
|
if (dialogs.Count == 0) |
|
{ |
|
throw new InvalidOperationException("No dialogs found"); |
|
} |
|
|
|
var contentDialog = dialogs.First(dialog => dialog.Content is T); |
|
|
|
return (contentDialog, contentDialog.Content as T)!; |
|
} |
|
|
|
internal void SaveScreenshot(Visual visual) |
|
{ |
|
var rect = new Rect(visual!.Bounds.Size); |
|
|
|
var pixelSize = new PixelSize((int)rect.Width, (int)rect.Height); |
|
var dpiVector = new Vector(96, 96); |
|
using var bitmap = new RenderTargetBitmap(pixelSize, dpiVector); |
|
|
|
using var fs = File.Open( |
|
$"C:\\StabilityMatrix\\StabilityMatrix-avalonia\\StabilityMatrix.UITests\\" |
|
+ Guid.NewGuid().ToString() |
|
+ ".png", |
|
FileMode.OpenOrCreate |
|
); |
|
bitmap.Render(visual); |
|
bitmap.Save(fs); |
|
fs.Flush(); |
|
} |
|
}
|
|
|