using System; using System.Linq; using System.Threading; using Avalonia.Controls; using Avalonia.Headless; using Avalonia.Threading; using Avalonia.VisualTree; using Omika.App.Views; using Xunit; namespace Omika.Tests.Mobile; /// /// Régression « bouton retour toujours accessible » : dans chaque page de détail, /// le bouton « ← Retour » est construit dans un en-tête FIXE, donc HORS de la zone /// de défilement — sinon il disparaît dès que l'utilisateur descend dans la page /// et l'oblige à remonter pour revenir en arrière. /// /// /// Deux pièges de mesure sont évités ici : /// /// la surcharge Dispatch(Action) n'attend pas la fin de l'action /// (elle s'exécute après le retour de l'appel) : les assertions ne seraient /// jamais évaluées dans le test — d'où l'appel à la surcharge générique, qui est /// attendue ; /// une vue non attachée à une fenêtre n'a pas d'arbre visuel : la vue est /// donc réellement affichée dans une fenêtre avant d'être inspectée. /// /// La classe rejoint la collection « ApplicationRuntimeContext » : une session /// Avalonia headless ne doit jamais s'exécuter en parallèle d'une autre, sous /// peine de corrompre le localisateur global d'Avalonia. /// [Collection("ApplicationRuntimeContext")] public sealed class DetailViewBackHeaderTests : IDisposable { private readonly HeadlessUnitTestSession _session; public DetailViewBackHeaderTests() => _session = HeadlessUnitTestSession.StartNew(typeof(LayoutTestAppBuilder)); public void Dispose() => _session.Dispose(); /// Toutes les pages de détail exposant un bouton retour. public static TheoryData VuesDeDetail => new() { typeof(ClientDetailView), typeof(DossierDetailView), typeof(SiteDetailView), typeof(ContactDetailView), typeof(CollaborateurDetailView), typeof(EquipeDetailView), typeof(InterventionDetailView), typeof(InterventionContactsView), typeof(InterventionEmailsView), typeof(InterventionNotesView), typeof(InterventionNotesAdministrativesView), typeof(InterventionResourcesView), typeof(InterventionDocumentsView), typeof(CompteRenduCreateView), typeof(RendezVousDetailView), typeof(RapportChampsView), typeof(NouveauEmailView), typeof(SynchronisationView), typeof(AgendaEquipeView) }; [Theory] [MemberData(nameof(VuesDeDetail))] public void BoutonRetour_EstHorsZoneDeDefilement(Type typeVue) { _session.Dispatch( () => { var vue = (UserControl)Activator.CreateInstance(typeVue)!; // Vue réellement affichée : sans cela l'arbre visuel est vide et // le test passerait sans rien vérifier. var fenetre = new Window { Width = 420, Height = 800, Content = vue }; fenetre.Show(); Dispatcher.UIThread.RunJobs(); Control[] descendants = vue.GetVisualDescendants().OfType().ToArray(); Button[] boutonsRetour = descendants .OfType