- 공용 부품 ui_template_loading(showLoading · loadingError · delayedShow) — 칸 안 작은 회전 표시 + 「불러오는 중...」 · 화면 전체 잠금 아님 · 다른 페이지도 씀 - 붙인 자리 — 좌측 나무(구조물 · 일위대가 · 사람 나무) · 상세 칸(구조물 표 · 도면 · 면적 · 재료) · 조합 목록 · 조합 상세 · 항목 카드 - 공용 글 Common_Load_Failed · Common_Reload - 시험 test_ui_loading(0.3초 규칙 가짜 시계 · 실패 글 · 붙은 자리) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
3.8 KiB
Python
85 lines
3.8 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 "showLoading(host)" in _text(M02 / "M02_MasterTemplete_ItemCards.ts")
|