using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Threading; using System.Windows.Media.Imaging; using Xunit; using ytLive.Models; using ytLive.Services; namespace ytLive.Tests; /// /// WebView2Manager owns the frame-driven web sources (composition-captured, see /// Services/WebCaptureFrameSource.cs). The controller/visual/GraphicCaptureItem /// layer is WinRT and only exercisable on Windows at runtime, so these tests pin /// the pure pieces (transparency script, the alpha-bbox math) and the ONE /// integration test drives the session plumbing with a fake source: registration, /// crop-stamped frames, the shared cropped preview bitmap, and coalescing to the /// latest frame. /// public class WebView2ManagerTests { private sealed class FakeWebSource : IScreenCaptureSource { public string Key { get; } public event Action? FrameAvailable; public FakeWebSource(string key) => Key = key; public Task StartAsync() => Task.CompletedTask; public Task StopAsync() => Task.CompletedTask; public void Pump(VideoFrame frame) => FrameAvailable?.Invoke(frame); } // A real Dispatcher pumping on a background STA thread, so the manager's // BeginInvoke queue can be drained deterministically from the test thread // (same harness as ScreenCaptureManagerTests). private sealed class DispatcherPump : IDisposable { private readonly Thread _thread; private readonly ManualResetEventSlim _ready = new(false); private Dispatcher? _dispatcher; public Dispatcher Dispatcher => _dispatcher!; public DispatcherPump() { _thread = new Thread(() => { _dispatcher = Dispatcher.CurrentDispatcher; _ready.Set(); Dispatcher.Run(); }); _thread.IsBackground = true; _thread.SetApartmentState(ApartmentState.STA); _thread.Start(); _ready.Wait(); } // Queued behind anything already posted at Render/higher, so pending // bitmap copies run first. public void Drain() => Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle); public void Dispose() { Dispatcher.InvokeShutdown(); _thread.Join(3000); } } [Fact] public void TransparentBackgroundScript_Is_A_Important_Element_Wide_Wipe() { // The regression the inline style lost to: a widget repainting a container (or // html/body) opaque after connect re-backs the capture → "black box" in the // recording while early frames stayed transparent. The OBS-validated formula is a // pre-parse