namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests; public sealed class LegacyRowDoubleClickParityTests { private static readonly string RepositoryRoot = FindRepositoryRoot(); private static readonly string App = File.ReadAllText(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "Web", "app.js")); private static readonly string MainWindow = File.ReadAllText(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "MainWindow.xaml.cs")); [Fact] public void GraphE_double_click_sends_one_opaque_atomic_command() { var handler = Extract( "manualWorkspace.addEventListener(\"dblclick\"", "manualWorkspace.addEventListener(\"click\""); Assert.Contains("send(\"activate-manual-financial-result\"", handler, StringComparison.Ordinal); Assert.Contains("resultId: row.dataset.manualResultId", handler, StringComparison.Ordinal); Assert.DoesNotContain("load-manual-financial", handler, StringComparison.Ordinal); Assert.DoesNotContain("actionId", handler, StringComparison.Ordinal); Assert.Contains("clearDelayedClick(manualResultClickTimer)", handler, StringComparison.Ordinal); } [Fact] public void Theme_double_click_is_atomic_while_single_click_remains_delayed_selection() { var doubleClick = Extract( "categoryTree.addEventListener(\"dblclick\"", "categoryTree.addEventListener(\"click\""); var click = Extract( "categoryTree.addEventListener(\"click\"", "categoryTree.addEventListener(\"change\""); Assert.Contains("send(\"activate-theme-result\"", doubleClick, StringComparison.Ordinal); Assert.DoesNotContain("send(\"select-theme\"", doubleClick, StringComparison.Ordinal); Assert.Contains("window.setTimeout", click, StringComparison.Ordinal); Assert.Contains("send(\"select-theme\"", click, StringComparison.Ordinal); } [Fact] public void Named_playlist_double_click_uses_id_bound_commands_and_closes_after_receipt_only() { var doubleClick = Extract( "namedPlaylistDefinitions.addEventListener(\"dblclick\"", "namedPlaylistDefinitions.addEventListener(\"click\""); var action = Extract( "function runNamedPlaylistDoubleClick", "function lockNamedPlaylistControls"); var confirmation = Extract( "function resolveNamedPlaylistConfirmation", "function renderNamedPlaylist"); var matcher = Extract( "function isMatchingNamedPlaylistReceipt", "function openNamedPlaylistConfirmation"); var render = Extract("function renderNamedPlaylist", "function renderOperatorCatalog"); Assert.Contains("namedPlaylistSelection.defer", doubleClick, StringComparison.Ordinal); Assert.Contains("runNamedPlaylistDoubleClick", doubleClick, StringComparison.Ordinal); Assert.Contains("\"load-named-playlist-by-id\"", action, StringComparison.Ordinal); Assert.Contains("openNamedPlaylistConfirmation", action, StringComparison.Ordinal); Assert.Contains("message: \"저장하겠습니까?\"", action, StringComparison.Ordinal); Assert.Contains("showSavedAlert: false", action, StringComparison.Ordinal); Assert.Contains("closeOnNo: true", action, StringComparison.Ordinal); Assert.DoesNotContain("window.confirm", action + doubleClick, StringComparison.Ordinal); Assert.Contains("\"save-current-named-playlist-to\"", confirmation, StringComparison.Ordinal); Assert.DoesNotContain("select-named-playlist", doubleClick, StringComparison.Ordinal); Assert.Contains("commandResult.succeeded === true", render, StringComparison.Ordinal); Assert.Contains("commandResult.targetId === pending.targetId", matcher, StringComparison.Ordinal); Assert.Contains("closeNamedPlaylist()", render, StringComparison.Ordinal); } [Fact] public void Native_dispatch_awaits_all_atomic_read_then_materialize_commands() { foreach (var method in new[] { "ActivateManualFinancialResultAsync(", "ActivateThemeResultAsync(", "LoadNamedPlaylistByIdAsync(", "SaveCurrentNamedPlaylistToAsync(" }) { Assert.Contains(method, MainWindow, StringComparison.Ordinal); } } private static string Extract(string startToken, string endToken) { var start = App.IndexOf(startToken, StringComparison.Ordinal); var end = App.IndexOf(endToken, start + startToken.Length, StringComparison.Ordinal); Assert.True(start >= 0 && end > start); return App[start..end]; } private static string FindRepositoryRoot() { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (File.Exists(Path.Combine(current.FullName, "MBN_STOCK_WEBVIEW.sln"))) { return current.FullName; } current = current.Parent; } throw new DirectoryNotFoundException("Repository root was not found."); } }