- 새 산근(로직 연결 · 입력값) = 연결 즉시 뒤에서 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>
86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""481-2 B08 · B09 단계 이동(☰ · 진행 단계 · [<] [>]) = 보이는 화면 저장 성공 뒤 · 실패면 머묾.
|
|
|
|
`helper_481_2_save_move.cjs` 가 진짜 `B08_Quantity_UI_Page.ts` · `B08_Quantity_UI_Options.ts` ·
|
|
`B09_Estimation_UI_Shell.ts` 를 가짜 DOM · 가짜 의존 위에서 돌림.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def r():
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_481_2_save_move.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):
|
|
b = r["b08"]
|
|
assert b["summaryOk"] == ["save:options", "req:complete", "go:b09"] # 298-2 단계 5 완료
|
|
assert b["materialOk"] == ["save:options", "save:material", "go:b07"]
|
|
|
|
|
|
def test_B08_저장_실패면_머묾(r):
|
|
b = r["b08"]
|
|
assert b["optionsFail"] == ["save:options"]
|
|
assert b["materialFail"] == ["save:options", "save:material"]
|
|
assert b["optionsFailSkipsTab"] == ["save:options"]
|
|
assert b["hydroFail"] == ["save:options", "save:hydro"]
|
|
|
|
|
|
def test_B08_떠난_탭은_저장_안_부름(r):
|
|
assert r["b08"]["leftTab"] == ["save:options", "req:complete", "go:b09"]
|
|
|
|
|
|
def test_B08_좌측_옵션_save(r):
|
|
o = r["options"]
|
|
assert o["clean"] == [True, []] # 고침 없음 = 요청 없이 참
|
|
assert o["changed"] == [True, ["req:PUT", "req:milestone", "redraw"]]
|
|
assert o["after"] is False
|
|
assert o["milestoneOnly"][0] is True and "req:PUT" in o["milestoneOnly"][1]
|
|
assert o["blankPipe"] == [False, []] # 1본 빈칸 = 머묾
|
|
assert o["fail"] == [False, ["req:PUT"]]
|
|
assert o["keptOnFail"] is True
|
|
|
|
|
|
def test_B09_고친_값_있으면_물음_뒤_이동(r):
|
|
# 702-3 B09 [저장] 단추 생김 — 단계 이동 = 저장 안 한 고침 있으면 물음(저장 · 버림 · 머묾)
|
|
b = r["b09"]
|
|
assert b["beforeLoad"] == ["go:b08"] # 불러오기 전 = 물음 · 저장 없이(캐시 남음)
|
|
assert b["clean"] == ["go:b08"] # 고침 없음 = 요청 없이
|
|
put = "fetch:PUT:/api/projects/P1/estimation"
|
|
assert b["fail"] == ["ask", put] # [저장] 실패 = 머묾
|
|
assert b["ok"] == ["ask", put, "go:b08"]
|
|
assert b["discard"] == [["ask", "go:b08"], False] # [버림] = 캐시 지움 · 저장 없이
|
|
assert b["stay"] == [["ask"], True]
|
|
|
|
|
|
def test_자재_수리_탭_저장_등록():
|
|
material = (ROOT / "B08_Quantity/B08_Quantity_UI_Material.ts").read_text(encoding="utf-8")
|
|
hydro = (ROOT / "B08_Quantity/B08_Quantity_UI_Hydro.ts").read_text(encoding="utf-8")
|
|
assert re.search(
|
|
r'onSave\?\.\(async \(\) => !readState\("b08-materials", projectId\) \|\| saveAll\(\)\)',
|
|
material,
|
|
)
|
|
assert re.search(
|
|
r"onSave\?\.\(async \(\) => !Object\.keys\(drafts\)\.length \|\| saveAll\(\)\)", hydro
|
|
)
|
|
for src in (material, hydro):
|
|
assert "const saveAll = async (): Promise<boolean>" in src
|