125 lines
4.6 KiB
C#
125 lines
4.6 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Headless.XUnit;
|
|
using Avalonia.Media;
|
|
using Avalonia.Styling;
|
|
using Avalonia.VisualTree;
|
|
using PostIt.ViewModels;
|
|
using PostIt.Views;
|
|
|
|
namespace PostIt.Tests;
|
|
|
|
/// <summary>
|
|
/// UI tests for <see cref="SessionStatusBanner"/>. Mounted inside
|
|
/// a real <see cref="MainWindow"/> via the headless Avalonia
|
|
/// platform declared in <c>TestApp.cs</c>.
|
|
///
|
|
/// <para>The pattern is the one that <c>UnitTest1.MainPage_Should_Load</c>
|
|
/// established: a test attribute <c>[AvaloniaFact]</c> (from
|
|
/// <c>Avalonia.Headless.XUnit</c>) instead of plain <c>[Fact]</c>,
|
|
/// <c>new MainWindow()</c>, <c>window.Show()</c>. The AvaloniaFact
|
|
/// attribute schedules the test body inside a dispatcher, which
|
|
/// is the precondition for the headless Window's
|
|
/// <c>PlatformManager.CreateWindow()</c> to find a registered
|
|
/// service. A plain <c>[Fact]</c> test that calls
|
|
/// <c>new Window().Show()</c> throws because the harness has not
|
|
/// been initialised for that thread.</para>
|
|
///
|
|
/// <para>The session banner's <c>DataContext</c> is not wired in
|
|
/// these tests: <c>App.OnFrameworkInitializationCompleted</c> is
|
|
/// 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>
|
|
/// </summary>
|
|
public class SessionStatusBannerTests
|
|
{
|
|
[AvaloniaFact]
|
|
public void Banner_renders_three_buttons_in_the_visual_tree()
|
|
{
|
|
var window = new MainWindow();
|
|
window.SessionBanner.DataContext = new SessionStatusViewModel();
|
|
window.Show();
|
|
|
|
var buttons = window.SessionBanner.GetVisualDescendants()
|
|
.OfType<Button>()
|
|
.ToList();
|
|
|
|
// Three buttons, named by their content text: Se
|
|
// déconnecter, Se connecter, Paramètres. If any one is
|
|
// missing, the user has no way to trigger the
|
|
// corresponding navigation event.
|
|
Assert.Equal(3, buttons.Count);
|
|
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 == "Paramètres");
|
|
}
|
|
|
|
[AvaloniaFact]
|
|
public void Banner_login_button_is_visible_when_logged_out()
|
|
{
|
|
var window = new MainWindow();
|
|
var vm = new SessionStatusViewModel();
|
|
Assert.True(vm.IsLoggedOut); // VM default
|
|
window.SessionBanner.DataContext = vm;
|
|
window.Show();
|
|
|
|
var login = window.SessionBanner.GetVisualDescendants()
|
|
.OfType<Button>()
|
|
.Single(b => b.Content as string == "Se connecter");
|
|
|
|
// The XAML binds IsVisible to IsLoggedOut. After Show,
|
|
// the binding has been evaluated.
|
|
Assert.True(login.IsVisible);
|
|
}
|
|
|
|
[AvaloniaFact]
|
|
public void Banner_logout_button_is_hidden_when_logged_out()
|
|
{
|
|
var window = new MainWindow();
|
|
var vm = new SessionStatusViewModel();
|
|
Assert.False(vm.IsLoggedIn); // VM default
|
|
window.SessionBanner.DataContext = vm;
|
|
window.Show();
|
|
|
|
var logout = window.SessionBanner.GetVisualDescendants()
|
|
.OfType<Button>()
|
|
.Single(b => b.Content as string == "Se déconnecter");
|
|
|
|
Assert.False(logout.IsVisible);
|
|
}
|
|
|
|
[AvaloniaFact]
|
|
public void Banner_settings_button_is_visible_regardless_of_session()
|
|
{
|
|
var window = new MainWindow();
|
|
window.SessionBanner.DataContext = new SessionStatusViewModel();
|
|
window.Show();
|
|
|
|
var settings = window.SessionBanner.GetVisualDescendants()
|
|
.OfType<Button>()
|
|
.Single(b => b.Content as string == "Paramètres");
|
|
|
|
// Paramètres is the only button with no IsVisible
|
|
// binding — always shown. The user's only path to the
|
|
// settings page goes through this button.
|
|
Assert.True(settings.IsVisible);
|
|
}
|
|
|
|
[AvaloniaFact]
|
|
public void Banner_session_label_reflects_DataContext()
|
|
{
|
|
var window = new MainWindow();
|
|
window.SessionBanner.DataContext = new SessionStatusViewModel();
|
|
window.Show();
|
|
|
|
var label = window.SessionBanner.GetVisualDescendants()
|
|
.OfType<TextBlock>()
|
|
.First(t => t.Text == "Déconnecté" || t.Text == "Connecté");
|
|
|
|
// Default SessionLabel is "Déconnecté" until Refresh()
|
|
// is called with a valid session. This pins the default
|
|
// so a future refactor that breaks the initial value
|
|
// (e.g. by removing the field initialiser) is caught.
|
|
Assert.Equal("Déconnecté", label.Text);
|
|
}
|
|
}
|