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:
@@ -0,0 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>AppClientBase.UnitTests</AssemblyName>
|
||||
<RootNamespace>AppClientBase.UnitTests</RootNamespace>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EN: Test framework dependencies / VI: Phụ thuộc framework test -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
<!-- EN: Source generator package used by included view models.
|
||||
VI: Gói source generator dùng cho view model được include. -->
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EN: Reuse app source files that are platform-neutral.
|
||||
VI: Tái sử dụng source file ứng dụng không phụ thuộc nền tảng. -->
|
||||
<Compile Include="..\..\ViewModels\BaseViewModel.cs" Link="ViewModels\BaseViewModel.cs" />
|
||||
<Compile Include="..\..\ViewModels\MainViewModel.cs" Link="ViewModels\MainViewModel.cs" />
|
||||
<Compile Include="..\..\Services\INavigationService.cs" Link="Services\INavigationService.cs" />
|
||||
<Compile Include="..\..\Services\ISettingsService.cs" Link="Services\ISettingsService.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
25
apps/app-client-base-swift/smoke-tests/Package.swift
Normal file
25
apps/app-client-base-swift/smoke-tests/Package.swift
Normal file
@@ -0,0 +1,25 @@
|
||||
// swift-tools-version: 5.9
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "AppClientBaseSwiftSmokeTests",
|
||||
platforms: [
|
||||
.macOS(.v14),
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "AppClientBaseSwiftSmoke",
|
||||
targets: ["AppClientBaseSwiftSmoke"]
|
||||
),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "AppClientBaseSwiftSmoke"
|
||||
),
|
||||
.testTarget(
|
||||
name: "AppClientBaseSwiftSmokeTests",
|
||||
dependencies: ["AppClientBaseSwiftSmoke"]
|
||||
),
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
import Foundation
|
||||
|
||||
/// EN: Localization resource smoke-test helper.
|
||||
/// VI: Helper smoke-test cho tài nguyên localization.
|
||||
public enum LocalizationManifest {
|
||||
/// EN: Relative path from package root to app resources.
|
||||
/// VI: Đường dẫn tương đối từ package root đến tài nguyên ứng dụng.
|
||||
public static let resourcesRelativePath = "../AppClientBaseSwift/AppClientBaseSwift/Resources"
|
||||
|
||||
/// EN: Build absolute path to Localizable.strings for a locale.
|
||||
/// VI: Tạo đường dẫn tuyệt đối tới Localizable.strings theo locale.
|
||||
public static func localizableFilePath(
|
||||
for locale: String,
|
||||
currentDirectoryPath: String = FileManager.default.currentDirectoryPath
|
||||
) -> String {
|
||||
let localeFolder = "\(locale).lproj"
|
||||
return URL(fileURLWithPath: currentDirectoryPath)
|
||||
.appendingPathComponent(resourcesRelativePath)
|
||||
.appendingPathComponent(localeFolder)
|
||||
.appendingPathComponent("Localizable.strings")
|
||||
.path
|
||||
}
|
||||
|
||||
/// EN: Check if a locale file exists.
|
||||
/// VI: Kiểm tra file locale có tồn tại hay không.
|
||||
public static func hasLocale(_ locale: String, fileManager: FileManager = .default) -> Bool {
|
||||
fileManager.fileExists(atPath: localizableFilePath(for: locale))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import XCTest
|
||||
@testable import AppClientBaseSwiftSmoke
|
||||
|
||||
/// EN: Smoke tests for localization assets.
|
||||
/// VI: Smoke tests cho tài nguyên bản địa hóa.
|
||||
final class LocalizationManifestTests: XCTestCase {
|
||||
func testEnglishLocalizationFileShouldExist() {
|
||||
XCTAssertTrue(LocalizationManifest.hasLocale("en"))
|
||||
}
|
||||
|
||||
func testVietnameseLocalizationFileShouldExist() {
|
||||
XCTAssertTrue(LocalizationManifest.hasLocale("vi"))
|
||||
}
|
||||
|
||||
func testUnknownLocaleShouldNotExist() {
|
||||
XCTAssertFalse(LocalizationManifest.hasLocale("zz"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using FluentAssertions;
|
||||
using WebClientBase.Shared;
|
||||
using Xunit;
|
||||
|
||||
namespace WebClientBase.SmokeTests;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Smoke tests for shared API response contracts.
|
||||
/// VI: Smoke tests cho contract API response dùng chung.
|
||||
/// </summary>
|
||||
public class ApiResponseTests
|
||||
{
|
||||
[Fact]
|
||||
public void Ok_ShouldReturnSuccessWithPayload()
|
||||
{
|
||||
// Act
|
||||
var response = ApiResponse<string>.Ok("healthy");
|
||||
|
||||
// Assert
|
||||
response.Success.Should().BeTrue();
|
||||
response.Data.Should().Be("healthy");
|
||||
response.Error.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fail_ShouldReturnErrorWithoutPayload()
|
||||
{
|
||||
// Act
|
||||
var response = ApiResponse<string>.Fail("bad-request");
|
||||
|
||||
// Assert
|
||||
response.Success.Should().BeFalse();
|
||||
response.Data.Should().BeNull();
|
||||
response.Error.Should().Be("bad-request");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>WebClientBase.SmokeTests</AssemblyName>
|
||||
<RootNamespace>WebClientBase.SmokeTests</RootNamespace>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EN: Test framework dependencies / VI: Phụ thuộc framework test -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\WebClientBase.Shared\WebClientBase.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,44 @@
|
||||
using EggymonLandingPage.Shared;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace EggymonLandingPage.SmokeTests;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Smoke tests for landing page shared API response model.
|
||||
/// VI: Smoke tests cho model API response dùng chung của landing page.
|
||||
/// </summary>
|
||||
public class ApiResponseTests
|
||||
{
|
||||
[Fact]
|
||||
public void ApiResponse_ShouldStoreSuccessPayload()
|
||||
{
|
||||
// Act
|
||||
var response = new ApiResponse<string>
|
||||
{
|
||||
Success = true,
|
||||
Data = "ok",
|
||||
};
|
||||
|
||||
// Assert
|
||||
response.Success.Should().BeTrue();
|
||||
response.Data.Should().Be("ok");
|
||||
response.Error.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApiResponse_ShouldStoreErrorMessage()
|
||||
{
|
||||
// Act
|
||||
var response = new ApiResponse<object>
|
||||
{
|
||||
Success = false,
|
||||
Error = "invalid-state",
|
||||
};
|
||||
|
||||
// Assert
|
||||
response.Success.Should().BeFalse();
|
||||
response.Data.Should().BeNull();
|
||||
response.Error.Should().Be("invalid-state");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>EggymonLandingPage.SmokeTests</AssemblyName>
|
||||
<RootNamespace>EggymonLandingPage.SmokeTests</RootNamespace>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EN: Test framework dependencies / VI: Phụ thuộc framework test -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\EggymonLandingPage.Shared\EggymonLandingPage.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,36 @@
|
||||
using FluentAssertions;
|
||||
using WebClientTpos.Shared;
|
||||
using Xunit;
|
||||
|
||||
namespace WebClientTpos.SmokeTests;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Smoke tests for TPOS shared API response helpers.
|
||||
/// VI: Smoke tests cho helper API response dùng chung của TPOS.
|
||||
/// </summary>
|
||||
public class ApiResponseTests
|
||||
{
|
||||
[Fact]
|
||||
public void Ok_ShouldReturnSuccessfulResponse()
|
||||
{
|
||||
// Act
|
||||
var response = ApiResponse<int>.Ok(200);
|
||||
|
||||
// Assert
|
||||
response.Success.Should().BeTrue();
|
||||
response.Data.Should().Be(200);
|
||||
response.Error.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fail_ShouldReturnFailedResponse()
|
||||
{
|
||||
// Act
|
||||
var response = ApiResponse.Fail("forbidden");
|
||||
|
||||
// Assert
|
||||
response.Success.Should().BeFalse();
|
||||
response.Data.Should().BeNull();
|
||||
response.Error.Should().Be("forbidden");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>WebClientTpos.SmokeTests</AssemblyName>
|
||||
<RootNamespace>WebClientTpos.SmokeTests</RootNamespace>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EN: Test framework dependencies / VI: Phụ thuộc framework test -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\WebClientTpos.Shared\WebClientTpos.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user