Files
MBN_STOCK_WEBVIEW/tests/Web/operator-command-matrix.test.cjs

157 lines
5.5 KiB
JavaScript

"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const fixed = require("../../Web/legacy-fixed-workflow.js");
const industry = require("../../Web/industry-workflow.js");
const stock = require("../../Web/operator-workflow.js");
const comparison = require("../../Web/comparison-workflow.js");
const now = new Date("2026-07-11T12:00:00+09:00");
const kospiStock = Object.freeze({
market: "kospi",
stockName: "삼성전자",
displayName: "삼성전자",
stockCode: "005930",
isNxt: false
});
const primaryIndustry = Object.freeze({
market: "kospi",
code: "001",
name: "전기전자"
});
const secondaryIndustry = Object.freeze({
market: "kospi",
code: "002",
name: "금융업"
});
const kosdaqPrimaryIndustry = Object.freeze({
market: "kosdaq",
code: "101",
name: "IT"
});
const kosdaqSecondaryIndustry = Object.freeze({
market: "kosdaq",
code: "102",
name: "제약"
});
const comparisonPair = Object.freeze([
Object.freeze({ kind: "krx-stock", market: "kospi", stockName: "삼성전자", stockCode: "005930" }),
Object.freeze({ kind: "krx-stock", market: "kospi", stockName: "SK하이닉스", stockCode: "000660" })
]);
test("the original operator command matrix has exactly 412 visible slots", () => {
assert.equal(fixed.actions.length, 328);
assert.equal(industry.cuts.length * industry.markets.length, 44);
assert.equal(stock.stockCuts.length, 31);
assert.equal(comparison.actions.length, 9);
assert.equal(
fixed.actions.length + industry.cuts.length * industry.markets.length +
stock.stockCuts.length + comparison.actions.length,
412);
assert.equal(new Set(fixed.actions.map(value => value.id)).size, 328);
assert.equal(new Set(industry.cuts.map(value => value.id)).size, 22);
assert.equal(new Set(stock.stockCuts.map(value => value.id)).size, 31);
assert.equal(new Set(comparison.actions.map(value => value.id)).size, 9);
});
test("all 322 non-manual fixed slots create and strictly round-trip", () => {
const available = fixed.actions.filter(value => value.available);
assert.equal(available.length, 322);
for (const [index, action] of available.entries()) {
const created = fixed.createFixedPlaylistEntry(action.id, {
id: `fixed-matrix-${index + 1}`,
fadeDuration: 6,
now,
ma5: true,
ma20: true
});
const restored = fixed.restoreFixedPlaylistEntry(created, { now });
assert.ok(restored, `${action.id} ${action.label}`);
assert.equal(restored.builderKey, action.builderKey);
assert.equal(restored.code, action.code);
}
});
test("the six fixed manual placeholders resolve only through their dedicated editors", () => {
const manual = fixed.actions.filter(value => !value.available);
assert.deepEqual(
manual.map(value => [value.id, value.label, value.builderKey, value.code]),
[
["fixed-245", "개인 순매도 상위(수동)", "s5025", "5025"],
["fixed-246", "외국인 순매도 상위(수동)", "s5025", "5025"],
["fixed-247", "기관 순매도 상위(수동)", "s5025", "5025"],
["fixed-262", "VI 발동(수동)", "s5074", "5074"],
["fixed-293", "VI 발동(수동)", "s5074", "5074"],
["fixed-320", "VI 발동(수동)", "s5074", "5074"]
]);
for (const action of manual) {
assert.throws(() => fixed.createFixedPlaylistEntry(action.id, {
id: `blocked-${action.id}`,
fadeDuration: 6,
now
}), /manual|수동|입력/i);
}
});
test("all 44 industry slots create and strictly round-trip with explicit selections", () => {
let ordinal = 0;
for (const market of industry.markets) {
const selected = market === "kospi" ? primaryIndustry : kosdaqPrimaryIndustry;
const pair = market === "kospi"
? [primaryIndustry, secondaryIndustry]
: [kosdaqPrimaryIndustry, kosdaqSecondaryIndustry];
for (const cut of industry.cuts) {
ordinal += 1;
const created = industry.createIndustryPlaylistEntry(market, cut.id, {
id: `industry-matrix-${ordinal}`,
fadeDuration: 6,
selected,
pair,
now,
ma5: true,
ma20: true
});
const restored = industry.restoreIndustryPlaylistEntry(created, { now });
assert.ok(restored, `${market} ${cut.id}`);
assert.equal(restored.builderKey, created.builderKey);
assert.equal(restored.code, created.code);
}
}
assert.equal(ordinal, 44);
});
test("all 31 stock and nine comparison slots create and strictly round-trip", () => {
for (const [index, cut] of stock.stockCuts.entries()) {
const created = stock.createStockPlaylistEntry(kospiStock, cut.id, {
id: `stock-matrix-${index + 1}`,
fadeDuration: 6,
ma5: true,
ma20: true
});
assert.ok(stock.restoreStockPlaylistEntry(created), cut.id);
}
for (const [index, action] of comparison.actions.entries()) {
const created = comparison.createComparisonPlaylistEntry(
action.id,
comparisonPair,
{ id: `comparison-matrix-${index + 1}`, fadeDuration: 6 });
assert.ok(comparison.restoreComparisonPlaylistEntry(created), action.id);
}
});
test("the four GraphE buttons remain outside the 412 slots and map to exact INPUT tables", () => {
assert.deepEqual(
stock.manualStockActions.map(value => [value.id, value.builderKey, value.prerequisiteTable]),
[
["manual-revenue-mix", "s5076", "INPUT_PIE"],
["manual-growth-metrics", "s5079", "INPUT_GROW"],
["manual-sales", "s5080", "INPUT_SELL"],
["manual-operating-profit", "s5081", "INPUT_PROFIT"]
]);
});