Migrate remaining legacy operator workflows
This commit is contained in:
180
tests/Web/named-comparison-restore-workflow.test.cjs
Normal file
180
tests/Web/named-comparison-restore-workflow.test.cjs
Normal file
@@ -0,0 +1,180 @@
|
||||
"use strict";
|
||||
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const workflow = require("../../Web/named-comparison-restore-workflow.js");
|
||||
|
||||
function raw(overrides = {}) {
|
||||
return {
|
||||
itemIndex: 0,
|
||||
enabled: true,
|
||||
groupCode: "코스피,코스닥",
|
||||
subject: "삼성전자,에이비엘바이오",
|
||||
graphicType: "종목별 비교분석_캔들 그래프",
|
||||
subtype: "",
|
||||
pageText: "1/1",
|
||||
dataCode: "",
|
||||
...overrides
|
||||
};
|
||||
}
|
||||
|
||||
function pending(value = raw(), id = "db-comparison-0") {
|
||||
return workflow.classify(value, { id, fadeDuration: 6 });
|
||||
}
|
||||
|
||||
function response(rows, requestId = "named-load-1") {
|
||||
return {
|
||||
requestId,
|
||||
retrievedAt: "2026-07-12T12:00:00+09:00",
|
||||
totalRowCount: rows.length,
|
||||
rows
|
||||
};
|
||||
}
|
||||
|
||||
test("the exact original action grammar classifies all nine comparison leaves", () => {
|
||||
const cases = [
|
||||
["2열판", "", "two-column-current"],
|
||||
["2열판", "예상체결", "two-column-expected"],
|
||||
["종목별 비교분석_캔들 그래프", "", "comparison-candle"],
|
||||
["종목별 비교분석_라인 그래프", "", "comparison-line"],
|
||||
["종목별 수익률 비교", "5일", "return-5d"],
|
||||
["종목별 수익률 비교", "1개월", "return-1m"],
|
||||
["종목별 수익률 비교", "3개월", "return-3m"],
|
||||
["종목별 수익률 비교", "6개월", "return-6m"],
|
||||
["종목별 수익률 비교", "12개월", "return-12m"]
|
||||
];
|
||||
for (let index = 0; index < cases.length; index += 1) {
|
||||
const [graphicType, subtype, actionId] = cases[index];
|
||||
const value = pending(raw({
|
||||
itemIndex: index,
|
||||
groupCode: graphicType === "2열판" ? "지수" : "코스피,코스닥",
|
||||
subject: graphicType === "2열판"
|
||||
? "코스피 지수,코스닥 지수"
|
||||
: "삼성전자,에이비엘바이오",
|
||||
graphicType,
|
||||
subtype
|
||||
}), `comparison-${index}`);
|
||||
assert.ok(value);
|
||||
assert.equal(value.actionId, actionId);
|
||||
}
|
||||
});
|
||||
|
||||
test("market-lost stock rows are submitted but can only normalize as a failed outcome", () => {
|
||||
const value = pending(raw({
|
||||
groupCode: "종목",
|
||||
subject: "삼성전자,엔비디아",
|
||||
graphicType: "2열판"
|
||||
}));
|
||||
assert.ok(value);
|
||||
const normalized = workflow.normalizeResponse(response([{
|
||||
itemIndex: 0,
|
||||
status: "failed",
|
||||
failure: "MISSING_MARKET_IDENTITY"
|
||||
}]), "named-load-1", [value]);
|
||||
assert.equal(normalized.rows[0].failure, "MISSING_MARKET_IDENTITY");
|
||||
assert.equal(workflow.materialize(value, normalized.rows[0]), null);
|
||||
});
|
||||
|
||||
test("a correlated fixed-pair result materializes the explicit comparison selection", () => {
|
||||
const value = pending(raw({
|
||||
groupCode: "지수",
|
||||
subject: "코스피 지수,코스닥 지수",
|
||||
graphicType: "2열판"
|
||||
}));
|
||||
const normalized = workflow.normalizeResponse(response([{
|
||||
itemIndex: 0,
|
||||
status: "resolved",
|
||||
actionId: "two-column-current",
|
||||
first: { kind: "market-target", target: "Kospi" },
|
||||
second: { kind: "market-target", target: "Kosdaq" }
|
||||
}]), "named-load-1", [value]);
|
||||
const entry = workflow.materialize(value, normalized.rows[0]);
|
||||
|
||||
assert.equal(entry.operator.source, "legacy-comparison-workflow");
|
||||
assert.equal(entry.operator.actionId, "two-column-current");
|
||||
assert.equal(entry.selection.subject, "Kospi,Kosdaq");
|
||||
assert.equal(entry.builderKey, "s8018");
|
||||
assert.equal(entry.enabled, true);
|
||||
});
|
||||
|
||||
test("a correlated exact KRX result materializes candle and preserves disabled state", () => {
|
||||
const value = pending(raw({ enabled: false }), "db-comparison-disabled");
|
||||
const normalized = workflow.normalizeResponse(response([{
|
||||
itemIndex: 0,
|
||||
status: "resolved",
|
||||
actionId: "comparison-candle",
|
||||
first: {
|
||||
kind: "krx-stock", market: "kospi", stockName: "삼성전자", stockCode: "005930"
|
||||
},
|
||||
second: {
|
||||
kind: "krx-stock", market: "kosdaq", stockName: "에이비엘바이오", stockCode: "298380"
|
||||
}
|
||||
}]), "named-load-1", [value]);
|
||||
const entry = workflow.materialize(value, normalized.rows[0]);
|
||||
|
||||
assert.equal(entry.builderKey, "s5026");
|
||||
assert.equal(entry.operator.pair[0].stockCode, "005930");
|
||||
assert.equal(entry.selection.dataCode, "KOSPI:005930|KOSDAQ:298380");
|
||||
assert.equal(entry.enabled, false);
|
||||
});
|
||||
|
||||
test("tampered correlation, ordering, action, target, and failure codes are rejected", () => {
|
||||
const first = pending(raw(), "first");
|
||||
const second = pending(raw({
|
||||
itemIndex: 1,
|
||||
graphicType: "종목별 비교분석_라인 그래프"
|
||||
}), "second");
|
||||
const validRows = [
|
||||
{
|
||||
itemIndex: 0,
|
||||
status: "failed",
|
||||
failure: "IDENTITY_NOT_FOUND"
|
||||
},
|
||||
{
|
||||
itemIndex: 1,
|
||||
status: "failed",
|
||||
failure: "IDENTITY_AMBIGUOUS"
|
||||
}
|
||||
];
|
||||
assert.ok(workflow.normalizeResponse(response(validRows), "named-load-1", [first, second]));
|
||||
assert.equal(workflow.normalizeResponse(response(validRows, "stale"), "named-load-1", [first, second]), null);
|
||||
assert.equal(workflow.normalizeResponse(response([...validRows].reverse()), "named-load-1", [first, second]), null);
|
||||
assert.equal(workflow.normalizeResponse(response([
|
||||
{ ...validRows[0], failure: "GUESS_MARKET" }, validRows[1]
|
||||
]), "named-load-1", [first, second]), null);
|
||||
|
||||
const wrongAction = response([{
|
||||
itemIndex: 0,
|
||||
status: "resolved",
|
||||
actionId: "comparison-line",
|
||||
first: { kind: "krx-stock", market: "kospi", stockName: "삼성전자", stockCode: "005930" },
|
||||
second: { kind: "krx-stock", market: "kosdaq", stockName: "에이비엘바이오", stockCode: "298380" }
|
||||
}]);
|
||||
assert.equal(workflow.normalizeResponse(wrongAction, "named-load-1", [first]), null);
|
||||
});
|
||||
|
||||
test("malformed raw fields and retryable native errors are rejected", () => {
|
||||
assert.equal(pending(raw({ pageText: "1/2" })), null);
|
||||
assert.equal(pending(raw({ dataCode: "005930" })), null);
|
||||
assert.equal(pending(raw({ subject: "삼성전자" })), null);
|
||||
assert.equal(pending(raw({ subject: " 삼성전자,기아" })), null);
|
||||
assert.equal(pending(raw({ subtype: "20일", graphicType: "종목별 수익률 비교" })), null);
|
||||
|
||||
assert.deepEqual(workflow.normalizeError({
|
||||
requestId: "named-load-1",
|
||||
code: "DATABASE_UNAVAILABLE",
|
||||
message: "현재 DB를 사용할 수 없습니다.",
|
||||
retryable: false
|
||||
}, "named-load-1"), {
|
||||
requestId: "named-load-1",
|
||||
code: "DATABASE_UNAVAILABLE",
|
||||
message: "현재 DB를 사용할 수 없습니다.",
|
||||
retryable: false
|
||||
});
|
||||
assert.equal(workflow.normalizeError({
|
||||
requestId: "named-load-1",
|
||||
code: "DATABASE_UNAVAILABLE",
|
||||
message: "현재 DB를 사용할 수 없습니다.",
|
||||
retryable: true
|
||||
}, "named-load-1"), null);
|
||||
});
|
||||
Reference in New Issue
Block a user