Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Deux pièges de mesure sont évités ici :
|
||||
/// <list type="bullet">
|
||||
/// <item>la surcharge <c>Dispatch(Action)</c> 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 ;</item>
|
||||
/// <item>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.</item>
|
||||
/// </list>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[Collection("ApplicationRuntimeContext")]
|
||||
public sealed class DetailViewBackHeaderTests : IDisposable
|
||||
{
|
||||
private readonly HeadlessUnitTestSession _session;
|
||||
|
||||
public DetailViewBackHeaderTests()
|
||||
=> _session = HeadlessUnitTestSession.StartNew(typeof(LayoutTestAppBuilder));
|
||||
|
||||
public void Dispose() => _session.Dispose();
|
||||
|
||||
/// <summary>Toutes les pages de détail exposant un bouton retour.</summary>
|
||||
public static TheoryData<Type> 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<Control>().ToArray();
|
||||
|
||||
Button[] boutonsRetour = descendants
|
||||
.OfType<Button>()
|
||||
.Where(b => (b.Content as string)?.Contains("Retour", StringComparison.Ordinal) == true)
|
||||
.ToArray();
|
||||
|
||||
Assert.NotEmpty(boutonsRetour);
|
||||
|
||||
// Au moins un bouton retour est FIXE : aucun ScrollViewer au-dessus
|
||||
// de lui, il ne défile donc pas avec le contenu.
|
||||
Assert.Contains(
|
||||
boutonsRetour,
|
||||
b => !b.GetVisualAncestors().Any(a => a is ScrollViewer));
|
||||
|
||||
// Le contenu de la page, lui, reste défilable.
|
||||
Assert.Contains(descendants, c => c is ScrollViewer);
|
||||
|
||||
fenetre.Close();
|
||||
return true;
|
||||
},
|
||||
CancellationToken.None).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user