fix(b06): 횡단 보기 반폭 [적용] = 요청값만 — 교차점 맞춤 폭으로 누를 때마다 재생성하던 옛 줄 지움(173-6)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
This commit is contained in:
2026-10-10 08:47:40 +09:00
co-authored by Claude Opus 5.5
parent 3f82ea259f
commit 3e20341810
4 changed files with 102 additions and 47 deletions
@@ -0,0 +1,50 @@
/* 횡단 보기 반폭 [적용](PLAN 173-6) 단위검증 헬퍼 — `createSampleWidener` 를 그 자리에서 트랜스파일해 돌린다.
* 보유 샘플(20 m) 안 요청은 재생성 없이 true · 넘는 요청만 재생성 한 번. 결과는 표준출력에 JSON 한 벌.
* 짝 = `test_173_6_half_width_apply.py`.
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const ROOT = path.join(__dirname, "..", "..");
const calls = { regenerate: [], overlay: 0 };
const STUBS = {
"@ui/ui_template_locale": {
currentLanguageIndex: 0,
ui_locales: new Proxy({}, { get: () => [""] }),
},
"@ui/ui_template_elements": {
showLoadingOverlay: () => calls.overlay++,
hideLoadingOverlay: () => {},
showToast: () => {},
},
"./B06_Section_Api_Fetch": {
regenerateSections: async (_p, _r, width) => calls.regenerate.push(width),
fetchSectionDetail: async () => ({ cross_sections: [] }),
},
"./B06_Section_Section_Store": { replaceSectionDetail: () => {} },
};
const file = path.join(ROOT, "B06_Section", "B06_Section_UI_Page_Common.ts");
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
new Function("exports", "module", "require", js)(box.exports, box, (r) => STUBS[r]);
(async () => {
let sampled = 20;
const widen = box.exports.createSampleWidener({
target: () => ({ projectId: "p", routeId: 1 }),
sampledHalfWidth: () => sampled,
applyDetail: () => (sampled = calls.regenerate.at(-1)),
});
const out = {};
out.within = [await widen(10), await widen(15), await widen(20)];
out.withinCalls = calls.regenerate.length;
out.over = await widen(25);
out.overCalls = [...calls.regenerate];
out.again = await widen(25); // 넓힌 뒤 같은 값은 재생성 없음
out.againCalls = calls.regenerate.length;
process.stdout.write(JSON.stringify(out));
})();
@@ -0,0 +1,48 @@
"""173-6 횡단 보기 반폭 [적용] — 요청값만으로 샘플 폭을 잼(교차점 맞춤 폭 안 씀).
원지반 못 만나는 측점이 있으면 누를 때마다 서버 재생성하던 옛 줄(`maxToeFitHalfWidth`)을 지움 →
보유 샘플(20 m) 넘는 값일 때만 재생성 · 나머지는 카드 다시 그리기만.
소스(`design_view_cross.ts` · `B06_Section_UI_Cross_Fit.ts`) + `createSampleWidener` 를 돌린 값
(`helper_173_6_half_width.cjs`).
"""
import json
import subprocess
from pathlib import Path
import pytest
HERE = Path(__file__).parent
ROOT = HERE.parents[1]
DVC = (ROOT / "A00_Common" / "design" / "design_view_cross.ts").read_text(encoding="utf-8")
FIT = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Fit.ts").read_text(encoding="utf-8")
def _apply_body() -> str:
at = DVC.index("async function applyCrossHalfWidth")
return DVC[at : DVC.index("\n }\n", at)]
def test_적용은_요청값만_넘김() -> None:
body = _apply_body()
assert "ensureSampledWidth(requested)" in body
assert "maxToeFitHalfWidth" not in DVC and "Math.max" not in body
def test_교차점_맞춤_폭_함수_지움() -> None:
assert "maxToeFitHalfWidth" not in FIT and "toeFitHalfWidth" not in FIT
@pytest.mark.skipif(not (ROOT / "config" / "node_modules").is_dir(), reason="의존성 미설치")
def test_보유_폭_안은_재생성_없음_넘을_때만_한_번() -> None:
done = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(HERE / "helper_173_6_half_width.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
)
assert done.returncode == 0, done.stderr
out = json.loads(done.stdout)
assert out["within"] == [True, True, True] and out["withinCalls"] == 0
assert out["over"] is True and out["overCalls"] == [25]
assert out["again"] is True and out["againCalls"] == 1