Cover the mixed-keychain regroup refusal headlessly

The two-keychain branch of VaultViewModel.RegroupChosenHosts had no test:
7.6a's manual walk was the only thing asserting that a mixed set gets the
sentence instead of the picker. A ShellFlowTests case now ticks a host in
each of two vaults, reads the refusal off the status line, and shows the
same command opening the picker once the set is one keychain's again.
Check 7.6a cites the test and keeps only the popup wiring for the eye.
This commit is contained in:
2026-08-08 22:19:46 +02:00
parent d32f5609e3
commit 009b35e069
2 changed files with 60 additions and 4 deletions
+6 -4
View File
@@ -984,10 +984,12 @@ across that line would leave everyone else in the shared vault seeing a machine
**Failure means:** the set's write is `ChangingTheGroupOfTheChosenHosts_FilesThemAllAtOnce` again — one **Failure means:** the set's write is `ChangingTheGroupOfTheChosenHosts_FilesThemAllAtOnce` again — one
command reads the whole set, so "filed one of three" has no half-gesture to hide in the way the old drag's command reads the whole set, so "filed one of three" has no half-gesture to hide in the way the old drag's
payload did. The refusal, though, is asserted by **nothing automated at all**: `VaultViewModel.RegroupChosenHosts` payload did. The refusal is covered headlessly too:
counts the distinct vaults and no test raises it, so this check is the only thing between that sentence and `RegroupingHostsChosenAcrossTwoKeychains_IsRefusedBeforeThePickerOpens` ticks a host in each of two
silence. A panel that does open over a mixed set is the worse half — it would offer one keychain's groups keychains and asserts no picker opens and the sentence is on the status line. What is left for the eye is
for another keychain's machines, which is the half-filed set the refusal exists to prevent. 7.9's wiring, as in 7.6 — and a panel that does open over a mixed set is the worse half: it would offer one
keychain's groups for another keychain's machines, which is the half-filed set the refusal exists to
prevent.
### 7.7 A click still selects, and a double click still connects ### 7.7 A click still selects, and a double click still connects
@@ -5845,6 +5845,60 @@ public sealed class ShellFlowTests : IAsyncLifetime
Host(vault, "staging").Host.GroupId.ShouldBeNull("it was never ticked"); Host(vault, "staging").Host.GroupId.ShouldBeNull("it was never ticked");
} }
/// <remarks>
/// The other refusal at the same door, and the one that needs two keychains to raise: a group is an
/// item of one vault, so filing a mixed set under it would leave everyone else in the shared vault
/// seeing a machine filed under nothing. Checked when the picker is asked for and over the whole set —
/// see <see cref="VaultViewModel.RegroupChosenHosts"/> — rather than once per host mid-write, which is
/// why no panel opens at all and the status line's sentence has to carry the whole explanation.
/// </remarks>
[Fact]
public async Task RegroupingHostsChosenAcrossTwoKeychains_IsRefusedBeforeThePickerOpens()
{
await UnlockedAsync();
var vaults = shell.Vaults;
await vaults.LoadAsync(Token);
vaults.NewVaultCommand.Execute(null);
vaults.NewVaultName = "Platform secrets";
await vaults.CreateVaultCommand.ExecuteAsync(null);
var vault = shell.Vault!;
var sharedVaultId = vaults.SelectedVault!.VaultId;
await vault.LoadAsync(Token);
await AddHostAsync(vault, "prod-db");
vault.NewHostCommand.Execute(null);
vault.EditorSelectedVault =
vault.EditorVaultChoices.Single(choice => choice.VaultId == sharedVaultId);
vault.EditorLabel = "prod-web";
vault.EditorHostname = "web.internal";
await vault.SaveHostCommand.ExecuteAsync(null);
vault.ChooseHostCommand.Execute(Host(vault, "prod-db"));
vault.ToggleHostChoiceCommand.Execute(Host(vault, "prod-web"));
vault.RegroupChosenHostsCommand.Execute(null);
vault.IsRegroupingChosenHosts.ShouldBeFalse("a group belongs to one keychain");
vault.Status.ShouldStartWith("These hosts are in more than one keychain");
vault.IsChoosingHosts.ShouldBeTrue("the set was refused, not dissolved");
// Unticking the visitor is all it takes: the refusal is about the set, not a latch the screen has
// to be talked out of.
vault.ToggleHostChoiceCommand.Execute(Host(vault, "prod-web"));
vault.RegroupChosenHostsCommand.Execute(null);
vault.IsRegroupingChosenHosts.ShouldBeTrue(vault.Status);
}
/// <remarks> /// <remarks>
/// Duplicating keeps the group and the tags, which is the whole difference between it and a copy into /// Duplicating keeps the group and the tags, which is the whole difference between it and a copy into
/// another vault: the copy stays in the same keychain, so everything it points at is still there. /// another vault: the copy stays in the same keychain, so everything it points at is still there.