Add more `dotnetup walkthrough` tests
- Dominant language
- C#
- Stars
- 3.2k
- Forks
- 1.3k
- PR merge metrics
- PR metrics pending
Description
# Enable E2E testing of WalkthroughCommand without real I/O or downloads
## Problem
`WalkthroughCommand` cannot be unit/integration tested today because it has hard dependencies on:
1. **`InstallerOrchestratorSingleton`** — a true singleton with a private constructor that performs real downloads and file extraction. No interface exists.
2. **`Spectre.Console.AnsiConsole` (static)** — all output and interactive prompts (`SelectionPrompt`, `MarkupLine`, `Live`) go through the static `AnsiConsole`. `InteractiveOptionSelector` reads `Console.ReadKey` directly.
3. **File system / config** — `DotnetupConfig.EnsurePathPreference` reads/writes a real config file. `GetInstalledAdminInstalls` reads real disk paths via `HostFxrWrapper`.
This blocks testing:
- Output ordering (banner → channel prompt → path preference → install → config → "Setup complete!")
- Admin migration prompt suppression when no admin installs exist
- Deferred install flow when admin installs are present
- Channel prompt default selection with redirected input
## Proposed Changes
### 1. Extract `IInstallerOrchestrator` from `InstallerOrchestratorSingleton`
**Effort: Medium** — this is the critical blocker.
```csharp
internal interface IInstallerOrchestrator
{
InstallResult Install(DotnetInstallRequest request, bool noProgress = false);
IReadOnlyList InstallMany(IEnumerable requests, IProgressReporter reporter);
// Static helpers like PredownloadToCacheAsync can remain static or move to a separate service.
}
```
- `InstallerOrchestratorSingleton` implements `IInstallerOrchestrator`.
- Inject via constructor into `InstallExecutor`, `InstallWorkflow`, command classes.
- Tests provide a `MockInstallerOrchestrator` that returns fake `InstallResult` values without downloading.
### 2. Create `MockDotnetInstallManager`
**Effort: Small** — `IDotnetInstallManager` already exists.
```csharp
internal class MockDotnetInstallManager : IDotnetInstallManager
{
public List AdminInstalls { get; set; } = [];
public string DefaultInstallPath { get; set; } = "/tmp/dotnet";
// ... implement all interface members with configurable return values
}
```
This enables testing:
- `GetInstalledAdminInstalls()` returns empty → admin migration prompt is skipped
- `GetInstalledAdminInstalls()` returns items → admin migration prompt fires
- `GetConfiguredInstallType()` returns specific install types
### 3. Thread `IAnsiConsole` through display methods
**Effort: Medium** — many `SpectreAnsiConsole.*` call sites.
Spectre.Console supports `IAnsiConsole` injection. The pattern already exists in `DotnetBotBannerTests`:
```csharp
var writer = new StringWriter();
var console = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(writer),
Ansi = AnsiSupport.No,
});
```
Changes:
- Add `IAnsiConsole` parameter to `WalkthroughCommand`, `InstallExecutor` display methods, `InstallWalkthrough`, `InteractiveOptionSelector`.
- Default to `AnsiConsole.Console` in production.
- Tests pass a `TestConsole` or `AnsiConsole.Create(...)` with a `StringWriter` to capture output.
- For input simulation: `Console.IsInputRedirected` already causes fallback to defaults in `InteractiveOptionSelector` and `PromptChannel`. Tests redirect stdin.
### 4. Write walkthrough tests
**Effort: Small** once 1–3 are done.
```csharp
public class WalkthroughCommandTests
{
[Fact]
public void Walkthrough_OutputAppearsInCorrectOrder()
{
// Verify: banner → channel → path preference → install → config → "Setup complete!"
}
[Fact]
public void Walkthrough_NoAdminInstalls_SkipsAdminMigrationPrompt()
{
// MockDotnetInstallManager returns empty admin installs
// Assert output does not contain migration prompt text
}
[Fact]
public void Walkthrough_WithAdminInstalls_ShowsMigrationPrompt()
{
// MockDotnetInstallManager returns admin installs
// Assert output contains migration prompt and deferred install messages
}
[Fact]
public void Walkthrough_DotnetupDotnetMode_SkipsAdminMigration()
{
// PathPreference.DotnetupDotnet should never trigger admin migration
}
}
```
## Implementation Order
| Step | What | Blocks |
|------|------|--------|
| 1 | `MockDotnetInstallManager` | Nothing — `IDotnetInstallManager` exists |
| 2 | `IInstallerOrchestrator` extraction | Walkthrough tests (can't avoid real downloads without it) |
| 3 | `IAnsiConsole` threading | Output-order assertions (can use process-level capture as interim) |
| 4 | Walkthrough tests | Steps 1–2 minimum; step 3 for output assertions |
## Interim: Process-Level E2E
Before the full refactoring, we can test *some* ordering via the existing `DotnetupTestUtilities.RunDotnetupProcess` pattern with `--interactive false --no-progress` and stdout capture. This doesn't test interactive prompts but verifies the non-interactive flow and output structure.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.