using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Headless; using Avalonia.VisualTree; using Omika.App.Controls; using Omika.App.Local.Abstractions; using Xunit; namespace Omika.Tests.Mobile; /// /// Bouton « Envoyer un email » : un email exige le réseau, donc le bouton devient /// INACTIF hors ligne — dans TOUS les écrans, puisque la règle est portée par le /// contrôle réutilisable et non répétée sur chaque vue. /// /// /// Le bouton reste VISIBLE et à sa place : l'action existe, elle est seulement /// momentanément impossible, et l'info-bulle le dit. Une détection de connectivité /// en échec ne bloque jamais l'action (repli « considéré en ligne »). /// /// /// /// Session Avalonia headless : la classe rejoint la collection /// « ApplicationRuntimeContext » pour qu'aucune autre session Avalonia ne tourne /// en parallèle (le localisateur d'Avalonia est global au processus). /// [Collection("ApplicationRuntimeContext")] public sealed class EmailButtonTests : IDisposable { private readonly HeadlessUnitTestSession _session = HeadlessUnitTestSession.StartNew(typeof(LayoutTestAppBuilder)); public void Dispose() { // Le point d'injection est statique : on le remet à zéro entre les classes. EmailButton.Connectivite = null; _session.Dispose(); } private sealed class FauxReseau : INetworkConnectivity { public bool Online { get; set; } = true; public Task IsOnlineAsync(CancellationToken cancellationToken = default) => Task.FromResult(Online); } private sealed class FauxReseauEnPanne : INetworkConnectivity { public Task IsOnlineAsync(CancellationToken cancellationToken = default) => throw new InvalidOperationException("capteur réseau indisponible"); } /// Bouton réellement rendu à l'intérieur du contrôle. private static Button BoutonInterne(EmailButton email) => email.GetVisualDescendants().OfType