95 lines
3.5 KiB
C#
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();
|
|
}
|