Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user