117 lines
5.5 KiB
JavaScript
117 lines
5.5 KiB
JavaScript
"use strict";
|
|
|
|
const assert = require("node:assert/strict");
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
const test = require("node:test");
|
|
|
|
const root = path.resolve(__dirname, "..", "..");
|
|
const webRoot = path.join(root, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "Web");
|
|
const app = fs.readFileSync(path.join(webRoot, "app.js"), "utf8");
|
|
const styles = fs.readFileSync(path.join(webRoot, "styles.css"), "utf8");
|
|
|
|
function section(startToken, endToken) {
|
|
const start = app.indexOf(startToken);
|
|
const end = app.indexOf(endToken, start + startToken.length);
|
|
assert.ok(start >= 0 && end > start, `missing ${startToken} section`);
|
|
return app.slice(start, end);
|
|
}
|
|
|
|
test("UC5 Web keeps the original top-to-bottom index, industry, stock order", () => {
|
|
const render = section("function renderOverseas(state)", "function renderComparison(state)");
|
|
const fixed = render.indexOf('fixedHeading.textContent = "해외지수"');
|
|
const industry = render.indexOf('searchGroup("industry", "해외 업종지수", "업종 검색"');
|
|
const stock = render.indexOf('searchGroup("stock", "해외 종목", "종목 검색"');
|
|
|
|
assert.ok(fixed >= 0 && fixed < industry && industry < stock);
|
|
assert.match(render, /periodButtons\("fixedIndex"\)/);
|
|
assert.match(render, /model\.isTruncated === true/);
|
|
assert.match(render, /검색 결과가 최대 500건으로 제한되었습니다\./);
|
|
assert.match(styles, /\.overseas-truncation/);
|
|
assert.match(render, /actionButton\(current, "1열판"\)/);
|
|
assert.match(render, /action\.periodDays \+ "일"/);
|
|
assert.doesNotMatch(render, /overseas-action-panel|overseas-selected|overseas-note/);
|
|
assert.doesNotMatch(render, /document\.createElement\("details"\)/);
|
|
|
|
for (const selector of [
|
|
".overseas-workspace",
|
|
".overseas-fixed-body",
|
|
".overseas-period-actions",
|
|
".overseas-result-area"
|
|
]) {
|
|
assert.match(styles, new RegExp(selector.replaceAll(".", "\\.")));
|
|
}
|
|
assert.match(styles, /grid-template-rows:\s*minmax\(176px.*minmax\(184px.*minmax\(210px/u);
|
|
});
|
|
|
|
test("UC5 rows are immediately selected, preserve their DOM on receipts, and keep data private", () => {
|
|
const render = section("function renderOverseas(state)", "function renderComparison(state)");
|
|
const update = section("function updateOverseasWorkspace", "function markOverseasRowSelected");
|
|
const click = section(
|
|
'categoryTree.addEventListener("click"',
|
|
'categoryTree.addEventListener("change"');
|
|
const overseasClick = click.slice(
|
|
click.indexOf('const overseasTarget = event.target.closest("button[data-overseas-target-id]");'),
|
|
click.indexOf("const comparisonChoice", click.indexOf("const overseasTarget")));
|
|
|
|
assert.match(app, /function selectOverseasRow\(row\)[\s\S]*markOverseasRowSelected\(row\)/);
|
|
assert.match(overseasClick, /selectOverseasRow\(overseasTarget\)/);
|
|
assert.match(overseasClick, /selectOverseasRow\(overseasResult\)/);
|
|
assert.doesNotMatch(overseasClick, /setTimeout/);
|
|
assert.match(render,
|
|
/existingWorkspace && structureKey === overseasRenderStructureKey[\s\S]*updateOverseasWorkspace\(existingWorkspace, overseas/);
|
|
assert.doesNotMatch(update, /replaceChildren/);
|
|
assert.doesNotMatch(render, /nationCode|FOREIGN_|symbol/i);
|
|
assert.match(app, /event\.key === "Enter"[\s\S]*overseas-industry-search/);
|
|
});
|
|
|
|
test("UC5 listboxes keep one tab stop and move a single native selection by keyboard", () => {
|
|
const helper = section("function moveOverseasListSelection", "function renderOverseas(state)");
|
|
const keydown = section(
|
|
'categoryTree.addEventListener("keydown"',
|
|
'window.addEventListener("pointerup"');
|
|
|
|
assert.match(helper, /list\.getAttribute\("aria-disabled"\) === "true"/);
|
|
assert.match(helper, /querySelectorAll\("button"\)/);
|
|
assert.match(helper, /selectOverseasRow\(nextRow\)/);
|
|
assert.match(helper, /scrollIntoView\(\{ block: "nearest", inline: "nearest" \}\)/);
|
|
assert.match(keydown, /const overseasList = event\.target\.closest\("\[data-overseas-list\]"\)/);
|
|
assert.match(keydown, /event\.stopPropagation\(\);[\s\S]*moveOverseasListSelection\(overseasList, event\.key\)/);
|
|
assert.match(keydown, /moveOverseasListSelection\(overseasList, event\.key\)/);
|
|
assert.match(app, /button\.tabIndex = -1/g);
|
|
|
|
const rows = [0, 1, 2].map(index => ({
|
|
index,
|
|
selected: false,
|
|
scrolled: 0,
|
|
getAttribute(name) { return name === "aria-selected" ? String(this.selected) : null; },
|
|
scrollIntoView() { this.scrolled += 1; }
|
|
}));
|
|
const list = {
|
|
busy: false,
|
|
getAttribute(name) { return name === "aria-disabled" && this.busy ? "true" : "false"; },
|
|
querySelectorAll(selector) { assert.equal(selector, "button"); return rows; }
|
|
};
|
|
const selected = [];
|
|
const move = new Function("selectOverseasRow", `${helper}; return moveOverseasListSelection;`)(row => {
|
|
rows.forEach(candidate => { candidate.selected = candidate === row; });
|
|
selected.push(row.index);
|
|
});
|
|
|
|
assert.equal(move(list, "ArrowDown"), true);
|
|
assert.equal(move(list, "ArrowDown"), true);
|
|
assert.equal(move(list, "Home"), true);
|
|
assert.equal(move(list, "ArrowUp"), false);
|
|
assert.equal(move(list, "End"), true);
|
|
assert.deepEqual(selected, [0, 1, 0, 2]);
|
|
assert.equal(rows[0].scrolled, 2);
|
|
assert.equal(rows[1].scrolled, 1);
|
|
assert.equal(rows[2].scrolled, 1);
|
|
|
|
list.busy = true;
|
|
assert.equal(move(list, "ArrowUp"), false);
|
|
assert.deepEqual(selected, [0, 1, 0, 2]);
|
|
const empty = { getAttribute() { return "false"; }, querySelectorAll() { return []; } };
|
|
assert.equal(move(empty, "ArrowDown"), false);
|
|
});
|