Files
Sharepoint-Toolbox/.planning/phases/06-global-site-selection/06-05-PLAN.md
2026-04-07 09:57:15 +02:00

207 lines
9.6 KiB
Markdown

---
phase: 06-global-site-selection
plan: 05
type: execute
wave: 3
depends_on: [06-01, 06-02, 06-04]
files_modified:
- SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs
autonomous: true
requirements:
- SITE-01
- SITE-02
must_haves:
truths:
- "Unit tests verify GlobalSitesChangedMessage broadcasts when MainWindowViewModel global sites change"
- "Unit tests verify FeatureViewModelBase receives global sites and updates GlobalSites property"
- "Unit tests verify single-site tab VMs pre-fill SiteUrl from first global site"
- "Unit tests verify PermissionsViewModel pre-populates SelectedSites from global sites"
- "Unit tests verify local override prevents global sites from overwriting tab state"
- "Unit tests verify tenant switch clears global site selection"
- "All tests pass with dotnet test"
artifacts:
- path: "SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs"
provides: "Comprehensive unit tests for global site selection flow"
contains: "GlobalSiteSelectionTests"
key_links:
- from: "SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs"
to: "SharepointToolbox/ViewModels/MainWindowViewModel.cs"
via: "Tests broadcast and clear behavior"
pattern: "GlobalSelectedSites"
- from: "SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs"
to: "SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs"
via: "Tests single-site consumption and local override"
pattern: "OnGlobalSitesChanged"
---
<objective>
Create unit tests covering the full global site selection flow: message broadcast, base class reception, tab VM consumption, local override behavior, and tenant switch clearing.
Purpose: Verify the contracts established in plans 06-01 through 06-04 work correctly end-to-end without requiring a live SharePoint tenant.
Output: GlobalSiteSelectionTests.cs with passing tests covering all critical paths.
</objective>
<execution_context>
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/06-global-site-selection/06-CONTEXT.md
@.planning/phases/06-global-site-selection/06-01-SUMMARY.md
@.planning/phases/06-global-site-selection/06-02-SUMMARY.md
@.planning/phases/06-global-site-selection/06-04-SUMMARY.md
<interfaces>
<!-- From plan 06-01: Base class contract -->
```csharp
// FeatureViewModelBase
protected IReadOnlyList<SiteInfo> GlobalSites { get; private set; }
protected virtual void OnGlobalSitesChanged(IReadOnlyList<SiteInfo> sites) { }
// Registers for GlobalSitesChangedMessage in OnActivated()
```
<!-- From plan 06-02: MainWindowViewModel -->
```csharp
public ObservableCollection<SiteInfo> GlobalSelectedSites { get; }
public RelayCommand OpenGlobalSitePickerCommand { get; }
public string GlobalSitesSelectedLabel { get; }
// CollectionChanged on GlobalSelectedSites sends GlobalSitesChangedMessage
// OnSelectedProfileChanged clears GlobalSelectedSites
// ClearSessionAsync clears GlobalSelectedSites
```
<!-- From plan 06-04: Tab VM overrides -->
```csharp
// StorageViewModel (and Search, Duplicates, FolderStructure)
protected override void OnGlobalSitesChanged(IReadOnlyList<SiteInfo> sites)
{
if (_hasLocalSiteOverride) return;
SiteUrl = sites.Count > 0 ? sites[0].Url : string.Empty;
}
// PermissionsViewModel
protected override void OnGlobalSitesChanged(IReadOnlyList<SiteInfo> sites)
{
if (_hasLocalSiteOverride) return;
SelectedSites.Clear();
foreach (var site in sites) SelectedSites.Add(site);
}
```
<!-- Existing test patterns (from v1.0) -->
```csharp
// Tests use Moq for service interfaces, internal constructors for VMs
// InternalsVisibleTo is already configured
// WeakReferenceMessenger.Default for message sending in tests
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Create GlobalSiteSelectionTests with comprehensive test coverage</name>
<files>SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs</files>
<behavior>
- Test 1: GlobalSitesChangedMessage carries site list — send message, verify receiver gets the sites
- Test 2: FeatureViewModelBase updates GlobalSites on message receive — send message to a derived VM, check GlobalSites property
- Test 3: StorageViewModel pre-fills SiteUrl from first global site — send global sites message, verify SiteUrl equals first site URL
- Test 4: StorageViewModel local override prevents global update — set SiteUrl manually, then send global sites, verify SiteUrl unchanged
- Test 5: StorageViewModel clearing SiteUrl reverts to global — set local override, clear SiteUrl, verify it reverts to global site
- Test 6: PermissionsViewModel pre-populates SelectedSites from global sites — send global sites, verify SelectedSites matches
- Test 7: PermissionsViewModel local picker override prevents global update — mark local override, send global sites, verify SelectedSites unchanged
- Test 8: Tenant switch clears global sites on StorageViewModel — send global sites, then send TenantSwitchedMessage, verify SiteUrl cleared and override reset
- Test 9: TransferViewModel pre-fills SourceSiteUrl from first global site
- Test 10: MainWindowViewModel GlobalSitesSelectedLabel updates with count — add sites to GlobalSelectedSites, verify label text
</behavior>
<action>
Create `SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs` with the tests described above.
Use the existing test patterns from the project:
- Moq for `IStorageService`, `ISessionManager`, `IPermissionsService`, `ISiteListService`, `ILogger<FeatureViewModelBase>`
- Internal test constructors for ViewModels (already available via InternalsVisibleTo)
- `WeakReferenceMessenger.Default.Send(new GlobalSitesChangedMessage(...))` to simulate the toolbar broadcasting
Key implementation notes:
1. For tests that need to verify GlobalSites property on FeatureViewModelBase: Create a minimal concrete subclass in the test file:
```csharp
private class TestFeatureViewModel : FeatureViewModelBase
{
public TestFeatureViewModel(ILogger<FeatureViewModelBase> logger) : base(logger) { }
protected override Task RunOperationAsync(CancellationToken ct, IProgress<OperationProgress> progress)
=> Task.CompletedTask;
// Expose protected property for test assertions
public IReadOnlyList<SiteInfo> TestGlobalSites => GlobalSites;
}
```
2. For StorageViewModel tests: use the internal test constructor `StorageViewModel(IStorageService, ISessionManager, ILogger<FeatureViewModelBase>)`.
3. For PermissionsViewModel tests: use the internal test constructor `PermissionsViewModel(IPermissionsService, ISiteListService, ISessionManager, ILogger<FeatureViewModelBase>)`.
4. For TransferViewModel tests: use the production constructor with mocked dependencies. Check if TransferViewModel has an internal test constructor — if not, mock all constructor parameters.
5. For MainWindowViewModel label test: use the production constructor with mocked ProfileService, SessionManager, ILogger. Add SiteInfo items to GlobalSelectedSites and assert the label property.
6. Reset WeakReferenceMessenger.Default between tests to avoid cross-test contamination:
```csharp
public GlobalSiteSelectionTests()
{
WeakReferenceMessenger.Default.Reset();
}
```
7. Each test should be a `[Fact]` with a descriptive name following the pattern: `MethodOrScenario_Condition_ExpectedResult`.
Example test structure:
```csharp
[Fact]
public void OnGlobalSitesChanged_WithSites_PreFillsSiteUrlOnStorageTab()
{
var logger = Mock.Of<ILogger<FeatureViewModelBase>>();
var vm = new StorageViewModel(
Mock.Of<IStorageService>(),
Mock.Of<ISessionManager>(),
logger);
var sites = new List<SiteInfo>
{
new("https://contoso.sharepoint.com/sites/hr", "HR"),
new("https://contoso.sharepoint.com/sites/finance", "Finance")
};
WeakReferenceMessenger.Default.Send(new GlobalSitesChangedMessage(sites.AsReadOnly()));
Assert.Equal("https://contoso.sharepoint.com/sites/hr", vm.SiteUrl);
}
```
Write all 10 tests. Ensure every test has clear Arrange/Act/Assert sections.
</action>
<verify>
<automated>cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet test SharepointToolbox.Tests/SharepointToolbox.Tests.csproj --filter "FullyQualifiedName~GlobalSiteSelection" --verbosity normal 2>&1 | tail -20</automated>
</verify>
<done>All 10 tests in GlobalSiteSelectionTests pass. Tests cover message broadcast, base class reception, single-site pre-fill, multi-site pre-populate, local override, override reset, tenant switch clear, and label update.</done>
</task>
</tasks>
<verification>
- `dotnet test SharepointToolbox.Tests --filter "GlobalSiteSelection"` shows 10 passed, 0 failed
- `dotnet test SharepointToolbox.Tests` shows no regressions in existing tests
- Test file exists at SharepointToolbox.Tests/ViewModels/GlobalSiteSelectionTests.cs
- Tests cover both SITE-01 (global consumption) and SITE-02 (local override) requirements
</verification>
<success_criteria>
All 10 unit tests pass, validating the full global site selection contract: message creation, base class plumbing, tab VM consumption (multi-site and single-site), local override behavior, and tenant switch clearing. No regressions in existing test suite.
</success_criteria>
<output>
After completion, create `.planning/phases/06-global-site-selection/06-05-SUMMARY.md`
</output>