Files
LlamaCasty/ytLive.Tests/NotificationAreaIntegrationTests.cs
T

97 lines
3.0 KiB
C#

using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Notification.Core;
using Notification.Wpf.Controls;
using Xunit;
using ytLive.Services;
namespace ytLive.Tests;
/// <summary>
/// TASK 24 integration: the real NotificationService against a real window-hosted
/// ToastArea. Transient notifications expire on their own; errors stick until the
/// area goes away. ONE integration test per the Good Dog Rule.
/// </summary>
[Collection("RealApp")]
public class NotificationAreaIntegrationTests
{
private readonly RealAppHost _app;
public NotificationAreaIntegrationTests(RealAppHost app) => _app = app;
[Fact]
public void Info_Auto_Dismisses_And_Error_Sticks()
{
Window? window = null;
NotificationArea? area = null;
NotificationService? service = null;
_app.Run(() =>
{
area = new NotificationArea { Name = NotificationService.AreaName, Position = NotificationPosition.BottomRight, MaxItems = 4 };
var grid = new Grid();
grid.Children.Add(area);
window = new Window { Content = grid, Width = 400, Height = 300, WindowStartupLocation = WindowStartupLocation.Manual, Left = -32000, Top = 0, ShowInTaskbar = false, ShowActivated = false };
window.Show();
service = new NotificationService();
});
try
{
service!.Info("Hello", "transient");
Assert.True(WaitFor(() => ItemCount(area!) == 1), "info toast never appeared");
Assert.True(WaitFor(() => ItemCount(area!) == 0, TimeSpan.FromSeconds(8)),
"info toast never auto-dismissed");
service!.Error("Broken", "sticky");
Assert.True(WaitFor(() => ItemCount(area!) == 1), "error toast never appeared");
Thread.Sleep(1200);
Assert.Equal(1, ItemCount(area!));
}
finally
{
_app.Run(() => window!.Close());
}
}
private int ItemCount(NotificationArea area)
{
var count = 0;
_app.Run(() => count = CountItems(area));
return count;
}
private static int CountItems(NotificationArea area)
{
var count = 0;
Walk(area, ref count);
return count;
static void Walk(DependencyObject node, ref int count)
{
if (node is Panel panel && panel.Name == "PART_Items")
{
count += panel.Children.Count;
return;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++)
Walk(VisualTreeHelper.GetChild(node, i), ref count);
}
}
private static bool WaitFor(Func<bool> condition, TimeSpan? timeout = null)
{
var deadline = DateTime.UtcNow + (timeout ?? TimeSpan.FromSeconds(3));
while (DateTime.UtcNow < deadline)
{
if (condition()) return true;
Thread.Sleep(50);
}
return condition();
}
}