using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Headless;
using Avalonia.Threading;
using Avalonia.VisualTree;
using Omika.App.Local.Abstractions;
using Omika.App.Local.Models;
using Omika.App.Navigation;
using Omika.App.Services;
using Omika.App.ViewModels;
using Omika.App.Views;
using Omika.Core.Contracts.Documents;
using Omika.Core.Contracts.Mobile.Sync;
using Xunit;
namespace Omika.Tests.Mobile;
///
/// Écran de composition d'un courriel en MESSAGERIE EXTERNE : le choix de
/// configuration SMTP disparaît (l'envoi ne passe pas par Omika), une explication
/// le remplace, et le panneau « Le courriel a-t-il été envoyé ? » (Oui / Non)
/// apparaît après le retour de l'application de messagerie.
///
///
/// Session headless partagée au niveau du processus (localisateur Avalonia global) :
/// la classe rejoint la collection « ApplicationRuntimeContext ».
///
[Collection("ApplicationRuntimeContext")]
public sealed class NouveauEmailViewExterneTests : IDisposable
{
private readonly HeadlessUnitTestSession _session =
HeadlessUnitTestSession.StartNew(typeof(LayoutTestAppBuilder));
public void Dispose() => _session.Dispose();
private void Executer(Action scenario)
=> _session.Dispatch(
() =>
{
scenario();
return true;
},
CancellationToken.None).GetAwaiter().GetResult();
///
/// Messagerie externe : la configuration SMTP est MASQUÉE et l'explication
/// affichée (l'utilisateur doit comprendre que l'envoi se fera ailleurs).
///
[Fact]
public void MessagerieExterne_MasqueLaConfigurationSmtpEtExplique()
=> Executer(() =>
{
NouveauEmailView vue = Ouvrir(messagerieExterne: true);
Window fenetre = Fenetre(vue);
try
{
ComboBox? configuration = vue.FindControl("ConfigurationSmtp");
Assert.NotNull(configuration);
Assert.False(
configuration!.IsEffectivelyVisible,
"La configuration SMTP ne doit pas être proposée en messagerie externe.");
TextBlock explication = vue.GetVisualDescendants()
.OfType()
.Single(t => t.Text?.StartsWith("Messagerie externe", StringComparison.Ordinal) == true);
Assert.True(explication.IsEffectivelyVisible, "L'explication de la messagerie externe n'est pas affichée.");
}
finally
{
fenetre.Close();
}
});
/// Messagerie interne (Back-Office) : rien ne change, la configuration reste proposée.
[Fact]
public void MessagerieInterne_GardeLaConfigurationSmtp()
=> Executer(() =>
{
NouveauEmailView vue = Ouvrir(messagerieExterne: false);
Window fenetre = Fenetre(vue);
try
{
ComboBox? configuration = vue.FindControl("ConfigurationSmtp");
Assert.NotNull(configuration);
Assert.True(configuration!.IsEffectivelyVisible);
TextBlock? explication = vue.GetVisualDescendants()
.OfType()
.FirstOrDefault(t => t.Text?.StartsWith("Messagerie externe", StringComparison.Ordinal) == true);
Assert.True(explication is null || !explication.IsEffectivelyVisible);
}
finally
{
fenetre.Close();
}
});
///
/// La question n'est PAS affichée avant l'envoi, puis apparaît avec ses deux
/// réponses « Oui » (enregistre comme envoyé) et « Non » (conserve en brouillon).
///
[Fact]
public void QuestionEnvoiExterne_SafficheApresLeRetourAvecOuiEtNon()
=> Executer(() =>
{
NouveauEmailView vue = Ouvrir(messagerieExterne: true);
Window fenetre = Fenetre(vue);
try
{
var modele = (NouveauEmailViewModel)vue.DataContext!;
Button oui = Bouton(vue, "Oui");
Button non = Bouton(vue, "Non");
Assert.False(
oui.IsEffectivelyVisible,
"La question ne doit pas apparaître avant l'ouverture de la messagerie.");
modele.AfficherQuestionEnvoiExterne = true;
Dispatcher.UIThread.RunJobs();
Assert.True(oui.IsEffectivelyVisible, "Le bouton « Oui » n'est pas affiché.");
Assert.True(non.IsEffectivelyVisible, "Le bouton « Non » n'est pas affiché.");
Assert.NotNull(oui.Command);
Assert.NotNull(non.Command);
Assert.NotSame(oui.Command, non.Command);
}
finally
{
fenetre.Close();
}
});
// =====================================================================
// Aides
// =====================================================================
private static Button Bouton(Control vue, string libelle)
=> vue.GetVisualDescendants()
.OfType