using ClaudeDo.Installer.Checks; using ClaudeDo.Installer.Core; using Vm = ClaudeDo.Installer.Pages.SystemCheckPage.SystemCheckPageViewModel; namespace ClaudeDo.Installer.Tests.Pages.SystemCheckPage; public sealed class SystemCheckPageViewModelTests { private static Vm CreateViewModel(Func factory) => new(new InstallContext(), factory); private static Func FactoryFor(params IEnvironmentCheck[] checks) => () => new EnvironmentCheckService(checks); [Fact] public async Task Entering_the_page_runs_checks_exactly_once() { var check = FakeEnvironmentCheck.Ok("a"); var vm = CreateViewModel(FactoryFor(check)); await vm.LoadAsync(); Assert.Equal(1, check.CallCount); Assert.True(vm.HasRun); Assert.Single(vm.Rows); } [Fact] public async Task Entering_the_page_a_second_time_does_not_run_checks_again() { var check = FakeEnvironmentCheck.Ok("a"); var vm = CreateViewModel(FactoryFor(check)); await vm.LoadAsync(); await vm.LoadAsync(); Assert.Equal(1, check.CallCount); } [Fact] public async Task Recheck_while_a_run_is_in_progress_does_not_start_a_second_run() { var gate = new TaskCompletionSource(); var slow = new FakeEnvironmentCheck("slow", CheckSeverity.Error, async (_, _) => { await gate.Task; return CheckResult.Ok("slow", CheckSeverity.Error, "checks.slow.title", "ok"); }); var factoryCalls = 0; var vm = CreateViewModel(() => { factoryCalls++; return new EnvironmentCheckService(new IEnvironmentCheck[] { slow }); }); var firstRun = vm.RunChecksCommand.ExecuteAsync(null); Assert.True(vm.IsRunning); await vm.RunChecksCommand.ExecuteAsync(null); // recheck while the first run is still in flight Assert.Equal(1, factoryCalls); Assert.Equal(1, slow.CallCount); gate.SetResult(); await firstRun; Assert.False(vm.IsRunning); } [Fact] public async Task Blocking_error_blocks_navigation_and_clears_after_a_clean_recheck() { var callNumber = 0; var vm = CreateViewModel(() => { callNumber++; IEnvironmentCheck check = callNumber == 1 ? FakeEnvironmentCheck.Fail("git", CheckSeverity.Error) : FakeEnvironmentCheck.Ok("git"); return new EnvironmentCheckService(new[] { check }); }); await vm.LoadAsync(); Assert.True(vm.HasBlockingError); Assert.True(vm.BlocksNavigation); await vm.RunChecksCommand.ExecuteAsync(null); Assert.False(vm.HasBlockingError); Assert.False(vm.BlocksNavigation); } [Fact] public async Task Only_warnings_does_not_block_navigation() { var warning = FakeEnvironmentCheck.Fail("gitIdentity", CheckSeverity.Warning); var vm = CreateViewModel(FactoryFor(warning)); await vm.LoadAsync(); Assert.False(vm.HasBlockingError); Assert.False(vm.BlocksNavigation); } [Fact] public async Task Only_unknown_results_do_not_block_navigation() { var unknown = FakeEnvironmentCheck.Unknown("claudeAuth", CheckSeverity.Error); var vm = CreateViewModel(FactoryFor(unknown)); await vm.LoadAsync(); Assert.False(vm.HasBlockingError); Assert.False(vm.BlocksNavigation); } [Fact] public async Task Summary_reports_all_ok() { var vm = CreateViewModel(FactoryFor(FakeEnvironmentCheck.Ok("git"))); await vm.LoadAsync(); Assert.Equal("Everything looks good.", vm.Summary); } [Fact] public async Task Summary_reports_warning_count() { var vm = CreateViewModel(FactoryFor( FakeEnvironmentCheck.Fail("gitIdentity", CheckSeverity.Warning), FakeEnvironmentCheck.Fail("ports", CheckSeverity.Warning))); await vm.LoadAsync(); Assert.Equal("2 warning(s) found.", vm.Summary); } [Fact] public async Task Summary_reports_blocking_errors_by_name() { var vm = CreateViewModel(FactoryFor( FakeEnvironmentCheck.Fail("git", CheckSeverity.Error), FakeEnvironmentCheck.Fail("writeAccess", CheckSeverity.Error))); await vm.LoadAsync(); Assert.Equal("2 problem(s) must be fixed: checks.git.title, checks.writeAccess.title", vm.Summary); } [Fact] public async Task Summary_reports_running_state_while_a_check_is_in_flight() { var gate = new TaskCompletionSource(); var slow = new FakeEnvironmentCheck("slow", CheckSeverity.Error, async (_, _) => { await gate.Task; return CheckResult.Ok("slow", CheckSeverity.Error, "checks.slow.title", "ok"); }); var vm = CreateViewModel(FactoryFor(slow)); var run = vm.RunChecksCommand.ExecuteAsync(null); Assert.True(vm.IsRunning); Assert.Equal("Checking your system…", vm.Summary); gate.SetResult(); await run; } }