- 셸 = 위 머리 48(AISLO · 회사 이름 — 시스템 관리자 회사 전환 · 찾기 자리 · [?] · 알림 자리 · 사용자 메뉴) + 왼쪽 메뉴 210 + 챗봇 단추
- 등록부 B01_Dashboard_UI_Views.ts — { key, title, group, roles, icon, mount(host, ctx) } · 주소 ?view= · 같은 주소 안 이동 = 페이지만 갈아 끼움(MountedPage)
- 역할 넷(일반 · 회사 관리자 · 산림청 · 시스템 관리자) · 권한 없는 묶음 · 항목 숨김 · 권한 없는 열쇠 = 홈
- 열쇠마다 옛 구역 부품 그대로 얹음(B01_Dashboard_UI_Legacy.ts) — 기능 빠짐 0
- 옛 ☰ 서랍 · 구역 접기 · 회사 알약 걷음 — 테마 · 언어 · 터치 · 설정 · 로그아웃은 사용자 메뉴로
- 아이콘 = Tabler(MIT) 선 아이콘 몇 개(ui_template_icons.ts · 라이센스 글 함께)
- 시험 — test_b01_settings_cards 옛 한 페이지 단정(buildPage · 접힘 · 알약) 지움 · 셸 회사 고르기 단정으로 바꿈 · test_546_b01_shell 새로
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
4.4 KiB
Python
107 lines
4.4 KiB
Python
"""546 대시보드 셸 · 세부 페이지 등록부 시험 — 화면 조작은 ORCA.
|
|
|
|
· 역할 넷(일반 · 회사 관리자 · 산림청 · 시스템 관리자)별 메뉴 묶음 · 항목 — 등록부를 Node 로 바로 돌림
|
|
· 없는 열쇠 · 권한 없는 열쇠 = 홈 · 주소 열쇠 하나에 한 페이지
|
|
· 셸 = 라우터 MountedPage(같은 주소 안 이동 = 페이지만 갈아 끼움) · 옛 ☰ 서랍 · 구역 접기 없음
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
B01 = ROOT / "B01_Dashboard"
|
|
|
|
|
|
def _text(path: Path) -> str:
|
|
return path.read_text(encoding="utf-8")
|
|
|
|
|
|
def _run_views(body: str) -> object:
|
|
src = re.sub(r"^import[\s\S]*?;\n", "", _text(B01 / "B01_Dashboard_UI_Views.ts"), flags=re.M)
|
|
script = (
|
|
"const mountLegacy = () => {}; const mountGuide = () => {}; const mountChat = () => {};\n"
|
|
+ src
|
|
+ "\n"
|
|
+ body
|
|
)
|
|
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
|
|
return json.loads(result.stdout)
|
|
|
|
|
|
MENU = (
|
|
"const menu = (r: ViewRole) => VIEWS.filter((v) => v.roles.includes(r) && v.group !== 'hidden')"
|
|
".map((v) => v.group + ':' + v.key);\n"
|
|
)
|
|
|
|
|
|
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
|
def test_역할별_메뉴():
|
|
out = _run_views(
|
|
MENU + "console.log(JSON.stringify(['USER','ADMIN','FOREST','SYSTEM_ADMIN'].map(menu)));"
|
|
)
|
|
work = ["work:home", "work:projects", "work:assigned", "work:temp"]
|
|
help_ = ["help:guide", "help:chat"]
|
|
user, admin, forest, system = out
|
|
assert user == [*work, "company:company", "company:company-defaults", *help_]
|
|
assert admin == [*work, "company:people", "company:company", "company:company-defaults", *help_]
|
|
# 산림청 = 받은 예정노선 없음(보내는 쪽)
|
|
assert forest == [
|
|
"work:home", "work:projects", "work:temp",
|
|
"company:company", "company:company-defaults", *help_,
|
|
] # fmt: skip
|
|
assert system == [
|
|
*work, "company:people", "company:company",
|
|
"system:sys-overview", "system:sys-companies", "system:sys-users",
|
|
"system:sys-defaults", "system:sys-logs", *help_,
|
|
] # fmt: skip
|
|
|
|
|
|
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
|
def test_주소_열쇠_권한_없으면_홈():
|
|
out = _run_views(
|
|
"console.log(JSON.stringify(["
|
|
"viewFor(null, 'USER').key, viewFor('없음', 'USER').key,"
|
|
"viewFor('people', 'USER').key, viewFor('people', 'ADMIN').key,"
|
|
"viewFor('sys-logs', 'ADMIN').key, viewFor('sys-logs', 'SYSTEM_ADMIN').key,"
|
|
"viewFor('project', 'USER').key, viewFor('me', 'FOREST').key,"
|
|
"roleOf({ role: 'USER' }, true), roleOf({ role: 'ADMIN' }, true),"
|
|
"roleOf({ role: 'SYSTEM_ADMIN' }, true), roleOf({ role: 'USER' }, false),"
|
|
"new Set(VIEWS.map((v) => v.key)).size === VIEWS.length,"
|
|
"]));"
|
|
)
|
|
assert out == [
|
|
"home", "home", "home", "people", "home", "sys-logs", "project", "me",
|
|
"FOREST", "ADMIN", "SYSTEM_ADMIN", "USER", True,
|
|
] # fmt: skip
|
|
|
|
|
|
def test_셸_한_벌():
|
|
shell = _text(B01 / "B01_Dashboard_UI_Shell.ts")
|
|
assert "covers: (route) => route === ROUTES.B01_ACCOUNT" in shell # 같은 주소 안 = show
|
|
assert 'currentQuery().get("view")' in shell
|
|
assert "buildKnowledgeChat()" in shell # 챗봇 둥근 단추 그대로
|
|
page = _text(B01 / "B01_Dashboard_UI_Page.ts")
|
|
assert "mountDashboardShell(root, user, Boolean(session?.is_forest_service))" in page
|
|
for name in ("Page", "Shell", "Nav", "Views", "Legacy"):
|
|
src = _text(B01 / f"B01_Dashboard_UI_{name}.ts")
|
|
assert "setDrawerSteps" not in src and "attachCollapsible" not in src, name
|
|
assert len(src.splitlines()) <= 700, name
|
|
css = _text(B01 / "B01_Dashboard_UI_Style_Shell.css")
|
|
# 색 변수는 셸 안에서만 — :root 에 안 둠
|
|
assert "--b01-accent: #1f7a4d;" in css and not re.search(r"^:root\s*\{", css, re.M)
|
|
assert ':root[data-theme="dark"] .b01-shell {' in css
|
|
icons = _text(ROOT / "ui_template" / "ui_template_icons.ts")
|
|
assert "MIT License" in icons and "Paweł Kuna" in icons
|