test: add app-level smoke baselines and mobile CI test jobs

Co-authored-by: Velik <hongochai10@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-02-23 13:15:02 +00:00
parent 969aa81ea2
commit d808f1d4e1
12 changed files with 432 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
using AppClientBase.Services;
using AppClientBase.ViewModels;
using FluentAssertions;
using Xunit;
namespace AppClientBase.UnitTests.ViewModels;
/// <summary>
/// EN: Unit tests for main view model behavior.
/// VI: Unit tests cho hành vi của main view model.
/// </summary>
public class MainViewModelTests
{
[Fact]
public void Constructor_ShouldSetDefaultTitleAndWelcomeMessage()
{
// Arrange
var navigationService = new FakeNavigationService();
var settingsService = new FakeSettingsService();
// Act
var viewModel = new MainViewModel(navigationService, settingsService);
// Assert
viewModel.Title.Should().Be("Home");
viewModel.WelcomeMessage.Should().Be("Welcome to AppClientBase!");
viewModel.ClickCount.Should().Be(0);
viewModel.ButtonText.Should().Be("Click me");
}
[Fact]
public void IncrementCounterCommand_ShouldIncreaseCountAndPersistSetting()
{
// Arrange
var navigationService = new FakeNavigationService();
var settingsService = new FakeSettingsService();
var viewModel = new MainViewModel(navigationService, settingsService);
// Act
viewModel.IncrementCounterCommand.Execute(null);
viewModel.IncrementCounterCommand.Execute(null);
// Assert
viewModel.ClickCount.Should().Be(2);
viewModel.ButtonText.Should().Be("Clicked 2 times");
settingsService.Get("ClickCount", 0).Should().Be(2);
}
private sealed class FakeNavigationService : INavigationService
{
public Task GoToAsync(string route, IDictionary<string, object>? parameters = null) => Task.CompletedTask;
public Task GoBackAsync() => Task.CompletedTask;
}
private sealed class FakeSettingsService : ISettingsService
{
private readonly Dictionary<string, object?> _store = new(StringComparer.Ordinal);
public T Get<T>(string key, T defaultValue)
{
if (_store.TryGetValue(key, out var value) && value is T typed)
{
return typed;
}
return defaultValue;
}
public void Set<T>(string key, T value)
{
_store[key] = value;
}
public bool Contains(string key) => _store.ContainsKey(key);
public void Remove(string key) => _store.Remove(key);
public void Clear() => _store.Clear();
}
}