Files
MBN_STOCK_WEBVIEW/tests/Web/market-nav-reorder-app-integration.test.cjs

56 lines
2.9 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 app = fs.readFileSync(path.join(root, "Web/app.js"), "utf8");
const index = fs.readFileSync(path.join(root, "Web/index.html"), "utf8");
const styles = fs.readFileSync(path.join(root, "Web/styles.css"), "utf8");
const moduleSource = fs.readFileSync(path.join(root, "Web/market-nav-reorder.js"), "utf8");
test("market reorder module loads before app and binds only to marketNav", () => {
const moduleIndex = index.indexOf('<script src="market-nav-reorder.js"></script>');
const appIndex = index.indexOf('<script src="app.js"></script>');
assert.ok(moduleIndex >= 0 && appIndex > moduleIndex);
assert.match(app, /const marketNavReorder = globalThis\.MbnMarketNavReorder;/u);
assert.match(app, /marketNavReorder\.createController\(\{\s*nav: marketNav,/u);
assert.match(app,
/isBlocked: \(\) => hasOpenOperatorModal\(\) \|\| isPlaylistSnapshotLocked\(\)/u);
assert.match(app, /if \(!marketNavReorderController\.mount\(\)\)/u);
});
test("dashboard remains first and exactly ten original data-market identities reorder", () => {
const nav = index.match(/<nav id="marketNav"[\s\S]*?<\/nav>/u)?.[0] || "";
const markets = [...nav.matchAll(/data-market="([^"]+)"/gu)].map(match => match[1]);
assert.deepEqual(markets, [
"dashboard", "overseas", "exchange", "index", "kospi", "kosdaq",
"compare", "theme", "foreign-stock", "expert", "halted"
]);
assert.match(moduleSource, /const fixedMarket = "dashboard";/u);
assert.match(moduleSource, /button\.draggable = reorderable;/u);
assert.match(moduleSource, /"aria-keyshortcuts", "Alt\+ArrowUp Alt\+ArrowDown"/u);
assert.match(moduleSource, /"드래그 또는 Alt\+화살표로 업무 탭 순서 변경"/u);
});
test("reorder is DOM/session-only and cannot alter view, DB, or playlist state", () => {
assert.doesNotMatch(moduleSource,
/localStorage|sessionStorage|requestMarketData|state\.|playlist|postNative/u);
assert.match(moduleSource, /nav\.prepend\(dashboard\)/u);
assert.match(moduleSource, /for \(const market of normalized\) nav\.append/u);
const clickStart = app.indexOf('marketNav.addEventListener("click"');
const clickEnd = app.indexOf("elements.catalogSearch.addEventListener", clickStart);
const clickHandler = app.slice(clickStart, clickEnd);
assert.match(clickHandler, /state\.activeMarket = button\.dataset\.market;/u);
assert.doesNotMatch(clickHandler, /children\[|childNodes\[|selectedIndex/u);
assert.match(clickHandler, /requestMarketData\(state\.activeMarket\)/u);
});
test("drag affordance is visible without changing dashboard markup semantics", () => {
assert.match(styles, /\.nav-item\[draggable="true"\] \{ cursor: grab; \}/u);
assert.match(styles, /\.nav-item\.dragging \{ opacity: \.55; cursor: grabbing; \}/u);
});