207 lines
9.6 KiB
Markdown
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>
|