Files
Aislo/resources/tester/test_ui_loading.py
T
eomsangdonandClaude Opus 5.5 bcb1c725c4 refactor(M02): 항목 카드 넷 공용 틀 CardShell (PLAN 31-7)
- 공용 틀 — 제목 줄(제목 · 저장 안 한 점 ● · 오른쪽 단추 자리) + 한 줄 부제(번호 · 이름 · 말줄임) · 상태(불러오는 중 · 실패 + 다시 불러오기 · 비었음) · [저장](늘 보임 · 고쳐야 켜짐 · 카드 안 Ctrl+S · 알림 글 한 벌) · ?(단축키 상자)
- 도면 정보 · 면적산출 · 재료산출(ItemCards) · 선택 입력(관리 화면 · 고르기 모달 값 카드)이 틀에 내용만 넣음
- 「〇〇 수정」 빈 단추 한 모양 · 엑셀 카드에도 ? · 불러오는 중 네 카드 · 실패는 카드 안 글(토스트 안 씀) · 물음 한 번(어느 카드든)
- 저장 길(saveTemplate · 도면 write · sheetEdit.save · 위 [저장] saveInputs) · 단축키는 그대로 · 고르기 모달은 보기만
- 시험 test_m02_card_shell 새로 · 옛 모양 시험 맞춤

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 21:24:49 +09:00

86 lines
3.9 KiB
Python

"""컨테이너 안 「불러오는 중」(PLAN 30-6 · `ui_template_loading.ts`) — 0.3초 · 실패 글 · M02 자리.
① `delayedShow` 를 Node 로 가짜 시계로 돌림 — 0.3초 전에 끝나면 안 보임(깜빡임 없음) · 넘으면 보이고
끝나면 걷힘 · 끝낸 뒤 시계가 와도 안 보임.
② 실패 자리 = 까닭 글(「불러오지 못함 — 까닭」) + [다시 불러오기] · 화면 전체 잠금 안 씀.
③ M02 나무 · 상세(표 · 도면) · 조합 목록 · 조합 상세 · 항목 카드가 이 부품을 씀.
"""
from __future__ import annotations
import json
import re
import shutil
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
LOADING = ROOT / "ui_template" / "ui_template_loading.ts"
M02 = ROOT / "M02_MasterTemplete"
def _text(path: Path) -> str:
return path.read_text(encoding="utf-8")
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
def test_0점3초_넘을_때만_보임():
found = re.search(r"^export function delayedShow[\s\S]*?^}", _text(LOADING), re.M)
assert found, "delayedShow 를 못 찾음"
script = (
"const LOADING_DELAY_MS = 300;\n"
+ found.group(0).replace("export ", "")
+ """
let now = 0; const jobs = [];
const timer = {
set: (fn, ms) => { jobs.push({ at: now + ms, fn, live: true }); return jobs.length - 1; },
clear: (id) => { if (jobs[id]) jobs[id].live = false; },
};
const tick = (ms) => {
now += ms;
for (const j of jobs) if (j.live && j.at <= now) { j.live = false; j.fn(); }
};
const log = [];
const on = (n) => () => log.push(n + ":show"); const off = (n) => () => log.push(n + ":hide");
const fast = delayedShow(on("fast"), off("fast"), undefined, timer);
tick(200); fast(); tick(500);
const slow = delayedShow(on("slow"), off("slow"), undefined, timer);
tick(299); log.push("299"); tick(1); slow(); tick(500);
console.log(JSON.stringify(log));
"""
)
result = subprocess.run(
["node", "--experimental-strip-types", "--no-warnings",
"--input-type=module-typescript", "-e", script],
capture_output=True, text=True, encoding="utf-8", timeout=60,
) # fmt: skip
assert result.returncode == 0, result.stderr
assert json.loads(result.stdout) == ["299", "slow:show", "slow:hide"]
def test_실패_글과_다시_불러오기_M02_자리():
src = _text(LOADING)
assert 'reason ? `${t("Common_Load_Failed")} — ${reason}` : t("Common_Load_Failed")' in src
assert 'createButton({ label: t("Common_Reload")' in src and 'role: "alert"' in src
assert "showLoadingOverlay()" not in src # 칸 안만(화면 전체 잠금 안 부름)
# 브라우저 setTimeout 을 객체 메서드로 부르면 Illegal invocation — 감싼 기본값(ORCA 흠)
assert "set: (fn, ms) => setTimeout(fn, ms)," in src
assert "clear: (id) => clearTimeout(id)," in src
locale = _text(ROOT / "ui_template" / "ui_template_locale_common.ts")
assert 'Common_Load_Failed: ["불러오지 못함"' in locale
assert 'Common_Reload: ["다시 불러오기"' in locale
tree = _text(M02 / "M02_MasterTemplete_TreePanel.ts")
assert "const stop = showLoading(body);" in tree
assert "loadingError(why(error), () => void refresh())" in tree
main = _text(M02 / "M02_MasterTemplete_UI_Main.ts")
assert "const stop = showLoading(host);" in main
assert "loadingError(why, () => void open(next))" in main
edit = _text(M02 / "M02_MasterTemplete_Labor_Edit.ts")
assert "loadingError(reason(error), () => void open(key))" in edit
assert "(current ? () => {} : showLoading(view))" in edit
assert "const stop = editor.loading();" in _text(M02 / "M02_MasterTemplete_Labor.ts")
assert "cards.map((c) => c.shell.loading())" in _text(M02 / "M02_MasterTemplete_ItemCards.ts")
assert "loading: () => showLoading(host)," in _text(M02 / "M02_MasterTemplete_CardShell.ts")