Files
MBN_STOCK_WEBVIEW/tests/MBN_STOCK_WEBVIEW.LegacyWeb.Tests/LegacyIndustryListWebContractTests.cs

193 lines
8.8 KiB
C#

using System.Text.RegularExpressions;
namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
public sealed class LegacyIndustryListWebContractTests
{
private static readonly string RepositoryRoot = FindRepositoryRoot();
private static readonly string App = File.ReadAllText(Path.Combine(
RepositoryRoot,
"src",
"MBN_STOCK_WEBVIEW.LegacyParityApp",
"Web",
"app.js"));
[Fact]
public void Industry_list_is_one_tab_stop_and_rows_are_programmatic_descendants()
{
var renderIndustry = Extract(
App,
" function renderIndustry(state) {",
" function renderOverseas(state) {");
var listFactory = Extract(
renderIndustry,
" const list = document.createElement(\"div\");",
" const comparisonTitle = document.createElement(\"strong\");");
Assert.Contains("list.setAttribute(\"role\", \"listbox\");", listFactory,
StringComparison.Ordinal);
Assert.Contains("list.tabIndex = 0;", listFactory, StringComparison.Ordinal);
Assert.Contains("industry.industries.forEach(function (row) {", listFactory,
StringComparison.Ordinal);
Assert.Contains("button.dataset.industryIndex = String(row.index);", listFactory,
StringComparison.Ordinal);
Assert.Contains("button.tabIndex = -1;", listFactory, StringComparison.Ordinal);
Assert.Contains("button.setAttribute(\"role\", \"option\");", listFactory,
StringComparison.Ordinal);
Assert.Single(Regex.Matches(listFactory, @"\.tabIndex\s*=\s*0;").Cast<Match>());
Assert.DoesNotContain("button.tabIndex = 0;", listFactory, StringComparison.Ordinal);
}
[Fact]
public void Industry_list_handles_arrow_home_and_end_navigation()
{
var keyHandler = Extract(
App,
" categoryTree.addEventListener(\"keydown\", function (event) {",
" window.addEventListener(\"pointerup\", function () {");
Assert.Contains("const industryList = event.target.closest(\".industry-list\");",
keyHandler, StringComparison.Ordinal);
Assert.Contains(
"[\"ArrowUp\", \"ArrowDown\", \"Home\", \"End\"].includes(event.key)",
keyHandler,
StringComparison.Ordinal);
Assert.Contains("event.preventDefault();", keyHandler, StringComparison.Ordinal);
Assert.Contains("if (event.key === \"Home\") nextIndex = 0;", keyHandler,
StringComparison.Ordinal);
Assert.Contains("else if (event.key === \"End\") nextIndex = rows.length - 1;",
keyHandler, StringComparison.Ordinal);
Assert.Contains(
"else if (event.key === \"ArrowUp\") nextIndex = Math.max(0, selectedIndex - 1);",
keyHandler,
StringComparison.Ordinal);
Assert.Contains(
"else nextIndex = Math.min(rows.length - 1, selectedIndex + 1);",
keyHandler,
StringComparison.Ordinal);
Assert.Contains("selectIndustryRow(nextRow);", keyHandler, StringComparison.Ordinal);
Assert.Contains("nextRow.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });",
keyHandler, StringComparison.Ordinal);
}
[Fact]
public void Selection_only_state_receipt_updates_rows_without_replacing_the_workspace()
{
var renderIndustry = Extract(
App,
" function renderIndustry(state) {",
" function renderOverseas(state) {");
var structureIdentity = Extract(
renderIndustry,
" const structureKey = JSON.stringify({",
" const existingWorkspace = categoryTree.querySelector(\".industry-workspace\");");
var selectionOnlyReceipt = Extract(
renderIndustry,
" if (existingWorkspace && structureKey === industryRenderStructureKey) {",
" const previousList = categoryTree.querySelector(\".industry-list\");");
Assert.Contains("market: industry.market", structureIdentity, StringComparison.Ordinal);
Assert.Contains("rows: industry.industries.map", structureIdentity,
StringComparison.Ordinal);
Assert.Contains("actions: industry.actions.map", structureIdentity,
StringComparison.Ordinal);
Assert.DoesNotContain("selectedIndex", structureIdentity, StringComparison.Ordinal);
Assert.Contains("existingWorkspace.querySelectorAll(\"button[data-industry-index]\")",
selectionOnlyReceipt, StringComparison.Ordinal);
Assert.Contains(
"const selected = Number(row.dataset.industryIndex) === industry.selectedIndex;",
selectionOnlyReceipt,
StringComparison.Ordinal);
Assert.Contains("row.classList.toggle(\"selected\", selected);", selectionOnlyReceipt,
StringComparison.Ordinal);
Assert.Contains(
"row.setAttribute(\"aria-selected\", selected ? \"true\" : \"false\");",
selectionOnlyReceipt,
StringComparison.Ordinal);
Assert.Contains("return;", selectionOnlyReceipt, StringComparison.Ordinal);
Assert.DoesNotContain("replaceChildren", selectionOnlyReceipt, StringComparison.Ordinal);
Assert.DoesNotContain("document.createElement", selectionOnlyReceipt,
StringComparison.Ordinal);
}
[Fact]
public void Industry_list_is_appended_before_comparison_label_and_slots()
{
var renderIndustry = Extract(
App,
" function renderIndustry(state) {",
" function renderOverseas(state) {");
Assert.Contains("comparisonTitle.textContent = \"업종비교\";", renderIndustry,
StringComparison.Ordinal);
Assert.Contains("selector.append(list, comparisonTitle, slots);", renderIndustry,
StringComparison.Ordinal);
Assert.DoesNotContain("selector.append(comparisonTitle, slots, list);", renderIndustry,
StringComparison.Ordinal);
}
[Fact]
public void Comparison_text_boxes_commit_closed_text_intents_without_replacing_focused_dom()
{
var renderIndustry = Extract(
App,
" function renderIndustry(state) {",
" function renderOverseas(state) {");
var changeHandler = Extract(
App,
" categoryTree.addEventListener(\"change\", function (event) {",
" categoryTree.addEventListener(\"keydown\", function (event) {");
Assert.Contains("first.dataset.industrySlot = \"first\";", renderIndustry,
StringComparison.Ordinal);
Assert.Contains("second.dataset.industrySlot = \"second\";", renderIndustry,
StringComparison.Ordinal);
Assert.Contains("first.maxLength = 128;", renderIndustry, StringComparison.Ordinal);
Assert.Contains("second.maxLength = 128;", renderIndustry, StringComparison.Ordinal);
Assert.DoesNotContain("first.readOnly = true;", renderIndustry,
StringComparison.Ordinal);
Assert.DoesNotContain("second.readOnly = true;", renderIndustry,
StringComparison.Ordinal);
Assert.DoesNotContain("firstName: industry.firstName", renderIndustry,
StringComparison.Ordinal);
Assert.DoesNotContain("secondName: industry.secondName", renderIndustry,
StringComparison.Ordinal);
Assert.Contains("document.activeElement !== firstInput", renderIndustry,
StringComparison.Ordinal);
Assert.Contains("document.activeElement !== secondInput", renderIndustry,
StringComparison.Ordinal);
Assert.Contains("send(\"set-industry-comparison-text\"", changeHandler,
StringComparison.Ordinal);
Assert.Contains("slot: event.target.dataset.industrySlot", changeHandler,
StringComparison.Ordinal);
Assert.Contains("value: event.target.value", changeHandler,
StringComparison.Ordinal);
}
private static string Extract(string source, string startToken, string endToken)
{
var start = source.IndexOf(startToken, StringComparison.Ordinal);
var end = source.IndexOf(endToken, start + startToken.Length, StringComparison.Ordinal);
Assert.True(start >= 0, $"Start token was not found: {startToken}");
Assert.True(end > start, $"End token was not found after start token: {endToken}");
return source[start..end];
}
private static string FindRepositoryRoot()
{
var directory = new DirectoryInfo(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("Repository root was not found.");
}
}