- design_user_pick.ts 새 파일 — 사용자 고름 표시 한 칸(진짜 누름 안 · 묶음 차례 없음) - design_shared onReveal 한 곳이 그 칸만 봄 — 폼(고름 · 우클릭 추가)은 그대로 펴기를 부름 - design_page_data pageBusy — 묶음 차례가 떠 있나 - 배수유역 다시 나눔 응답 · 방향키 · 끌기 · 묶음 다시 돎의 다시 칠하기 = 안 폄 - 시험 test_398_1_reveal_user_pick(헬퍼 helper_398_1_user_pick.cjs) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
82 lines
3.7 KiB
JavaScript
82 lines
3.7 KiB
JavaScript
/* PLAN 398-1 단위검증 헬퍼 — 진짜 `design_user_pick.ts` + 진짜 `design_page_data.ts`(묶음 차례 · 「계산 중」)로
|
|
* 좌측 패널 펴기 한 곳(`design_shared` onReveal 과 같은 식)을 길마다 셈. 짝 = `test_398_1_reveal_user_pick.py`.
|
|
* 브라우저가 처리 중인 이벤트(`window.event`)는 `globalThis.event` 로 흉내. */
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const DESIGN = path.join(ROOT, "A00_Common", "design");
|
|
|
|
function load(file, stubs) {
|
|
const js = ts.transpileModule(fs.readFileSync(path.join(DESIGN, file), "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
new Function("exports", "module", "require", js)(box.exports, box, (name) => {
|
|
if (!stubs[name]) throw new Error(`stub 없음: ${name}`);
|
|
return stubs[name];
|
|
});
|
|
return box.exports;
|
|
}
|
|
|
|
const data = load("design_page_data.ts", {
|
|
"./design_page_route": { setPageRouteId: () => undefined, pageRouteId: () => null },
|
|
"../../B04_PreProcess/B04_PreProcess_Api_Fetch": { fetchDetailPipePoints: async () => ({}) },
|
|
"../../B05_Profile/B05_Profile_Api_Structures": {
|
|
fetchStructures: async () => ({}),
|
|
dropStaleStructureTypes: async () => false,
|
|
},
|
|
});
|
|
const pick = load("design_user_pick.ts", { "./design_page_data": data });
|
|
|
|
const P = "p1";
|
|
let reveals = 0;
|
|
/** 폼이 고른 것을 실을 때마다 부르는 펴기(`design_shared` onReveal 그대로). */
|
|
const onReveal = () => pick.isUserPick(P) && (reveals += 1);
|
|
/** 브라우저가 그 이벤트를 처리하는 동안(그 마이크로태스크까지) — 끝나면 이벤트 없음. */
|
|
async function during(event, body) {
|
|
globalThis.event = event;
|
|
try {
|
|
await body();
|
|
} finally {
|
|
globalThis.event = undefined;
|
|
}
|
|
}
|
|
const trusted = (type) => ({ type, isTrusted: true });
|
|
const count = async (event, body) => {
|
|
const before = reveals;
|
|
await during(event, body);
|
|
return reveals - before;
|
|
};
|
|
|
|
(async () => {
|
|
const out = {};
|
|
// 사용자 고름 — 종단 알약 · 횡단 카드(click) · 3D 부재(pointerup) · 우클릭 추가(contextmenu)
|
|
out.click = await count(trusted("click"), () => onReveal());
|
|
out.pointerup = await count(trusted("pointerup"), () => onReveal());
|
|
out.contextmenu = await count(trusted("contextmenu"), () => onReveal());
|
|
// 누름 밖 — 배수유역 다시 나눔 응답 · 횡단 다시 그림(서버 응답 · 타이머)
|
|
out.outside = await count(undefined, () => onReveal());
|
|
// 방향키로 교점 옮김 · 끌기 도중(pointermove)
|
|
out.arrow = await count(trusted("keydown"), () => onReveal());
|
|
out.drag = await count(trusted("pointermove"), () => onReveal());
|
|
// 스크립트가 낸 가짜 누름
|
|
out.synthetic = await count({ type: "click", isTrusted: false }, () => onReveal());
|
|
// 교점 끌기 놓음 · 곡선 지우기 · 되돌리기 단추 — 묶음 차례가 떠 그 마이크로태스크에서 관 · 구조물 따라가며 다시 칠함
|
|
let finish;
|
|
out.pipelineRepaint = await count(trusted("pointerup"), async () => {
|
|
data.trackPageBusy(P, new Promise((resolve) => (finish = resolve)));
|
|
await Promise.resolve();
|
|
onReveal(); // follow → 폼 다시 실음
|
|
});
|
|
out.busyPick = await count(trusted("click"), () => onReveal()); // 차례가 도는 사이 고름은 안 폄
|
|
finish();
|
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
out.afterRun = await count(trusted("click"), () => onReveal()); // 차례가 끝나면 다시 폄
|
|
process.stdout.write(JSON.stringify(out));
|
|
})().catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|