Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_3
This commit is contained in:
@@ -264,7 +264,7 @@ def test_카드_시스템_관리자만_글_다_있음():
|
||||
admin, rest = links.split('if (user.role === "SYSTEM_ADMIN") {')[1].split("// 회사 수정 =")
|
||||
assert 'key: "calcSites"' in admin and "calcSites" not in rest
|
||||
assert 'settingLinks(user, companyId).filter((link) => link.key !== "calcSites")' in nav
|
||||
page = _text("B01_Dashboard/B01_Dashboard_UI_Page.ts")
|
||||
page = _text("B01_Dashboard/B01_Dashboard_UI_Legacy.ts")
|
||||
assert 'link.key === "calcSites" ? void openCalcSitesDialog()' in page
|
||||
locale = _text("ui_template/ui_template_locale_m1.ts")
|
||||
for group in calc_sites.GROUPS:
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
"""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
|
||||
@@ -1,8 +1,7 @@
|
||||
"""B01 대시보드 「시스템 설정」 컨테이너 시험(27-3) — 화면 조작은 ORCA.
|
||||
"""B01 대시보드 설계 기본값 카드 · 회사 고르기 시험(27-3 · 29-1 · 546) — 화면 조작은 ORCA.
|
||||
|
||||
· 역할별 카드(제목 · 설명 · 이동 해시)를 Node 로 바로 돌림 — 가짜 DOM
|
||||
· 모든 역할 한 줄 · 통째로 접힘 · 「구조물 관리」 컨테이너 없음
|
||||
· 회사 고르기(29-1) — 시스템 관리자만 · 리소스 현황 아래 · 해시 company · 서버 인자 한 곳
|
||||
· 회사 고르기 — 시스템 관리자만 · 위 머리 회사 이름 · 해시 company · 서버 인자 한 곳
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -16,7 +15,8 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
PAGE = ROOT / "B01_Dashboard" / "B01_Dashboard_UI_Page.ts"
|
||||
PAGE = ROOT / "B01_Dashboard" / "B01_Dashboard_UI_Legacy.ts" # 옛 구역 부품(546)
|
||||
SHELL = ROOT / "B01_Dashboard" / "B01_Dashboard_UI_Shell.ts"
|
||||
NAV = ROOT / "A00_Common" / "m_settings_nav.ts" # 카드 규칙 한 벌(334)
|
||||
|
||||
|
||||
@@ -103,49 +103,23 @@ def test_회사_관리자_개인_카드_하나():
|
||||
]
|
||||
|
||||
|
||||
def test_모든_역할_한_줄_통째로_접힘():
|
||||
def test_회사_고르기_시스템_관리자만():
|
||||
src = _text(PAGE)
|
||||
build = _fn(src, "buildPage")
|
||||
# 세 갈래 모두 한 번씩 · 시스템 관리자는 리소스 현황 아래(29-1) · 프로젝트 위
|
||||
assert build.count("buildSystemSettingsSection(state)") == 3
|
||||
sys_part = build.split('} else if (state.user.role === "ADMIN")')[0]
|
||||
assert (
|
||||
sys_part.index('L("B01_Dashboard_Resources")')
|
||||
< sys_part.index("buildSystemSettingsSection(state)")
|
||||
< sys_part.index('L("B01_Dashboard_Projects")')
|
||||
)
|
||||
assert "StructureManage" not in src and "buildStructurePanel" not in src
|
||||
assert "top-row" not in src
|
||||
sect = _fn(src, "buildSystemSettingsSection")
|
||||
assert 'L("B01_Dashboard_SystemSettings"), panel, true)' in sect # 한 줄 통째
|
||||
assert '"ui-collapsible"' in sect and '"ui-collapsible__title"' in sect
|
||||
assert "attachCollapsible(card)" in sect
|
||||
config = _text(ROOT / "config" / "config_frontend.ts")
|
||||
assert re.search(r"PROTECTED_ROUTES[\s\S]*?ROUTES\.M02_MASTER_TEMPLATE,[\s\S]*?\];", config)
|
||||
|
||||
|
||||
def test_회사_알약_시스템_관리자만():
|
||||
src = _text(PAGE)
|
||||
sect = _fn(src, "buildSystemSettingsSection")
|
||||
assert 'if (user.role === "SYSTEM_ADMIN") withCompanyPill(card, state);' in sect
|
||||
pill = _fn(src, "withCompanyPill")
|
||||
assert "sessionStorage.setItem(ADMIN_COMPANY_KEY, String(company.id))" in pill
|
||||
assert "event.stopPropagation()" in pill # 알약 누름이 접힘으로 새지 않음
|
||||
assert "openCompanyPicker(state.allCompanies" in pill # 조회 후 고르기(29-5)
|
||||
assert '"ui-tag ui-tag--accent b01-dashboard__company-pill"' in pill # 공용 알약 모양
|
||||
assert '.querySelector(".b01-dashboard__section-header > .ui-card__title")?.after(pill)' in pill
|
||||
assert 'const ADMIN_COMPANY_KEY = "aislo.adminCompany";' in src # M02 와 같은 키
|
||||
shell = _text(SHELL)
|
||||
pick = _fn(shell, "buildCompany")
|
||||
assert 'if (ctx.role !== "SYSTEM_ADMIN") {' in pick # 그 밖 역할 = 이름만
|
||||
assert "openCompanyPicker(companies, ctx.companyId" in pick # 조회 후 고르기(29-5)
|
||||
assert "sessionStorage.setItem(ADMIN_COMPANY_KEY, String(company.id))" in pick
|
||||
assert "pickAdminCompany(me, companies)" in shell
|
||||
assert 'export const ADMIN_COMPANY_KEY = "aislo.adminCompany";' in src # M02 와 같은 키
|
||||
load = src.split("async function loadRoleData")[1].split("\n}\n")[0]
|
||||
for call in ("fetchAllUsers(companyId)", "fetchCompanyJoinRequests(companyId)",
|
||||
"fetchCompanyProjects(companyId)"): # fmt: skip
|
||||
assert call in load, call
|
||||
build = _fn(src, "buildPage")
|
||||
# 회사 따라 바뀌는 컨테이너 넷(프로젝트 · 사용자 관리 · 가입 요청 · 회사 관리)마다 알약
|
||||
sys_part = build.split('} else if (state.user.role === "ADMIN")')[0]
|
||||
assert sys_part.count("withCompanyPill(") == 4
|
||||
assert "withCompanyPill" not in build.split('} else if (state.user.role === "ADMIN")')[1]
|
||||
assert "companyTable(picked, state.user)" in build
|
||||
assert "openAddMemberModal(undefined, state.adminCompanyId)" in build
|
||||
assert "openAddMemberModal(undefined, s.adminCompanyId)" in src
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
||||
|
||||
Reference in New Issue
Block a user