Files
Aislo/resources/tester/helper_346_4_design_leave.cjs
T
eomsangdonandClaude Sonnet 5.5 8bbdbb9f69 test(508-1b 옛 헬퍼 공용 불러오기 4/7): 헬퍼 28 곳 loadTs 베낌 걷고 makeLoader 로
- 헬퍼 동작 그대로(풀이 함수 본문은 옮겨 담음) · 제품 코드 안 고침
- 확인: 이 묶음 헬퍼를 쓰는 시험 236 개 전 230 통과 → 후 230 통과 (시험별 junit 대조 · 어긋남 0)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 17:11:59 +09:00

166 lines
5.6 KiB
JavaScript

/* 346-4 떠남 확인 단위검증 헬퍼 — `A00_Common/design/design_leave.ts` 를 그 자리에서 트랜스파일 ·
* `b_page_state` 는 진짜 · 라우터 · 물음 창 · 문구는 흉내. 결과 JSON 을 stdout 으로.
*/
const fs = require("fs");
const path = require("path");
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const ROOT = path.join(__dirname, "..", "..");
function memoryStorage() {
const map = new Map();
return {
getItem: (key) => (map.has(key) ? map.get(key) : null),
setItem: (key, value) => map.set(key, String(value)),
removeItem: (key) => map.delete(key),
clear: () => map.clear(),
key: (index) => [...map.keys()][index] ?? null,
get length() {
return map.size;
},
};
}
const session = memoryStorage();
const win = new EventTarget();
win.sessionStorage = session;
win.localStorage = memoryStorage();
win.setTimeout = setTimeout;
globalThis.window = win;
globalThis.sessionStorage = session;
let route = "/b05-profile";
let guard = null;
let guardSets = 0;
let choice = "cancel";
const asked = [];
const STUBS = {
"@config/config_frontend": {
ROUTES: { B05_PROFILE: "/b05-profile", B06_SECTION: "/b06-section" },
},
"@ui/ui_template_locale": { t: (key) => key },
"@ui/ui_template_leave_dialog": {
leaveOrStay: async (message, hooks) => {
asked.push(message);
if (choice === "cancel") return "stay";
if (choice === "discard") {
await hooks.discard();
return "discarded";
}
await hooks.save();
return hooks.stillDirty() ? "stay" : "saved";
},
},
"../router": {
currentRoute: () => route,
setLeaveGuard: (fn) => {
guard = fn;
guardSets += 1;
},
},
};
const { loadTs } = makeLoader({
root: ROOT,
cache: false,
requireFor: (full, file) => (request) => {
if (request in STUBS) return STUBS[request];
if (request === "@ui/ui_template_window_watch")
return loadTs(path.join(ROOT, "ui_template", "ui_template_window_watch.ts"));
if (request.startsWith(".")) return loadTs(path.join(path.dirname(file), `${request}.ts`));
return require(request);
},
});
const leave = loadTs(path.join(ROOT, "A00_Common", "design", "design_leave.ts"));
const P = "p1";
const tick = () => new Promise((resolve) => setTimeout(resolve, 5));
/** 브라우저 BeforeUnloadEvent 처럼 returnValue 를 쓸 수 있게. */
class BeforeUnload extends Event {
returnValue = true;
}
const unloadBlocked = () => {
const event = new BeforeUnload("beforeunload", { cancelable: true });
win.dispatchEvent(event);
return event.defaultPrevented;
};
(async () => {
const out = {};
const root = { isConnected: true };
let saveMarks = true;
let saves = 0;
leave.guardDesignLeave(P, root, async () => {
saves += 1;
if (saveMarks) leave.markDesignClean(P);
});
out.emptyDirty = leave.designDirty(P);
// 고침이 아닌 칸 · 다른 페이지 칸 · 표준 횡단면만 — 안 물음
session.setItem(`aislo:draft:selection:${P}`, '{"chainageM":20}');
session.setItem(`aislo:draft:std-cross:${P}`, '{"soil":{}}');
session.setItem(`aislo:draft:pipe-ids:${P}`, '{"next":3}');
session.setItem(`aislo:draft:b08-materials:${P}`, '{"units":1}');
session.setItem(`aislo:draft:crossdesign:${P}:7`, "{}"); // 빈 칸
out.nonEditDirty = leave.designDirty(P);
out.nonEditUnload = unloadBlocked();
route = "/b08-quantity";
out.nonEditLeave = await guard();
out.askedNonEdit = asked.length;
// 횡단 초안(노선 7) — 물음
session.setItem(`aislo:draft:crossdesign:${P}:7`, '{"20.000":{"ground_type":"soil"}}');
out.editDirty = leave.designDirty(P);
out.editUnload = unloadBlocked();
// 같은 페이지(B05 → B06) — 안 묻고 한 틱 뒤 다시 걺
route = "/b06-section";
const setsBefore = guardSets;
out.samePage = await guard();
await tick();
out.reArmed = guardSets === setsBefore + 1;
out.askedSamePage = asked.length;
// 다른 페이지 — 취소 = 머묾
route = "/b08-quantity";
choice = "cancel";
out.cancelLeave = await guard();
// 저장 실패(깨끗한 표 없음) = 머묾 · 저장 성공 = 넘어감 · 뒤로 안 물음
choice = "save";
saveMarks = false;
out.saveFailLeave = await guard();
saveMarks = true;
out.saveLeave = await guard();
out.saves = saves;
out.afterSaveDirty = leave.designDirty(P);
out.afterSaveUnload = unloadBlocked();
const askedAfterSave = asked.length;
out.afterSaveLeave = await guard();
out.askedAfterSave = asked.length - askedAfterSave;
// 저장 뒤 다시 고침 — 다시 물음 · 버리고 넘어감 = 고침 칸만 지움
session.setItem(`aislo:draft:alignment-draft:${P}:7`, '{"station_offsets":{"20.000":0.3}}');
session.setItem(`aislo:draft:route-draft:${P}`, '{"rev":2}');
out.reEditDirty = leave.designDirty(P);
choice = "discard";
out.discardLeave = await guard();
out.left = {
crossdesign: session.getItem(`aislo:draft:crossdesign:${P}:7`),
alignment: session.getItem(`aislo:draft:alignment-draft:${P}:7`),
routeDraft: session.getItem(`aislo:draft:route-draft:${P}`),
selection: session.getItem(`aislo:draft:selection:${P}`),
stdCross: session.getItem(`aislo:draft:std-cross:${P}`),
b08: session.getItem(`aislo:draft:b08-materials:${P}`),
};
out.afterDiscardDirty = leave.designDirty(P);
// 페이지가 화면에서 빠짐 — 안 물음
session.setItem(`aislo:draft:crossdesign:${P}:7`, '{"40.000":{}}');
root.isConnected = false;
const askedGone = asked.length;
out.goneLeave = await guard();
out.goneUnload = unloadBlocked();
out.askedGone = asked.length - askedGone;
process.stdout.write(JSON.stringify(out));
})();