- 새 산근(로직 연결 · 입력값) = 연결 즉시 뒤에서 POST …/estimation/calc(화면 캐시로 셈 · 저장 안 함) · 차례 번호 · 옛 요청 끊기 · 오는 동안 그 줄 금액 칸만 「셈 중」 · 잠금 없음 (새 `B09_Estimation_UI_Live.ts`) · 기준 = payload.user(서버가 그 셈에 쓴 값) - 조작 중 셈 = 마지막 GET · [저장] 의 B08 원천 다시 씀(120 s · 0.6 → 0.15 s) · [저장] · GET 은 늘 새로 읽음 - [저장] 단추 = 왼쪽 아래 [초기화] 옆(B08 과 같은 부품 · 꼴) · 고침 없으면 알림만 - 단계 이동 · [>] = 저장 안 한 고침 있으면 공용 떠남 물음(취소 · 폐기 · 저장) — 옛 자동 저장 없앰 - 서고 사본 payload 의 user 받음(서버 기준) — 화면 캐시와 다른 로직 줄은 뒤에서 다시 셈 - 낡은 시험 고침: 481-2 · 298-2(자동 저장 → 물음 · [저장] 단추) · 184-3 · 304(단추 줄) · 204-2(user 받음) · 200-2(701-3 띠 · 702-1 펼침 뒤 셸 꼴) - 확인 = test_702_3 3 · B09 관련 312 통과 · typecheck 0 · 검증_sub5 T6 11 누름 · 연결 뒤 0.32~0.49 s 금액 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
115 lines
3.6 KiB
Python
115 lines
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""298-2 B08 · B09 좌측 아래 단추 줄 — [초기화] · [>] (PLAN 497-2 · 요구 300 C1 · C3 · C4 · C5 · 301).
|
|
|
|
`helper_298_2_b08_b09_buttons.cjs` 가 진짜 `B08_Quantity_UI_Options.ts` · `B08_Quantity_UI_Page.ts` ·
|
|
`B09_Estimation_UI_Shell.ts` 를 가짜 DOM · 가짜 의존 위에서 돌림.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
DRAFTS = ["b08-options", "b08-materials", "b08-hydro", "b08-milestone"]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def r():
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_298_2_b08_b09_buttons.cjs")],
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_B08_단추_줄_저장_다음_초기화(r):
|
|
assert r["options"]["order"] == ["filled", "danger-ghost"] # [?][<][>] 은 공용이 앞에
|
|
|
|
|
|
def test_B08_초기화_취소면_그대로(r):
|
|
assert r["options"]["cancel"] == [["confirm"], DRAFTS]
|
|
|
|
|
|
def test_B08_초기화_확인_잠금_요청_초안_비움_다시_그림(r):
|
|
calls, left = r["options"]["ok"]
|
|
assert calls == [
|
|
"confirm",
|
|
"lock",
|
|
"req:POST:/projects/P1/quantity/reset",
|
|
"milestone:true", # 이정 저장본 다시 읽음
|
|
"redraw",
|
|
"unlock",
|
|
]
|
|
assert left == []
|
|
|
|
|
|
def test_B08_초기화_실패면_초안_남음(r):
|
|
calls, left = r["options"]["fail"]
|
|
assert "toast:error" in calls and "redraw" not in calls and left == DRAFTS
|
|
|
|
|
|
def test_B08_다음_단계_완료_뒤_이동_실패면_머묾(r):
|
|
p = r["page"]
|
|
assert p["next"] == ["req:POST:/projects/P1/quantity/complete", "go:b09"]
|
|
assert p["back"] == ["go:b07"] # 앞 단계 = 완료 없음
|
|
assert p["fail"] == ["req:POST:/projects/P1/quantity/complete", "toast:error"]
|
|
|
|
|
|
def test_B09_단추_줄_저장_초기화(r):
|
|
assert r["b09"]["dock"] == ["filled", "danger-ghost"] # 702-3 [저장] = B08 과 같은 꼴 · 자리
|
|
assert r["b09"]["nextEnabled"] is True
|
|
|
|
|
|
def test_B09_다음_저장_완료_인쇄(r):
|
|
b = r["b09"]
|
|
assert b["clean"] == [True, ["fetch:POST:/api/projects/P1/estimation/complete", "next"]]
|
|
assert b["changed"] == [
|
|
True,
|
|
[
|
|
"ask", # 702-3 저장 안 한 고침 = 물음([저장] 고름)
|
|
"lock",
|
|
"fetch:PUT:/api/projects/P1/estimation",
|
|
"unlock",
|
|
"fetch:POST:/api/projects/P1/estimation/complete",
|
|
"next",
|
|
],
|
|
]
|
|
assert b["cleared"] is True
|
|
assert "next" not in b["saveFail"][1] and "toast:error" in b["saveFail"][1]
|
|
assert b["completeFail"][1] == [
|
|
"fetch:POST:/api/projects/P1/estimation/complete",
|
|
"toast:error",
|
|
]
|
|
assert b["prev"] == [False, []] # [<] = 공용 틀 몫
|
|
assert b["blocked"] == [True, ["toast:warning"]] # 701-3 빈 줄 있으면 저장 · 완료 없이 머묾
|
|
|
|
|
|
def test_B09_초기화(r):
|
|
b = r["b09"]
|
|
assert b["resetCancel"] == [["confirm"], True]
|
|
assert b["resetOk"] == [
|
|
["confirm", "lock", "fetch:POST:/api/projects/P1/estimation/reset", "unlock"],
|
|
False,
|
|
]
|
|
|
|
|
|
def test_B09_초안_없으면_다음_흐림(r):
|
|
assert r["b09NoDraft"] == {
|
|
"dock": ["filled", "danger-ghost"],
|
|
"nextEnabled": False,
|
|
"nav": [False, []],
|
|
}
|
|
|
|
|
|
def test_초안_다음_길_등록():
|
|
src = (ROOT / "B09_Estimation/draft/B09_Draft_Print_UI.ts").read_text("utf-8")
|
|
assert "DRAFT.next = () => navigateTo(ROUTE.path as RoutePath);" in src
|