Files
Omika/tests/Omika.Tests/Mobile/LicenseActivationViewConstructionTests.cs
T
2026-10-23 18:46:50 +02:00

95 lines
3.5 KiB
C#

using System.Linq;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Headless;
using Avalonia.VisualTree;
using Omika.App.Local.Abstractions;
using Omika.App.Local.Models;
using Omika.App.ViewModels;
using Omika.App.Views;
using Xunit;
namespace Omika.Tests.Mobile;
/// <summary>
/// Test 1 (régression inscription) : l'écran d'inscription doit toujours
/// exposer la saisie manuelle (TextBox) et le bouton « S'inscrire », en plus du
/// scan QR. Construit la vue réelle sur le backend Skia headless et vérifie la
/// présence effective des contrôles dans l'arbre visuel.
/// </summary>
/// <remarks>
/// Session Avalonia headless : la classe rejoint la collection
/// « ApplicationRuntimeContext » afin qu'aucune autre session headless (ni aucun
/// test construisant une vue Avalonia) ne s'exécute en parallèle — le
/// localisateur d'Avalonia est global au processus.
/// </remarks>
[Collection("ApplicationRuntimeContext")]
public sealed class LicenseActivationViewConstructionTests : IDisposable
{
private readonly HeadlessUnitTestSession _session;
public LicenseActivationViewConstructionTests()
{
_session = HeadlessUnitTestSession.StartNew(typeof(EnrollmentViewTestAppBuilder));
}
public void Dispose() => _session.Dispose();
private sealed class FakeEnrollmentService : IEnrollmentService
{
public Task<MobileEnrollmentConfiguration?> LoadAsync(CancellationToken ct = default)
=> Task.FromResult<MobileEnrollmentConfiguration?>(null);
public Task<EnrollmentResult> EnrollAsync(string qrContent, CancellationToken ct = default)
=> Task.FromResult(EnrollmentResult.Failed("refusée"));
public Task ClearAsync(CancellationToken ct = default) => Task.CompletedTask;
}
private sealed class FakeQrScanner : IEnrollmentQrScanner
{
public Task<string?> ScanAsync(IQrScannerPreviewSink? previewSink, CancellationToken ct = default)
=> Task.FromResult<string?>(null);
}
[Fact]
public void Vue_SaisieManuelle_TextBoxEtBoutonSinscrire_Presents()
{
_session.Dispatch(() =>
{
var viewModel = new LicenseActivationViewModel(new FakeEnrollmentService(), new FakeQrScanner());
var view = new LicenseActivationView { DataContext = viewModel };
Assert.NotNull(view.Content);
Control[] descendants = view.GetVisualDescendants().OfType<Control>().ToArray();
// Champ de saisie manuelle présent et lié à ManualEnrollmentCode.
TextBox? textBox = descendants.OfType<TextBox>()
.FirstOrDefault(t => t.Name == "ManualEnrollmentTextBox");
Assert.NotNull(textBox);
// Bouton « S'inscrire » présent.
Button? enrollButton = descendants.OfType<Button>()
.FirstOrDefault(b => string.Equals(b.Content as string, "S'inscrire", System.StringComparison.Ordinal));
Assert.NotNull(enrollButton);
}, CancellationToken.None);
}
}
/// <summary>Application de test headless (backend Skia + police Inter).</summary>
public sealed class EnrollmentViewTestApp : Application
{
}
/// <summary>Point d'entrée du builder headless.</summary>
public static class EnrollmentViewTestAppBuilder
{
public static AppBuilder BuildAvaloniaApp() => AppBuilder
.Configure<EnrollmentViewTestApp>()
.UseSkia()
.UseHeadless(new AvaloniaHeadlessPlatformOptions { UseHeadlessDrawing = false })
.WithInterFont();
}