Files
Aislo/resources/tester/test_171_2_group_cards.py
T

161 lines
7.7 KiB
Python

"""171-2 묶음 카드 공용 양식(`ui_template_group_cards`) — Node(타입 지움) + 작은 가짜 DOM.
- 머리 = 호표 · 명칭 · 규격 · 단위 · 합계 / 몸 = 이름 · 규격 · 수량 · 단위 · 합계 · 비고 / 합계 줄 = 노무 · 재료 · 경비 · 계
- 줄 금액 = 합계만 · 비목 셋 = 풍선 · 숫자 오른쪽 · 글자 14px 한 벌 · 줄 간격 좁게(공용 카드 16px 끼움 없음)
- 가로 열 수 1~4(기본 2 · 고르면 알림) · 접기 없음(181-2) · 이동해 온 박스 = `is-pick`(붉은 외곽선) · 머리 누름 = 이동
- 157-2 산근 카드 파일 = 이 양식으로 갈음(지움)
"""
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from resources.tester.helper_b09_group_cards import COMMON, run # noqa: E402
GROUPS_JS = """
const mk = (n) => ({
key: `G${n}`, at: n * 10, no: `제 ${n} 호표`, name: `묶음${n}`, spec: "규격", specTip: "원문번호 1",
unit: "m3", sum: 1234.5,
lines: [
{ at: n * 10 + 1, name: "석공", spec: "", qty: 0.072, unit: "인", sum: 18643.3,
parts: [18643.3, null, null], note: "노무3", link: true },
{ at: n * 10 + 2, name: "인용", tag: "품셈" },
],
foot: { at: n * 10 + 3, parts: [100, 20, 3], sum: 123, note: "빈 줄 1", tip: "빈 줄 — 모래" },
});
const picks = [];
const cols = [];
const make = (count, extra = {}) => createGroupCards({
groups: Array.from({ length: count }, (_, i) => mk(i + 1)),
onPick: (at) => picks.push(at), onColumns: (n) => cols.push(n), ...extra,
});
"""
def _run(body):
return run([COMMON], GROUPS_JS + body)
def test_도우미_열수_요약_풍선():
out = _run(
"\nconsole.log(JSON.stringify({"
" cols: [0, 1, 2, 3, 4, 5, '3', null, undefined].map(clampColumns),"
" tip: [partsTip([1000, 0, null]), partsTip([null, null, null]), partsTip(null)] }));"
)
assert out["cols"] == [2, 1, 2, 3, 4, 2, 2, 2, 2]
assert out["tip"] == ["노무 1,000 · 재료 0 · 경비 -", None, None]
def test_카드_머리_몸_합계_줄():
out = _run(
"\nconst root = make(1);"
"\nconst box = root.querySelector('.ui-group-card');"
"\nconst head = box.querySelector('.ui-group-card__head');"
"\nconst tds = box.querySelector('tbody').children[0].children;"
"\nconst ths = box.querySelector('thead').children[0].children;"
"\nconsole.log(JSON.stringify({"
" head: head.children.map((c) => [c.className, c.textContent, c.title]),"
" ths: ths.map((c) => [c.textContent, c.className]),"
" tds: tds.map((c) => [c.textContent, c.className, c.title]),"
" tag: box.querySelector('.ui-group-card__tag').textContent,"
" foot: box.querySelector('.ui-group-card__foot').children.map((c) => c.textContent),"
" link: box.querySelector('tbody').children.map((r) => r.classList.contains('is-link')),"
" cols: root.querySelector('.ui-group-cards__grid').style.props['--group-cols'],"
" summary: root.all('.ui-btn').map((b) => b.textContent) }));"
)
assert out["head"] == [
["ui-group-card__no", "제 1 호표", ""],
["ui-group-card__title", "묶음1", ""],
["ui-group-card__spec", "규격", "원문번호 1"],
["ui-group-card__unit", "m3", ""],
["ui-group-card__total", "1,234.5", ""],
]
assert out["ths"] == [
["이름", ""], ["규격", ""], ["수량", "is-num"], ["단위", ""], ["합계", "is-num"], ["비고", ""],
] # fmt: skip
# 줄 금액 = 합계만 · 비목 셋 = 풍선 · 숫자 칸 = 오른쪽(is-num)
assert out["tds"] == [
["석공", "ui-group-card__name", ""],
["", "", ""],
["0.1", "is-num", ""],
["인", "", ""],
["18,643.3", "is-num", "노무 18,643.3 · 재료 - · 경비 -"],
["노무3", "ui-group-card__note", ""],
]
assert out["tag"] == "품셈"
assert out["foot"] == ["노무 100", "재료 20", "경비 3", "계 123", "빈 줄 1"]
assert out["link"] == [True, False]
assert out["cols"] == "2" # 기본 2
assert out["summary"] == ["1", "2", "3", "4"] # 가로 열 수 단추뿐(요약 · 접기 단추 없음)
def test_가로_열수_고름_알림_누름_이동():
out = _run(
"\nconst root = make(2, { columns: 3 });"
"\nconst grid = root.querySelector('.ui-group-cards__grid');"
"\nconst before = grid.style.props['--group-cols'];"
"\nroot.querySelector('[data-group-cols=\"4\"]').click();"
"\nroot.querySelector('[data-at=\"21\"]').click();"
"\nroot.querySelector('[data-at=\"20\"]').click();"
"\nconsole.log(JSON.stringify({ before, after: grid.style.props['--group-cols'], cols,"
" pressed: root.all('[data-group-cols]').map((b) => b.attrs['aria-pressed']), picks }));"
)
assert out["before"] == "3" and out["after"] == "4"
assert out["cols"] == [4]
assert out["pressed"] == ["false", "false", "false", "true"]
assert out["picks"] == [21, 20] # 줄 · 머리 누름 = 표 줄 번호 그대로(갈 곳은 부르는 쪽 link)
def test_묶음_많아도_접힘_없음_고른_박스_붉은_외곽선():
out = _run(
"\nconst root = make(13, { focus: 52 });"
"\nconst cards = root.all('.ui-group-card');"
"\nconst focused = root.querySelector('[data-at=\"52\"]');"
"\nconst first = cards.map((c) => c.classList.contains('is-pick'));"
"\ncards[0].querySelector('.ui-group-card__head').click();"
"\nconsole.log(JSON.stringify({ first, picks,"
" closed: cards.map((c) => c.classList.contains('is-closed')),"
" buttons: root.all('.ui-btn').map((b) => b.textContent),"
" foot: cards.every((c) => c.querySelector('.ui-group-card__foot')),"
" focus: [focused.classList.contains('is-focus'), cards[4].scrolled === true] }));"
)
# 이동해 온 줄(5번째 묶음 줄) = 그 박스만 붉은 외곽선 · 그 줄 강조 · 박스 스크롤
assert out["first"] == [False] * 4 + [True] + [False] * 8
assert out["focus"] == [True, True]
assert out["closed"] == [False] * 13 # 13 묶음도 접힘 없음
assert out["picks"] == [10] # 머리 누름 = 이동(표 줄 번호 그대로)
assert out["buttons"] == ["1", "2", "3", "4"] # 모두 펼침 · 접기 단추 없음
assert out["foot"] is True
def test_고른_박스_없으면_외곽선_없음():
out = _run(
"\nconst root = make(3);"
"\nconsole.log(JSON.stringify(root.all('.ui-group-card').map("
"(c) => c.classList.contains('is-pick'))));"
)
assert out == [False, False, False]
def test_양식_글자_간격_숫자():
css = (ROOT / "ui_template" / "ui_template_group_cards.css").read_text("utf-8")
theme = (ROOT / "ui_template" / "ui_template_theme.css").read_text("utf-8")
assert "--text-body-sm: 14px;" in theme
assert "font-size: var(--text-body-sm);" in css # 14px 한 벌
assert [ln.strip() for ln in css.splitlines() if "font-size" in ln] == [
"font-size: var(--text-body-sm);",
"font-size: inherit;",
]
assert "padding: 1px var(--spacing-4);" in css # 줄 간격 좁게
assert "is-closed" not in css and "is-closed" not in (ROOT / COMMON).read_text("utf-8")
assert "border-color: var(--color-danger);" in css # 고른 박스 = B06 고름 꼴(181-2)
assert "spacing-16" not in css and "card-padding" not in css # 공용 카드 16px 끼움 없음
assert "grid-template-columns: repeat(var(--group-cols, 2), minmax(0, 1fr));" in css
assert "text-align: right;" in css
src = (ROOT / COMMON).read_text("utf-8")
assert "createCard" not in src
assert not (ROOT / "B09_Estimation" / "B09_Estimation_UI_Tabs_Sangeun_Cards.ts").exists()