From e32229feff05f22e85709b93082b460941aba2b5 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 6 Oct 2026 01:27:57 +0900 Subject: [PATCH] =?UTF-8?q?test(52-13):=20=EB=AA=85=EC=84=B8=20=ED=8F=BC?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=8B=9C=EB=82=98=EB=A6=AC=EC=98=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=C2=B7=2052-11=20=C2=B7=2052-15=20?= =?UTF-8?q?=EB=82=A1=EC=9D=80=20=EA=B8=B0=EC=A4=80=20=ED=95=9C=20=EC=A4=84?= =?UTF-8?q?=EC=94=A9=20=EA=B3=A0=EC=B9=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 52-13_예외: 빈 값 · 오가기 · 종류 바꾸기 · 여러 개 컨테이너 - 52-11: 보이는 명세 폼을 집도록 - 52-15: 현재 검증 프로젝트 id 를 읽도록 Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7 --- .../tester/ui_checks/52-11_정의_이름고치기.js | 2 +- resources/tester/ui_checks/52-13_예외.js | 189 ++++++++++++++++++ .../tester/ui_checks/52-15_같은측점_고르기.js | 2 +- 3 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 resources/tester/ui_checks/52-13_예외.js diff --git a/resources/tester/ui_checks/52-11_정의_이름고치기.js b/resources/tester/ui_checks/52-11_정의_이름고치기.js index 8cffe5b2b..125dd3622 100644 --- a/resources/tester/ui_checks/52-11_정의_이름고치기.js +++ b/resources/tester/ui_checks/52-11_정의_이름고치기.js @@ -214,7 +214,7 @@ const li = $$(".b05-route__irregular-list li").find((l) => /배관 1$/.test(l.textContent.trim()), ); - const spec = () => $(".b05-structure__spec", sec); + const spec = () => $$(".b05-structure__spec", sec).find((n) => n.offsetParent !== null); // 명세 폼이 종류마다 여럿 — 보이는 것 (li.querySelector("button") ?? li).click(); await W(800); if (!(spec() && spec().offsetParent !== null)) (li.querySelector("button") ?? li).click(); diff --git a/resources/tester/ui_checks/52-13_예외.js b/resources/tester/ui_checks/52-13_예외.js new file mode 100644 index 000000000..f3c60e262 --- /dev/null +++ b/resources/tester/ui_checks/52-13_예외.js @@ -0,0 +1,189 @@ +/* 52-13 — 명세 폼 예외 모음(배관 1 · BOX암거 · 세월교 1) — 빈 값 · 오가기 · 종류 바꾸기 · 여러 개 + * 시작 화면: B05 종단설계(#/b05-profile) · 검증 프로젝트 · 목록에 「배관 1」 「세월교 1」 · 로그인 상태 + * 부르는 법: 단계마다 한 번씩 — 앞에 `window.__m5213 = "단계";` 를 붙여 + * cache → 저장 안 하고 B05 → B06 → B05 오가기(캐시 값 그대로) · 종류 바꾸기(배관 → BOX → 배관) + * pipe → 배관 길이 · 전 · 후 비움 + 흙막이 추가 셋 + 도수로/돌붙임 하나 → [저장] + * (orca reload) pipe_v → 다시 열기 · 흙막이 수 3 · 비운 칸 그대로 + * bf → 258.12 를 BOX암거로(PUT) · 가로 비움 · 세월교 1 월류 폭 비움 → [저장] + * (orca reload) bf_v → 다시 열기 · 오류 없음 + * restore → 원래 관 지점으로 되돌림(PUT) · 초안 비움 + * 쓰는 것: 검증 프로젝트 pipe_points.json(되돌림 단계가 원래 값으로 다시 씀) + * 기대 수치: errors 0 · cache.same true · kind.leak 0 · soilCount 3 · inletBlank 빈 칸 셋 · restored true + * (배관 도수로/돌붙임 [추가] 는 하나 뒤에도 보임 — 「하나만」은 물넘이 포장 · 기타만 · 52-3 · 52-10) + */ +(async () => { + const MODE = window.__m5213 || "cache"; + const w = (ms) => new Promise((r) => setTimeout(r, ms)); + const until = async (fn, ms = 20000) => { + for (let t = 0; t < ms; t += 200) { + if (fn()) return true; + await w(200); + } + return false; + }; + const errors = []; + const onErr = (e) => errors.push(String(e.message ?? e.reason ?? e)); + window.addEventListener("error", onErr); + window.addEventListener("unhandledrejection", onErr); + const projectId = localStorage.getItem("frd_current_project_id"); + const modUrl = (part) => + performance + .getEntriesByType("resource") + .map((e) => e.name) + .filter((n) => n.includes(part)) + .pop(); + const fetchApi = await import(modUrl("/B04_PreProcess/B04_PreProcess_Api_Fetch.ts")); + const spec = () => + [...document.querySelectorAll(".b05-structure__spec")].find((n) => n.offsetParent !== null); + const box = (c, i = 0) => spec()?.querySelectorAll(`[data-spec-container="${c}"]`)[i]; + const ctl = (c, item, i = 0) => + box(c, i)?.querySelector(`[data-spec-item="${c}.${item}"]`)?.querySelector("select, input"); + const set = async (c, item, v, i = 0) => { + const el = ctl(c, item, i); + el.value = v; + el.dispatchEvent(new Event("change", { bubbles: true })); + await w(200); + }; + const clearDrafts = () => { + for (const k of Object.keys(sessionStorage)) + if (k.startsWith("aislo:draft:pipes:")) sessionStorage.removeItem(k); + }; + const pick = async (re) => { + const find = () => + [...document.querySelectorAll(".b05-route__irregular-list li")].find((l) => + re.test(l.textContent.trim()), + ); + await until(() => !!find()); + const li = find(); + (li.querySelector("button") ?? li).click(); + await until(() => !!spec(), 6000); + if (!spec()) (li.querySelector("button") ?? li).click(); + await until(() => !!spec()); + await w(500); + }; + const save = async () => { + document.querySelector('[data-dock-action="save"]').click(); + await w(500); + return until(() => !document.querySelector(".ui-overlay.is-active"), 60000); + }; + const items = () => [...spec().querySelectorAll("[data-spec-item]")].map((n) => n.dataset.specItem); + const point = async (lo, hi) => + (await fetchApi.fetchDetailPipePoints(projectId)).pipe_points.find( + (p) => p.chainage_m > lo && p.chainage_m < hi, + ); + const out = { mode: MODE }; + + if (MODE === "cache") { + await pick(/배관 1$/); + await set("inlet", "structure", "기슭막이"); + await set("inlet", "length", "12"); + out.before = ctl("inlet", "length").value; + location.hash = "#/b06-section"; + await w(7000); + location.hash = "#/b05-profile"; + await w(7000); + await pick(/배관 1$/); + out.after = ctl("inlet", "length")?.value; + out.same = out.before === out.after; + clearDrafts(); + } + + if (MODE === "pipe") { + sessionStorage.setItem("__5213_original", JSON.stringify((await fetchApi.fetchDetailPipePoints(projectId)).pipe_points)); + await pick(/배관 1$/); + await set("inlet", "structure", "기슭막이"); + await set("inlet", "form", "돌망태"); + await set("inlet", "length", ""); + await set("inlet", "before", ""); + await set("inlet", "after", ""); + for (let i = 0; i < 3; i++) { + spec().querySelector('[data-spec-add="soil_add"]').click(); + await w(200); + } + for (let i = 0; i < 3; i++) { + await set("soil_add", "structure", "기슭막이", i); + await set("soil_add", "form", "콘크리트", i); + } + spec().querySelector('[data-spec-add="chute_add"]').click(); + await w(200); + await set("chute_add", "structure", "돌붙임"); + out.soilCount = spec().querySelectorAll('[data-spec-container="soil_add"]').length; + out.saved = await save(); + const p = await point(80, 90); + out.file = p && p.options; + } + + if (MODE === "pipe_v") { + await pick(/배관 1$/); + out.soilCount = spec().querySelectorAll('[data-spec-container="soil_add"]').length; + out.chuteAdd = !!spec().querySelector('[data-spec-add="chute_add"]'); + out.inletBlank = ["length", "before", "after"].map((k) => ctl("inlet", k)?.value); + } + + if (MODE === "bf") { + const orig = (await fetchApi.fetchDetailPipePoints(projectId)).pipe_points; + if (!sessionStorage.getItem("__5213_original")) + sessionStorage.setItem("__5213_original", JSON.stringify(orig)); + const pts = JSON.parse(JSON.stringify(orig)).map((p) => + Math.abs(p.chainage_m - 258.12) < 0.05 + ? { ...p, facility: "box_culvert", options: { body_width_m: 3, body_height_m: 2.5 } } + : p, + ); + await fetchApi.saveDetailPipePoints(projectId, pts); + clearDrafts(); + out.ready = true; + } + + if (MODE === "bf_edit") { + await pick(/BOX암거$/); + await set("body", "size", "사용자 입력"); + await set("body", "width", ""); + out.boxSaved = await save(); + out.boxFile = (await point(250, 260))?.options; + await pick(/세월교 1$/); + await set("ford", "width", ""); + out.fordSaved = await save(); + out.fordFile = (await point(170, 176))?.options; + } + + if (MODE === "bf_v") { + await pick(/BOX암거$/); + out.box = { size: ctl("body", "size")?.value, width: ctl("body", "width")?.value }; + await pick(/세월교 1$/); + out.ford = { width: ctl("ford", "width")?.value, height: ctl("ford", "height")?.value }; + } + + if (MODE === "kind") { + const sec = document.querySelector(".b05-structure-section"); + const sel = () => sec.querySelectorAll(".b05-structure__grid select"); + const fire = (el, v) => { + el.value = v; + el.dispatchEvent(new Event("change", { bubbles: true })); + }; + const seen = {}; + for (const t of ["pipe", "box_culvert", "pipe"]) { + fire(sel()[0], "A"); + await w(300); + fire(sel()[1], t); + await w(600); + seen[t + "#" + Object.keys(seen).length] = items().join(","); + } + const vals = Object.values(seen); + out.seen = vals; + out.leak = vals[0] === vals[2] && !/body\./.test(vals[0]) && !/pipe\./.test(vals[1]) ? 0 : 1; + } + + if (MODE === "restore") { + const original = JSON.parse(sessionStorage.getItem("__5213_original") || "null"); + if (!original) return JSON.stringify({ error: "원래 값 없음" }); + await fetchApi.saveDetailPipePoints(projectId, original); + clearDrafts(); + sessionStorage.removeItem("__5213_original"); + const now = (await fetchApi.fetchDetailPipePoints(projectId)).pipe_points; + out.restored = JSON.stringify(now.map((p) => [p.chainage_m, p.facility ?? null, p.options ?? null])) === + JSON.stringify(original.map((p) => [p.chainage_m, p.facility ?? null, p.options ?? null])); + } + + out.errors = errors; + return JSON.stringify(out); +})(); diff --git a/resources/tester/ui_checks/52-15_같은측점_고르기.js b/resources/tester/ui_checks/52-15_같은측점_고르기.js index 0dfeabe36..605392815 100644 --- a/resources/tester/ui_checks/52-15_같은측점_고르기.js +++ b/resources/tester/ui_checks/52-15_같은측점_고르기.js @@ -44,7 +44,7 @@ }; const pickKey = () => Object.keys(sessionStorage).find((k) => k.includes("structure-pick") && k.includes(PROJECT)); - const PROJECT = "936be972-11bc-46c2-8bf3-b15d8de7df0d"; + const PROJECT = localStorage.getItem("frd_current_project_id"); // 환경마다 검증 프로젝트가 다름 const picked = () => { const raw = pickKey() ? sessionStorage.getItem(pickKey()) : null; let sid = null;