using System.Text.RegularExpressions; namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests; public sealed class LegacyWebContractTests { private static readonly string RepositoryRoot = FindRepositoryRoot(); private static readonly string WebRoot = Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "Web"); private static readonly string App = File.ReadAllText(Path.Combine(WebRoot, "app.js")); private static readonly string Markup = File.ReadAllText(Path.Combine(WebRoot, "index.html")); private static readonly string Styles = File.ReadAllText(Path.Combine(WebRoot, "styles.css")); [Fact] public void ShellExposesOriginalStockCutPlaylistAndPlayoutControls() { foreach (var id in new[] { "stock-search", "stock-search-button", "stock-results", "cut-list", "playlist-drop-zone", "playlist-rows", "legacy-dialog" }) { Assert.Contains($"id=\"{id}\"", Markup, StringComparison.Ordinal); } Assert.Contains("TAKE IN", Markup, StringComparison.Ordinal); Assert.Contains("TAKE OUT", Markup, StringComparison.Ordinal); Assert.Contains("NEXT", Markup, StringComparison.Ordinal); Assert.Matches("class=\"connection-state\"[^>]*>미연결", Markup); Assert.Contains( "class=\"active\" type=\"button\" disabled>해외", Markup, StringComparison.Ordinal); Assert.Contains( "type=\"button\" disabled>정지", Markup, StringComparison.Ordinal); } [Fact] public void WebLayerDoesNotOwnSceneDatabaseIdentityOrPlaylistState() { Assert.DoesNotMatch( new Regex("(?:sceneCode|cutCode|stockCode|dataCode|builderKey)"), App); Assert.DoesNotMatch( new Regex("(?:localStorage|sessionStorage|playlist\\.push|fetch\\s*\\()"), App); Assert.DoesNotMatch( new Regex("\\b(?:5001|N5001|5006|5011|5086|8035|8061|8040|8046|8051|8056|8003|5037)\\b"), App); } [Fact] public void DoubleClickUsesPointerFactsInsteadOfBrowserPolicy() { Assert.Contains("cut-pointer-down", App, StringComparison.Ordinal); Assert.Contains("timestampMilliseconds", App, StringComparison.Ordinal); Assert.Contains("event.ctrlKey", App, StringComparison.Ordinal); Assert.Contains("event.shiftKey", App, StringComparison.Ordinal); Assert.DoesNotContain("dblclick", App, StringComparison.Ordinal); } [Fact] public void CutRowsAreReconciledInPlace() { Assert.Contains("dataset.physicalIndex", App, StringComparison.Ordinal); Assert.Contains("function createCutElement", App, StringComparison.Ordinal); Assert.DoesNotContain("cutList.replaceChildren", App, StringComparison.Ordinal); } [Fact] public void StockAndPlaylistRowsPreserveNativeControlFocus() { Assert.Contains("dataset.resultIndex", App, StringComparison.Ordinal); Assert.Contains("dataset.rowId", App, StringComparison.Ordinal); Assert.DoesNotContain("stockResults.replaceChildren", App, StringComparison.Ordinal); Assert.DoesNotContain("playlistRows.replaceChildren", App, StringComparison.Ordinal); } [Fact] public void SeparatorRowsPreserveOriginalDragGesture() { Assert.Contains("element.draggable = true", App, StringComparison.Ordinal); Assert.DoesNotContain("draggable = !row.isSeparator", App, StringComparison.Ordinal); } [Fact] public void BusySnapshotFreezesControlsWithoutQueueingInput() { Assert.Contains("state.isBusy === true", App, StringComparison.Ordinal); Assert.Contains("classList.toggle(\"busy\"", App, StringComparison.Ordinal); Assert.Contains( "body.busy .operator-shell { pointer-events: none; }", Styles, StringComparison.Ordinal); } private static string FindRepositoryRoot() { DirectoryInfo? directory = new(AppContext.BaseDirectory); while (directory is not null) { if (File.Exists(Path.Combine(directory.FullName, "MBN_STOCK_WEBVIEW.sln"))) { return directory.FullName; } directory = directory.Parent; } throw new DirectoryNotFoundException("The repository root could not be located."); } }