157 lines
5.5 KiB
JavaScript
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"]
|
|
]);
|
|
});
|