Public Access
Merge branch 'claude/card-selection-state-sharing-f9348c'
This commit is contained in:
@@ -336,6 +336,99 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
vault.ShowsGroupActions.ShouldBeFalse("a pair of buttons with no subject is hidden rather than shown");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The two grids share one selection, so at most one card on the screen is ever lit.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// They are two <c>ListBox</c>es, each holding a selection of its own and each drawing it the same way.
|
||||
/// Left to themselves both stay marked — a group above and a host below — under two pairs of buttons of
|
||||
/// which only one acts on whichever card the eye has settled on. The vault is what joins them.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Driven on the screen rather than on the view model alone, because half of the rule lives in the
|
||||
/// controls: clearing the property has to reach the list that is drawing the card, and a selection
|
||||
/// nulled in the view model while the card stays highlighted is the exact failure this is about.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task TheHostAndGroupGridsShareOneSelection()
|
||||
{
|
||||
await OnTheGridAsync((screen, _) =>
|
||||
{
|
||||
var host = Row(vault, "stage-web");
|
||||
|
||||
vault.OpenHostPaneCommand.Execute(host);
|
||||
Dispatcher.UIThread.RunJobs();
|
||||
|
||||
vault.SelectedGroup = vault.VisibleGroups.Single();
|
||||
Dispatcher.UIThread.RunJobs();
|
||||
|
||||
vault.SelectedHost.ShouldBeNull("choosing a group is choosing something else");
|
||||
vault.SelectedSidebarRow.ShouldBeNull("and the list that draws the hosts is told");
|
||||
screen.HostGrid.SelectedItem.ShouldBeNull();
|
||||
CardFor(screen, host).IsSelected.ShouldBeFalse("the card the pointer left has to go dark");
|
||||
vault.IsDrawerOpen.ShouldBeFalse("a pane about one host cannot stand beside a marked group");
|
||||
|
||||
vault.SelectedHost = host;
|
||||
Dispatcher.UIThread.RunJobs();
|
||||
|
||||
vault.SelectedGroup.ShouldBeNull("and the same in the other direction");
|
||||
screen.GroupGrid.SelectedItem.ShouldBeNull();
|
||||
GroupCard(screen).IsSelected.ShouldBeFalse();
|
||||
vault.ShowsGroupActions.ShouldBeFalse("so the group's own two buttons have nothing to act on");
|
||||
});
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// EDIT takes the group as an argument now, so that the phone can open the editor on a heading without
|
||||
/// selecting a group and losing the host selection to it — see <c>VaultViewModel.EditGroup</c>. The
|
||||
/// button beside the cards passes nothing and means "the card that is selected", which is the half of
|
||||
/// that change that would fail silently: a command refusing a null parameter is a button that never
|
||||
/// fires, and nothing about the markup would say so.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task TheGroupsEditButtonStillActsOnTheSelectedCard()
|
||||
{
|
||||
await OnTheGridAsync((screen, _) =>
|
||||
{
|
||||
vault.SelectedGroup = vault.VisibleGroups.Single();
|
||||
Dispatcher.UIThread.RunJobs();
|
||||
|
||||
var edit = screen.GetVisualDescendants()
|
||||
.OfType<Button>()
|
||||
.Single(button => ReferenceEquals(button.Command, vault.EditGroupCommand));
|
||||
|
||||
edit.IsEffectivelyEnabled.ShouldBeTrue("the command has to accept the button's empty parameter");
|
||||
|
||||
edit.Command.ShouldNotBeNull().Execute(edit.CommandParameter);
|
||||
|
||||
vault.IsEditingGroup.ShouldBeTrue();
|
||||
vault.GroupEditorLabel.ShouldBe("production", "the card that was selected");
|
||||
});
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The half of the shared selection that is nobody's gesture. A reload falls back to the first host when
|
||||
/// nothing is selected, which is what puts a target under CONNECT on a fresh unlock — and with one mark
|
||||
/// between the two grids that fallback would quietly unselect a group card every time a sync landed.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task ASyncDoesNotTakeTheSelectionOffAGroupCard()
|
||||
{
|
||||
var production = vault.VisibleGroups.Single();
|
||||
|
||||
vault.SelectedGroup = production;
|
||||
vault.SelectedHost.ShouldBeNull("the seed's load left a host selected, and the group took the mark");
|
||||
|
||||
await vault.LoadAsync(Token);
|
||||
|
||||
vault.SelectedHost.ShouldBeNull("the reload invented none under the card that was chosen");
|
||||
vault.SelectedGroup
|
||||
.ShouldNotBeNull("re-found by id, since the reload replaces every row object in the list")
|
||||
.EntityId.ShouldBe(production.EntityId);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The gesture, performed. It is wired in the control rather than bound in the markup — which is exactly
|
||||
/// the sort of wiring that compiles whether or not it is connected to anything — and the first half of
|
||||
|
||||
Reference in New Issue
Block a user