Files
MBN_STOCK_WEBVIEW/tests/Web/trading-halt-name-sort-app-integration.test.cjs

78 lines
3.8 KiB
JavaScript

"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const root = path.resolve(__dirname, "../..");
const read = relativePath => fs.readFileSync(path.join(root, relativePath), "utf8");
const app = read("Web/app.js");
const index = read("Web/index.html");
const styles = read("Web/styles.css");
const native = fs.readdirSync(root)
.filter(name => /^MainWindow(?:\..+)?\.cs$/u.test(name))
.map(name => read(name))
.join("\n");
function functionBody(source, name, nextName) {
const start = source.indexOf(`function ${name}(`);
assert.ok(start >= 0, `${name} must exist`);
const end = source.indexOf(`function ${nextName}(`, start + 1);
assert.ok(end > start, `${name} must precede ${nextName}`);
return source.slice(start, end);
}
test("trading-halt results expose an accessible stock-name sort header", () => {
assert.match(index,
/class="trading-halt-results-header" role="group" aria-label="거래 정지 검색 결과 정렬"[\s\S]*id="tradingHaltNameSort"[\s\S]*aria-controls="tradingHaltResults"[\s\S]*data-sort-direction="none">종목명 ↕<\/button>/u);
assert.match(styles, /\.trading-halt-results-header\s*\{/u);
assert.match(styles, /\.trading-halt-results-header button:disabled\s*\{/u);
});
test("render sorts only a copied display view and preserves market-code selection identity", () => {
const identity = functionBody(app, "tradingHaltIdentity", "toggleTradingHaltNameSort");
const render = functionBody(app, "renderTradingHaltWorkflow", "requestTradingHaltSearch");
assert.match(identity, /tradingHaltWorkflow\.tradingHaltIdentity\(value\)/u);
assert.doesNotMatch(identity, /displayName/u);
assert.match(render,
/sortTradingHaltsForDisplay\(\s*workflow\.results,\s*workflow\.sortDirection\)/u);
assert.match(render,
/tradingHaltIdentity\(item\) === selectedIdentity/u);
assert.doesNotMatch(render, /workflow\.results\.sort\(/u);
});
test("sort is blocked while pending, locked, or empty and otherwise toggles locally", () => {
const toggle = functionBody(app, "toggleTradingHaltNameSort", "selectTradingHalt");
const render = functionBody(app, "renderTradingHaltWorkflow", "requestTradingHaltSearch");
assert.match(toggle,
/isPlaylistSnapshotLocked\(\) \|\| workflow\.status !== "ready" \|\| !workflow\.results\.length/u);
assert.match(toggle,
/workflow\.sortDirection = tradingHaltWorkflow\.nextTradingHaltNameSort\(workflow\.sortDirection\)/u);
assert.match(render,
/const canSort = workflow\.status === "ready" && workflow\.results\.length > 0/u);
assert.match(render, /tradingHaltNameSort\.disabled = locked \|\| !canSort/u);
assert.doesNotMatch(toggle,
/postNative|requestTradingHaltSearch|state\.playlist|renderPlaylist|updatePreview/u);
});
test("each new search and matching result restores the server-default order", () => {
const request = functionBody(app, "requestTradingHaltSearch", "handleTradingHaltResults");
const results = functionBody(app, "handleTradingHaltResults", "handleTradingHaltError");
assert.match(request,
/workflow\.status = "loading";[\s\S]*workflow\.results = \[\];[\s\S]*workflow\.sortDirection = null;/u);
assert.match(results,
/clearTradingHaltTimeout\(\);\s*workflow\.sortDirection = null;[\s\S]*workflow\.results = \[\.\.\.response\.results\]/u);
});
test("the display sort adds no native command surface or playlist mutation", () => {
const toggle = functionBody(app, "toggleTradingHaltNameSort", "selectTradingHalt");
assert.doesNotMatch(toggle,
/postNative|state\.playlist|renderPlaylist|updatePreview|prepare|take-in|take-out/iu);
assert.doesNotMatch(native, /sort-trading-halt|trading-halt-sort/iu);
assert.doesNotMatch(app, /postNative\("(?:sort-trading-halt|trading-halt-sort)"/iu);
});