From f0745f714d75ccf1542e269136616816193f3084 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 5 Oct 2026 16:22:25 +0900 Subject: [PATCH] =?UTF-8?q?test(M02):=2048-2=20=EC=A0=95=EC=9D=98=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=8B=9C=EB=82=98=EB=A6=AC=EC=98=A4=20?= =?UTF-8?q?=C2=B7=20=EC=A2=85=EB=A5=98=20=EC=A4=84=20=C2=B7=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EC=A4=84=20=EC=95=88=20=EC=A0=91=ED=9E=98=20=C2=B7?= =?UTF-8?q?=2048-1=20=EC=8B=9C=EB=82=98=EB=A6=AC=EC=98=A4=20=EC=83=88=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EA=B3=A0=EB=A6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt --- .../StructOptions/M02_SO_Style.css | 25 ++- .../tester/ui_checks/48-1_구조물정의_읽기.js | 10 +- .../ui_checks/48-2_M02_구조물정의_화면.js | 145 ++++++++++++++++++ 3 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 resources/tester/ui_checks/48-2_M02_구조물정의_화면.js diff --git a/M02_MasterTemplete/StructOptions/M02_SO_Style.css b/M02_MasterTemplete/StructOptions/M02_SO_Style.css index 80d3e4cec..a8570c86a 100644 --- a/M02_MasterTemplete/StructOptions/M02_SO_Style.css +++ b/M02_MasterTemplete/StructOptions/M02_SO_Style.css @@ -156,8 +156,19 @@ font-weight: 600; } +.m02-sod__kindrow { + flex-wrap: nowrap; +} + .m02-sod__kindrow > .m02-opts__kind { flex: 1 1 auto; + min-width: 0; +} + +.m02-sod__kindrow > button:not(.m02-opts__kind), +.m02-sod__family > button { + flex: none; + white-space: nowrap; } .m02-sod__block { @@ -219,9 +230,21 @@ align-items: start; } +.m02-sod__place { + flex-wrap: nowrap; +} + .m02-sod__placename { - flex: 1 1 8rem; + flex: 1 1 6rem; min-width: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.m02-sod__place > .m02-sod__num { + flex: none; + width: 4rem; } .m02-sod__grid { diff --git a/resources/tester/ui_checks/48-1_구조물정의_읽기.js b/resources/tester/ui_checks/48-1_구조물정의_읽기.js index 306517a2f..b66fdfe35 100644 --- a/resources/tester/ui_checks/48-1_구조물정의_읽기.js +++ b/resources/tester/ui_checks/48-1_구조물정의_읽기.js @@ -5,7 +5,7 @@ * - def = { 판 ≥ 1, types: 37, options: 235 }(GET /api/m02/structure-definition) * - types = { types: 37, options: 235, visibleAll: true, pipeGroups: ["관", "관 보호공(유입)", "관 보호공(유출)"] } * (GET /api/projects/structure-types — 옛 꼴 그대로) - * - 좌측 「구조물 옵션 보이기」 → 종류 단추 kinds = 37(옵션 없는 종류도 · 옛 화면 그대로) + * - 좌측 「구조물 옵션 정의」 → 종류 단추 kinds = 37(옵션 없는 종류도 · 48-2 정의 화면) * · pipe 단추에 그룹 표지 「3」 */ (async () => { @@ -41,14 +41,14 @@ pipeGroups: pipe.groups.map((g) => g.name), }; const row = await until(() => $("[data-options-row]")); - if (!row) return JSON.stringify({ ...out, error: "옵션 보이기 줄 없음" }); + if (!row) return JSON.stringify({ ...out, error: "정의 줄 없음" }); row.click(); - await until(() => $$("[data-options-kind]").length); - const kinds = $$("[data-options-kind]"); + await until(() => $$("[data-sod-kind]").length); + const kinds = $$("[data-sod-kind]"); out.screen = { kinds: kinds.length, withOptions: def.types.filter((t) => t.options.length).length, - pipeTag: $('[data-options-kind="pipe"]')?.innerText.replace(/\s+/g, " ").trim() ?? null, + pipeTag: $('[data-sod-kind="pipe"]')?.innerText.replace(/\s+/g, " ").trim() ?? null, }; out.ok = out.def.types === 37 && diff --git a/resources/tester/ui_checks/48-2_M02_구조물정의_화면.js b/resources/tester/ui_checks/48-2_M02_구조물정의_화면.js new file mode 100644 index 000000000..c5f3b47fd --- /dev/null +++ b/resources/tester/ui_checks/48-2_M02_구조물정의_화면.js @@ -0,0 +1,145 @@ +/* 48-2 — M02 구조물 옵션 정의 편집 화면(군 · 종류 · 옵션 · 선택지 · 배치 격자 · 그룹 형상 · 규칙 · 지난 판) + * 시작 화면: M02 마스터 템플릿 · 마스터 층(#/m02-master-template?root=master) · 시스템 관리자 + * 부르는 법: orca eval --expression "$(cat 이 파일)" (async 식 · JSON 글을 돌려줌 · 20초 안) + * 쓰는 것: 없음 — 화면 사본만 고치고 [저장] 안 누름(저장 길은 test_m02_structure_def_screen.py 가 사본으로) · + * 끝에 판이 그대로인지 GET 으로 봄 · 화면을 다시 띄우면 고침은 사라짐 + * 기대 수치: + * - families = 구조물군 수 · kinds = 37 · pipe 줄 options = pipe 옵션 수 · cells = 쓰는 옵션 수 · base = true + * - 이름 바꿈 → 왼쪽 단추 글 따라감 · [저장] 켜짐 + * - 선택지 펼침 = 3(흄관 · VR관 · 파형강관) · 「흄관」 → 「흄관X」 = 기본값 고르기에도 「흄관X」 + * - 너비 2 → 미리보기 span 2 · 겹치게 두면 issues 에 「배치 겹침」 · [저장] 꺼짐 · 되돌리면 사라짐 + * - 기준 측점 끔 → 미리보기 기준 측점 칸 0 + * - 그룹 형상 「길이」 켬 → 뜻 칸 열림 + * - [규칙 더함] → 규칙 줄 1 · 빨강 아님 · 지우기 → 0 + * - [지난 판] → 목록 칸(판 단추 또는 「지난 판 없음」) + * - 끝 판 = 처음 판(저장 안 함) + */ +(async () => { + const W = (ms) => new Promise((r) => setTimeout(r, ms)); + const $ = (s, root = document) => root.querySelector(s); + const $$ = (s, root = document) => [...root.querySelectorAll(s)]; + const until = async (fn, ms = 8000) => { + for (let t = 0; t < ms; t += 120) { + const v = fn(); + if (v) return v; + await W(120); + } + return null; + }; + /** 칸 값 바꿈 — 글자 넣음(input) + 떠남(change) */ + const put = (box, value) => { + box.value = value; + box.dispatchEvent(new Event("input", { bubbles: true })); + box.dispatchEvent(new Event("change", { bubbles: true })); + }; + const tick = (box, on) => { + if (box.checked !== on) box.click(); + }; + const def = await ( + await fetch("/api/m02/structure-definition", { credentials: "include" }) + ).json(); + if (!def.types) return JSON.stringify({ error: "정의 못 읽음" }); + const pipe = def.types.find((t) => t.type_id === "pipe"); + const out = { 판: def.판 }; + + const row = await until(() => $("[data-options-row]")); + if (!row) return JSON.stringify({ error: "정의 줄 없음" }); + row.click(); + if (!(await until(() => $$("[data-sod-kind]").length))) + return JSON.stringify({ error: "종류 목록 없음" }); + out.families = [$$("[data-sod-family]").length, Object.keys(def.구조물군).length]; + out.kinds = $$("[data-sod-kind]").length; + $('[data-sod-kind="pipe"]').click(); + await until(() => $('[data-sod-option="pipe_kind"]')); + const liveOpts = pipe.options.filter((o) => o.enabled !== false).length; + out.pipe = { + options: [$$("[data-sod-option]").length, pipe.options.length], + cells: [$$("[data-sod-cell]").length, liveOpts], + base: !!$(".m02-sod__cell.is-base"), + }; + + // 이름 바꿈 → 왼쪽 단추 · [저장] 켜짐 + put($("[data-sod-kind-name]"), "배수관(시험)"); + out.rename = { + left: $('[data-sod-kind="pipe"]').innerText.includes("배수관(시험)"), + save: !$("[data-sod-save]").disabled, + }; + + // 선택지 펼침 · 이름 바꿈 → 기본값 고르기에도 + $('[data-sod-choices="pipe_kind"]').click(); + await until(() => $$("[data-sod-choice]").length); + out.choices = $$("[data-sod-choice]").map((r) => $("input", r).value); + put($('[data-sod-choice="흄관"] [data-sod-choice-name]'), "흄관X"); + const defaultPick = $('[data-sod-option="pipe_kind"] [data-sod-default]'); + out.choiceRename = [...defaultPick.options].some((o) => o.value === "흄관X"); + + // 배치 — 너비 2 · 겹침 · 되돌림 + put($('[data-sod-place-row="pipe_kind"] [data-sod-width]'), "2"); + const cell = $('[data-sod-cell="pipe_kind"]'); + out.width2 = cell.style.gridColumn.replace(/\s+/g, " "); + const other = pipe.options.filter((o) => o.enabled !== false)[1].key; + put($(`[data-sod-place-row="${other}"] [data-sod-row]`), "1"); + put($(`[data-sod-place-row="${other}"] [data-sod-col]`), "2"); + out.overlap = { + issue: $("[data-sod-issues]").innerText.includes("배치 겹침"), + red: $$(".m02-sod__cell.is-bad").length, + saveOff: $("[data-sod-save]").disabled, + }; + put($('[data-sod-place-row="pipe_kind"] [data-sod-width]'), "1"); + out.overlapGone = !$("[data-sod-issues]").innerText.includes("배치 겹침"); + + // 기준 측점 끔 + tick($("[data-sod-base]"), false); + out.baseOff = $$(".m02-sod__cell.is-base").length; + + // 그룹 형상 「길이」 켬 → 뜻 칸 열림 + const shape = $("[data-sog-shape]"); + const meanBefore = $(".m02-sog__mean", shape).disabled; + tick($("[data-sog-shape-0]", shape), true); + out.shape = { before: meanBefore, after: $(".m02-sog__mean", $("[data-sog-shape]")).disabled }; + + // 규칙 더함 · 지우기 + $("[data-sod-rule-add]").click(); + const rule = await until(() => $("[data-sod-rule]")); + out.rule = { + rows: $$("[data-sod-rule]").length, + bad: rule.classList.contains("is-bad"), + top: $("[data-sod-rule-top]", rule).value, + target: $("[data-sod-rule-target]", rule).value, + }; + [...$$("button", rule)].find((b) => b.innerText.trim() === "지우기").click(); + out.ruleGone = $$("[data-sod-rule]").length; + + // 지난 판 목록 + $("[data-sod-history-toggle]").click(); + await until(() => $("[data-sod-history]").children.length); + out.history = $("[data-sod-history]").innerText.replace(/\s+/g, " ").trim().slice(0, 80); + + const after = await ( + await fetch("/api/m02/structure-definition", { credentials: "include" }) + ).json(); + out.판그대로 = after.판 === def.판; + out.ok = + out.families[0] === out.families[1] && + out.kinds === 37 && + out.pipe.options[0] === out.pipe.options[1] && + out.pipe.cells[0] === out.pipe.cells[1] && + out.pipe.base && + out.rename.left && + out.rename.save && + out.choices.length === 3 && + out.choiceRename && + out.width2.includes("span 2") && + out.overlap.issue && + out.overlap.saveOff && + out.overlapGone && + out.baseOff === 0 && + out.shape.before === true && + out.shape.after === false && + out.rule.rows === 1 && + !out.rule.bad && + out.ruleGone === 0 && + out.history.length > 0 && + out.판그대로; + return JSON.stringify(out); +})();