test: classify prerequisite lanes and own Avalonia sessions

This commit is contained in:
Erik 2026-08-18 11:30:47 +02:00
parent c1a905004a
commit 3684e7b5e7
113 changed files with 273 additions and 22 deletions

View file

@ -19,8 +19,8 @@ namespace AcDream.Launcher.Tests;
/// generated <c>InitializeComponent()</c>) reached the user gate through
/// 14,012 green tests that were all ViewModel-only.
///
/// Every test here constructs a real <see cref="MainWindow"/> against the
/// real compiled XAML and drives it exactly the way <c>App.axaml.cs</c>
/// The Avalonia test constructs real <see cref="MainWindow"/> instances against
/// the compiled XAML and drives them exactly the way <c>App.axaml.cs</c>
/// does: assign a live <see cref="LauncherWindowViewModel"/> as
/// <c>DataContext</c>, then exercise the modal open/close paths that
/// dereference the named controls (the bug class lives in
@ -28,7 +28,7 @@ namespace AcDream.Launcher.Tests;
/// <c>FocusActiveModal</c>). That focus work is queued via
/// <c>Dispatcher.UIThread.Post</c>, so every test pumps the headless
/// dispatcher with <see cref="Dispatcher.RunJobs"/> before asserting — a
/// test that only sets a property and asserts would pass vacuously
/// phase that only sets a property and asserts would pass vacuously
/// without ever running <c>FocusActiveModal</c>.
/// </summary>
public sealed class MainWindowViewTests
@ -49,7 +49,22 @@ public sealed class MainWindowViewTests
];
[AvaloniaFact]
public void EveryExplicitlyNamedControlIsAssignedAfterConstruction()
public async Task CompiledMarkupAndEveryModalFocusPathRunInOneOwnedAvaloniaSession()
{
// Avalonia's headless compositor is thread-affine. Keep the complete
// MainWindow matrix inside one runner-owned application session so
// xUnit cannot tear one compositor down on a different worker while
// starting the next scenario. Each named method remains a separate
// assertion phase for readable failure stacks.
EveryExplicitlyNamedControlIsAssignedAfterConstruction();
ReflectionSweepOfEveryXNameInMarkupFindsANonNullBackingField();
OpeningEveryEditorKindFocusesItsPrimaryFieldAndClosingRunsTheFallbackWithoutThrowing();
OpeningAndClosingTheFirstRunWizardFocusesAndRunsTheCloseFallbackWithoutThrowing();
await OpeningAndClosingTheUpdatePromptFocusesAndRunsTheCloseFallbackWithoutThrowing();
ClosingAModalRestoresThePreviouslyFocusedControlWithoutThrowing();
}
private static void EveryExplicitlyNamedControlIsAssignedAfterConstruction()
{
var window = new MainWindow();
@ -66,8 +81,7 @@ public sealed class MainWindowViewTests
}
}
[AvaloniaFact]
public void ReflectionSweepOfEveryXNameInMarkupFindsANonNullBackingField()
private static void ReflectionSweepOfEveryXNameInMarkupFindsANonNullBackingField()
{
string markupPath = Path.Combine(
FindRepositoryRoot(),
@ -114,8 +128,7 @@ public sealed class MainWindowViewTests
}
}
[AvaloniaFact]
public void OpeningEveryEditorKindFocusesItsPrimaryFieldAndClosingRunsTheFallbackWithoutThrowing()
private static void OpeningEveryEditorKindFocusesItsPrimaryFieldAndClosingRunsTheFallbackWithoutThrowing()
{
(ProfileEditorKind Kind, string FocusFieldName)[] cases =
[
@ -168,8 +181,7 @@ public sealed class MainWindowViewTests
}
}
[AvaloniaFact]
public void OpeningAndClosingTheFirstRunWizardFocusesAndRunsTheCloseFallbackWithoutThrowing()
private static void OpeningAndClosingTheFirstRunWizardFocusesAndRunsTheCloseFallbackWithoutThrowing()
{
using LauncherWindowViewModel viewModel = CreateViewModel();
var window = new MainWindow { DataContext = viewModel };
@ -198,8 +210,7 @@ public sealed class MainWindowViewTests
}
}
[AvaloniaFact]
public async Task OpeningAndClosingTheUpdatePromptFocusesAndRunsTheCloseFallbackWithoutThrowing()
private static async Task OpeningAndClosingTheUpdatePromptFocusesAndRunsTheCloseFallbackWithoutThrowing()
{
using LauncherWindowViewModel viewModel = CreateViewModel();
var window = new MainWindow { DataContext = viewModel };
@ -228,8 +239,7 @@ public sealed class MainWindowViewTests
}
}
[AvaloniaFact]
public void ClosingAModalRestoresThePreviouslyFocusedControlWithoutThrowing()
private static void ClosingAModalRestoresThePreviouslyFocusedControlWithoutThrowing()
{
using LauncherWindowViewModel viewModel = CreateViewModel();
var window = new MainWindow { DataContext = viewModel };