Files
LlamaCasty/ytLive.Tests/BrandLogoPreviewTests.cs
T
gramps 9528128ca7 feat(settings): brand-logo thumbnail with a hover enlargement
The creator (2026-10-30): the brand-logo field in App Settings showed only a file NAME, so a
myopic user could not confirm which picture was set. Now a 28x28 thumbnail sits left of the
field showing the actual image, and hovering it opens an enlarged copy (up to 420x320) beside
the panel with the file name underneath. A click collapses it; moving the pointer away closes
it, unless the pointer walked onto the popup itself, where it stays so the creator can look
closely.

Mechanics:
- `MainViewModel.BrandLogoPreviewImage` decodes the stored asset ONCE and freezes it, so the
  thumbnail and the enlargement share one bitmap and no dispatcher hop is needed. A corrupt
  image returns null instead of taking the dialog down.
- The thumbnail is hidden when no image is set (NotNullToVis), so there is nothing to hover and
  no empty frame can appear.
- The popup is a separate window: WPF refuses to open one until its placement target is in a
  live visual tree, which is why the test hosts the control in a real window rather than
  asserting on a detached control.

Guard: BrandLogoPreviewTests — the wiring (image binding, the no-image gate, the four gesture
handlers, the readable enlargement size) and the control's open/close behaviour.
2026-10-30 08:39:42 -07:00

61 lines
2.7 KiB
C#

using Xunit;
namespace ytLive.Tests;
/// <summary>The creator (2026-10-30): in App Settings the brand-logo field is only a file NAME,
/// which says nothing about the picture, so "myopic users like myself" cannot confirm what is
/// set. The field now carries a thumbnail — hover enlarges it, a click collapses it.
///
/// <para>The ONE test covers both halves: the XAML wiring that routes hover/leave/click, and the
/// control's own open/close behaviour (a Popup is a separate window, so only this seam can
/// observe it). Runs inside the real App because the control resolves theme resources at load.</para></summary>
[Collection("RealApp")]
public class BrandLogoPreviewTests
{
private readonly RealAppHost _app;
public BrandLogoPreviewTests(RealAppHost app) => _app = app;
[Fact]
public void Hovering_the_thumbnail_opens_the_enlarged_preview_and_a_click_collapses_it()
{
// 1. Wiring: the thumbnail is image-bound and hidden when no image is set, the enlarged
// popup shows the same source at a readable size, and every gesture reaches a handler.
var xaml = SourceAssert.Text("Controls", "OverlayHost.xaml");
Assert.Contains("x:Name=\"BrandLogoThumbImage\"", xaml);
Assert.Contains("{Binding BrandLogoPreviewImage}", xaml);
Assert.Contains("NotNullToVis", xaml);
Assert.Contains("x:Name=\"BrandLogoPreviewPopup\"", xaml);
Assert.Contains("MaxWidth=\"420\"", xaml);
foreach (var handler in new[]
{
"MouseEnter=\"BrandLogoThumb_MouseEnter\"",
"MouseLeave=\"BrandLogoThumb_MouseLeave\"",
"MouseLeftButtonUp=\"BrandLogoThumb_Click\"",
"MouseLeave=\"BrandLogoPreviewPopup_MouseLeave\"",
})
Assert.Contains(handler, xaml);
// 2. Behaviour on the real control.
_app.Run(() =>
{
// A Popup refuses to open until its placement target is in a live visual tree, so the
// control is hosted in a real window — the same condition the app provides.
var host = new ytLive.Controls.OverlayHost();
var window = new System.Windows.Window { Content = host, Width = 420, Height = 420 };
window.Show();
try
{
Assert.False(host.IsBrandLogoPreviewOpen);
host.OpenBrandLogoPreview();
Assert.True(host.IsBrandLogoPreviewOpen, "hovering the thumbnail must open the enlargement");
host.CloseBrandLogoPreview();
Assert.False(host.IsBrandLogoPreviewOpen, "a click must collapse it again");
}
finally { window.Close(); }
});
}
}