Files
ClaudeDo/tests/ClaudeDo.Ui.Tests/IslandsShellViewModelShutdownTests.cs
T
mika kuns 1bdf20272d feat(ui): worker-menu Shutdown ends worker + app after confirm
Adds a Shutdown entry after the Worker menu's Restart/Update Claude CLI
items. Confirms via IDialogService.ConfirmAsync, then kills this
installation's ClaudeDo.Worker process(es) (shared kill loop, extracted
from RestartWorkerService) and force-closes the window through the same
_forceClose path MainWindow already uses for the Mission-Control close
confirm, so no second confirmation dialog shows.
2026-09-10 13:48:50 +02:00

65 lines
3.0 KiB
C#

using System;
using System.Threading.Tasks;
using ClaudeDo.Ui.Services;
using ClaudeDo.Ui.ViewModels;
using ClaudeDo.Ui.ViewModels.Conflicts;
using ClaudeDo.Ui.ViewModels.Modals;
namespace ClaudeDo.Ui.Tests;
// Covers the worker-menu "Shutdown" command: a confirm dialog gates the actual kill-worker +
// close-app action. ShutdownOperation is a test seam standing in for the real body, so these
// tests only assert the confirm gate, never a real process kill.
public class IslandsShellViewModelShutdownTests
{
[Fact]
public async Task Declined_DoesNotInvokeShutdownOperation()
{
var invoked = false;
var vm = new IslandsShellViewModel
{
Dialogs = new FakeDialogService(confirmResult: false),
ShutdownOperation = () => invoked = true,
};
await vm.ShutdownCommand.ExecuteAsync(null);
Assert.False(invoked);
}
[Fact]
public async Task Confirmed_InvokesShutdownOperation()
{
var invoked = false;
var vm = new IslandsShellViewModel
{
Dialogs = new FakeDialogService(confirmResult: true),
ShutdownOperation = () => invoked = true,
};
await vm.ShutdownCommand.ExecuteAsync(null);
Assert.True(invoked);
}
private sealed class FakeDialogService(bool confirmResult) : IDialogService
{
public Task<bool> ConfirmAsync(string message) => Task.FromResult(confirmResult);
public Task ShowAboutAsync(AboutModalViewModel vm) => throw new NotImplementedException();
public Task ShowWeeklyReportAsync(WeeklyReportModalViewModel vm) => throw new NotImplementedException();
public Task ShowUsageMonitorAsync(UsageMonitorModalViewModel vm) => throw new NotImplementedException();
public Task ShowSettingsAsync(SettingsModalViewModel vm) => throw new NotImplementedException();
public Task ShowListSettingsAsync(ListSettingsModalViewModel vm) => throw new NotImplementedException();
public Task ShowRepoImportAsync(RepoImportModalViewModel vm) => throw new NotImplementedException();
public Task ShowWorktreesOverviewAsync(WorktreesOverviewModalViewModel vm) => throw new NotImplementedException();
public Task<IReadOnlyList<string>?> ShowMergeHelperSelectionAsync(MergeHelperSelectionModalViewModel vm) => throw new NotImplementedException();
public Task ShowWorkerConnectionAsync(WorkerConnectionModalViewModel vm) => throw new NotImplementedException();
public Task ShowConflictResolverAsync(ConflictResolverViewModel vm) => throw new NotImplementedException();
public Task ShowLogVisualizerAsync(LogVisualizerViewModel vm) => throw new NotImplementedException();
public Task ShowErrorAsync(string message) => Task.CompletedTask;
public void ShowMissionControl(MissionControlViewModel vm) => throw new NotImplementedException();
public void ShowCheatSheets(CheatSheetsViewModel vm) => throw new NotImplementedException();
}
}