300 lines
9.7 KiB
C#
300 lines
9.7 KiB
C#
using Omika.App.Local.Abstractions;
|
|
using Omika.App.Local.Models;
|
|
using Omika.App.Navigation;
|
|
using Omika.App.ViewModels;
|
|
|
|
namespace Omika.Tests.Mobile.Local;
|
|
|
|
/// <summary>
|
|
/// Tests du ViewModel Détail Contact (lecture seule) : chargement local,
|
|
/// coordonnées disponibles, actions téléphone / email via des fakes plateforme
|
|
/// et retour vers la liste des contacts de l'intervention.
|
|
/// </summary>
|
|
public class ContactDetailViewModelTests
|
|
{
|
|
private sealed class FakeContactsService : IInterventionContactsService
|
|
{
|
|
public InterventionContact? ContactToReturn { get; set; }
|
|
public bool ThrowOnLoad { get; set; }
|
|
|
|
public Task<IReadOnlyList<InterventionContact>> GetContactsForInterventionAsync(
|
|
Guid interventionGuid, CancellationToken ct = default)
|
|
=> Task.FromResult<IReadOnlyList<InterventionContact>>([]);
|
|
|
|
public Task<InterventionContact?> GetContactByIdAsync(Guid contactGuid, CancellationToken ct = default)
|
|
{
|
|
if (ThrowOnLoad)
|
|
{
|
|
throw new InvalidOperationException("Erreur de chargement");
|
|
}
|
|
return Task.FromResult(ContactToReturn);
|
|
}
|
|
|
|
public Task<IReadOnlyList<InterventionContact>> GetContactsDisponiblesAsync(Guid interventionGuid, CancellationToken ct = default)
|
|
=> Task.FromResult<IReadOnlyList<InterventionContact>>([]);
|
|
}
|
|
|
|
private sealed class FakePhoneLauncher : IPhoneLauncher
|
|
{
|
|
public int DialCalls { get; private set; }
|
|
public string? LastNumber { get; private set; }
|
|
public bool DialResult { get; set; } = true;
|
|
|
|
public Task<bool> DialAsync(string phoneNumber)
|
|
{
|
|
DialCalls++;
|
|
LastNumber = phoneNumber;
|
|
return Task.FromResult(DialResult);
|
|
}
|
|
}
|
|
|
|
private sealed class FakeEmailLauncher : IEmailLauncher
|
|
{
|
|
public int ComposeCalls { get; private set; }
|
|
public string? LastEmail { get; private set; }
|
|
public bool ComposeResult { get; set; } = true;
|
|
|
|
public Task<bool> ComposeAsync(string email)
|
|
{
|
|
ComposeCalls++;
|
|
LastEmail = email;
|
|
return Task.FromResult(ComposeResult);
|
|
}
|
|
}
|
|
|
|
private static InterventionContact CreateContact(
|
|
Guid id,
|
|
string? mobile = null,
|
|
string? phone = null,
|
|
string? email = null)
|
|
=> new()
|
|
{
|
|
ContactGuid = id,
|
|
DisplayName = "Alice Dupont",
|
|
Mobile = mobile,
|
|
Phone = phone,
|
|
Email = email
|
|
};
|
|
|
|
private readonly FakeContactsService _service = new();
|
|
private readonly FakePhoneLauncher _phoneLauncher = new();
|
|
private readonly FakeEmailLauncher _emailLauncher = new();
|
|
private readonly NavigationService _navigation = new();
|
|
private readonly ContactDetailViewModel _viewModel;
|
|
|
|
public ContactDetailViewModelTests()
|
|
{
|
|
_viewModel = new ContactDetailViewModel(_service, _phoneLauncher, _emailLauncher, _navigation);
|
|
}
|
|
|
|
private static DetailNavigation Nav(Guid interventionId, Guid contactId)
|
|
=> new(contactId, new NavigationContext(AppPage.InterventionContacts, interventionId));
|
|
|
|
|
|
[Fact]
|
|
public async Task Load_ChargeLeContact()
|
|
{
|
|
// Arrange
|
|
Guid interventionId = Guid.NewGuid();
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, mobile: "0600000000", email: "alice@test.fr");
|
|
|
|
// Act
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(interventionId, contactId));
|
|
|
|
// Assert
|
|
Assert.False(_viewModel.IsLoading);
|
|
Assert.Null(_viewModel.ErrorMessage);
|
|
Assert.NotNull(_viewModel.Contact);
|
|
Assert.Equal(contactId, _viewModel.ContactGuid);
|
|
Assert.True(_viewModel.HasPhone);
|
|
Assert.True(_viewModel.HasEmail);
|
|
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Load_ContactIntrouvable_MessageErreur()
|
|
{
|
|
// Arrange
|
|
_service.ContactToReturn = null;
|
|
|
|
// Act
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), Guid.NewGuid()));
|
|
|
|
// Assert
|
|
Assert.False(_viewModel.IsLoading);
|
|
Assert.NotNull(_viewModel.ErrorMessage);
|
|
Assert.Null(_viewModel.Contact);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Load_Erreur_MessageAffiché()
|
|
{
|
|
// Arrange
|
|
_service.ThrowOnLoad = true;
|
|
|
|
// Act
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), Guid.NewGuid()));
|
|
|
|
// Assert
|
|
Assert.False(_viewModel.IsLoading);
|
|
Assert.NotNull(_viewModel.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Call_NumeroDisponible_AppelleLeLauncher()
|
|
{
|
|
// Arrange
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, mobile: "0600000000");
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), contactId));
|
|
|
|
// Act
|
|
await _viewModel.CallCommand.ExecuteAsync(null);
|
|
|
|
// Assert
|
|
Assert.Equal(1, _phoneLauncher.DialCalls);
|
|
Assert.Equal("0600000000", _phoneLauncher.LastNumber);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Call_SansNumero_NeAppellePas()
|
|
{
|
|
// Arrange
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, email: "alice@test.fr");
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), contactId));
|
|
|
|
// Act
|
|
await _viewModel.CallCommand.ExecuteAsync(null);
|
|
|
|
// Assert
|
|
Assert.Equal(0, _phoneLauncher.DialCalls);
|
|
Assert.False(_viewModel.HasPhone);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Call_ContactNull_NeAppellePas()
|
|
{
|
|
// Act
|
|
await _viewModel.CallCommand.ExecuteAsync(null);
|
|
|
|
// Assert
|
|
Assert.Equal(0, _phoneLauncher.DialCalls);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Call_LauncherRetourneFalse_MessageErreur()
|
|
{
|
|
// Arrange
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, mobile: "0600000000");
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), contactId));
|
|
_phoneLauncher.DialResult = false;
|
|
|
|
// Act
|
|
await _viewModel.CallCommand.ExecuteAsync(null);
|
|
|
|
// Assert : le résultat false est remonté à l'utilisateur.
|
|
Assert.Equal(1, _phoneLauncher.DialCalls);
|
|
Assert.Equal("Aucune application téléphonique disponible.", _viewModel.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Email_Disponible_AppelleLeLauncher()
|
|
{
|
|
// Arrange
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, email: "alice@test.fr");
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), contactId));
|
|
|
|
// Act
|
|
await _viewModel.EmailCommand.ExecuteAsync(null);
|
|
|
|
// Assert
|
|
Assert.Equal(1, _emailLauncher.ComposeCalls);
|
|
Assert.Equal("alice@test.fr", _emailLauncher.LastEmail);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Email_SansAdresse_NeAppellePas()
|
|
{
|
|
// Arrange
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, mobile: "0600000000");
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), contactId));
|
|
|
|
// Act
|
|
await _viewModel.EmailCommand.ExecuteAsync(null);
|
|
|
|
// Assert
|
|
Assert.Equal(0, _emailLauncher.ComposeCalls);
|
|
Assert.False(_viewModel.HasEmail);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Email_ContactNull_NeAppellePas()
|
|
{
|
|
// Act
|
|
await _viewModel.EmailCommand.ExecuteAsync(null);
|
|
|
|
// Assert
|
|
Assert.Equal(0, _emailLauncher.ComposeCalls);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Email_LauncherRetourneFalse_MessageErreur()
|
|
{
|
|
// Arrange
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, email: "alice@test.fr");
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), contactId));
|
|
_emailLauncher.ComposeResult = false;
|
|
|
|
// Act
|
|
await _viewModel.EmailCommand.ExecuteAsync(null);
|
|
|
|
// Assert : le résultat false est remonté à l'utilisateur.
|
|
Assert.Equal(1, _emailLauncher.ComposeCalls);
|
|
Assert.Equal("Aucune application de messagerie disponible.", _viewModel.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Email_LauncherRetourneTrue_AucunMessage()
|
|
{
|
|
// Arrange
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId, email: "alice@test.fr");
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(Guid.NewGuid(), contactId));
|
|
|
|
// Act
|
|
await _viewModel.EmailCommand.ExecuteAsync(null);
|
|
|
|
// Assert : succès → aucun message d'erreur.
|
|
Assert.Equal(1, _emailLauncher.ComposeCalls);
|
|
Assert.Null(_viewModel.ErrorMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Back_RetourneALaListeDesContacts()
|
|
{
|
|
// Arrange
|
|
Guid interventionId = Guid.NewGuid();
|
|
Guid contactId = Guid.NewGuid();
|
|
_service.ContactToReturn = CreateContact(contactId);
|
|
|
|
// Construit l'historique de navigation : InterventionContacts -> ContactDetail.
|
|
_navigation.NavigateTo(AppPage.InterventionContacts, interventionId);
|
|
_navigation.NavigateTo(AppPage.ContactDetail, Nav(interventionId, contactId));
|
|
|
|
await _viewModel.LoadCommand.ExecuteAsync(Nav(interventionId, contactId));
|
|
|
|
// Act
|
|
_viewModel.BackCommand.Execute(null);
|
|
|
|
// Assert : retour vers la page précédente (liste des contacts de l'intervention).
|
|
Assert.Equal(AppPage.InterventionContacts, _navigation.CurrentPage);
|
|
Assert.Equal(interventionId, _navigation.CurrentParameter);
|
|
}
|
|
}
|