fix(postit): mount session banner in headless tests
All checks were successful
Dotnet build and test / build (push) Successful in 25m17s

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Paul Schneider 2026-10-11 07:28:17 +01:00
commit 2744619249
Signed by: notazof
GPG key ID: AD4B9B545FBD7D12
2 changed files with 29 additions and 32 deletions

View file

@ -29,6 +29,11 @@
### Fixed ### Fixed
* [PostIt.Tests] Les tests du bandeau de session utilisent le bandeau
réellement monté dans la fenêtre headless, au lieu d'un contrôle détaché.
Les fenêtres sont fermées après chaque test et les quatre boutons
de navigation sont vérifiés.
* [PostIt] Les liens Markdown des pièces jointes utilisent désormais * [PostIt] Les liens Markdown des pièces jointes utilisent désormais
le même filtre de nom que l'upload serveur, avant l'encodage URL. le même filtre de nom que l'upload serveur, avant l'encodage URL.
Le libellé conserve le nom original, notamment ses accents. Le libellé conserve le nom original, notamment ses accents.

View file

@ -1,6 +1,5 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Headless.XUnit; using Avalonia.Headless.XUnit;
using Avalonia.Styling;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using PostIt.ViewModels; using PostIt.ViewModels;
using PostIt.Views; using PostIt.Views;
@ -23,41 +22,36 @@ namespace PostIt.Tests;
/// <c>new Window().Show()</c> throws because the harness has not /// <c>new Window().Show()</c> throws because the harness has not
/// been initialised for that thread.</para> /// been initialised for that thread.</para>
/// ///
/// <para>The session banner's <c>DataContext</c> is not wired in /// <para>These tests set the DataContext directly on the banner
/// these tests: <c>App.OnFrameworkInitializationCompleted</c> is /// mounted in the window. The production code path is exercised
/// not called in a unit test, so we set the DataContext on the
/// banner directly. The production code path is exercised
/// end-to-end by the manual launch, not here.</para> /// end-to-end by the manual launch, not here.</para>
/// </summary> /// </summary>
public class SessionStatusBannerTests public class SessionStatusBannerTests : IDisposable
{ {
[AvaloniaFact] private MainWindow? _window;
public void Banner_renders_three_buttons_in_the_visual_tree()
{
MainWindow window = new MainWindow();
window.Show();
var buttons = window.GetVisualDescendants() [AvaloniaFact]
public void Banner_renders_four_buttons_in_the_visual_tree()
{
SessionStatusBanner banner = CreateBanner();
var buttons = banner.GetVisualDescendants()
.OfType<Button>() .OfType<Button>()
.ToList(); .ToList();
// Three buttons, named by their content text: Se Assert.Equal(4, buttons.Count);
// déconnecter, Se connecter, Paramètres. If any one is
// missing, the user has no way to trigger the
// corresponding navigation event.
Assert.True(buttons.Count>=4);
Assert.Contains(buttons, b => b.Content as string == "Se déconnecter"); Assert.Contains(buttons, b => b.Content as string == "Se déconnecter");
Assert.Contains(buttons, b => b.Content as string == "Se connecter"); Assert.Contains(buttons, b => b.Content as string == "Se connecter");
Assert.Contains(buttons, b => b.Content as string == "Paramètres"); Assert.Contains(buttons, b => b.Content as string == "Paramètres");
Assert.Contains(buttons, b => b.Content as string == "À propos");
} }
[AvaloniaFact] [AvaloniaFact]
public void Banner_login_button_is_visible_when_logged_out() public void Banner_login_button_is_visible_when_logged_out()
{ {
MainWindow window = new MainWindow(); SessionStatusBanner banner = CreateBanner();
window.Show();
var login = window.GetVisualDescendants() var login = banner.GetVisualDescendants()
.OfType<Button>() .OfType<Button>()
.Single(b => b.Content as string == "Se connecter"); .Single(b => b.Content as string == "Se connecter");
@ -71,10 +65,7 @@ public class SessionStatusBannerTests
{ {
SessionStatusBanner banner = CreateBanner(); SessionStatusBanner banner = CreateBanner();
Assert.False((banner.DataContext as SessionStatusViewModel)! Assert.False(Assert.IsType<SessionStatusViewModel>(banner.DataContext).IsLoggedIn);
.IsLoggedIn); // VM default
var logout = banner.GetVisualDescendants() var logout = banner.GetVisualDescendants()
.OfType<Button>() .OfType<Button>()
.Single(b => b.Content as string == "Se déconnecter"); .Single(b => b.Content as string == "Se déconnecter");
@ -91,22 +82,23 @@ public class SessionStatusBannerTests
.OfType<Button>() .OfType<Button>()
.Single(b => b.Content as string == "Paramètres"); .Single(b => b.Content as string == "Paramètres");
// Paramètres is the only button with no IsVisible // Paramètres has no IsVisible binding and is always shown.
// binding — always shown. The user's only path to the
// settings page goes through this button.
Assert.True(settings.IsVisible); Assert.True(settings.IsVisible);
} }
private static SessionStatusBanner CreateBanner() private SessionStatusBanner CreateBanner()
{ {
MainWindow window = new MainWindow(); _window = new MainWindow();
window.Show(); _window.Show();
var banner = new SessionStatusBanner(); var banner = _window.GetVisualDescendants()
var status = new SessionStatusViewModel(); .OfType<SessionStatusBanner>()
banner.DataContext = status; .Single();
banner.DataContext = new SessionStatusViewModel();
return banner; return banner;
} }
public void Dispose() => _window?.Close();
[AvaloniaFact] [AvaloniaFact]
public void Banner_session_label_reflects_DataContext() public void Banner_session_label_reflects_DataContext()
{ {