Files
willtools-demo/WillTools.extension/tests/test_app_js_live_kv.py
T
will 8e6ee31596
ci / test (push) Successful in 6m18s
WillTools 2026-09-09 -- clean snapshot of the development repo for review
History-free snapshot of the private development repository at cbe45c5
(2026-09-09). Code, docs and public catalogue only; no plant or job
knowledge layers, no client or job names (tools/scrub.py clean). The
intro deck is left out of this snapshot because its slide images could
not be checked for job drawings.
2026-09-09 08:32:15 -05:00

78 lines
3.2 KiB
Python

# -*- coding: utf-8 -*-
"""Host-side guard for issue #23's `live` kv contract.
The issue (owner, 2026-09-07: "啥叫JS活儿?html写不了?" -- the front end is
ours, so write it): a kv row that sums a row table -- the Reinforcement
page's Strand count, Total IP and Aps -- must follow the table's rows IN
THE BROWSER as they are edited, not only on the next page build / Run.
The page is plain ES2017 in a static file with no JS test runner, so this
suite checks the CONTRACT by reading the source, the same way
`test_button_tooltips.py` reads `bundle.yaml` / `script.py`: the three
pieces that wire the feature together must all exist and stay connected --
`renderKv` records the spec into `state.liveKv`, `recomputeLiveKv` rewrites
the value cells, and `updateValue` (plus the row add/remove handlers) calls
it whenever a key of the table changes. And the spec document must still
describe the row shape (docs/pa-web-spec.md, "kv").
"""
import io
import os
import re
_EXT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_REPO = os.path.dirname(_EXT)
APP_JS = os.path.join(_REPO, 'tools', 'pa_web', 'static', 'app.js')
SPEC_MD = os.path.join(_REPO, 'docs', 'pa-web-spec.md')
def _read(path):
with io.open(path, encoding='utf-8') as f:
return f.read()
def test_the_files_this_guards_still_exist():
"""If the page moves, this suite must fail loudly rather than pass by
reading nothing -- the test_button_tooltips.py discipline."""
assert os.path.isfile(APP_JS), 'missing {0}'.format(APP_JS)
assert os.path.isfile(SPEC_MD), 'missing {0}'.format(SPEC_MD)
def test_app_js_declares_the_live_kv_mechanism():
src = _read(APP_JS)
# renderKv records rows into state.liveKv, keyed by the spec's table...
assert 'state.liveKv' in src
assert 'function recomputeLiveKv' in src
# ...the value formatting helper exists, and row discovery is the SAME
# helper the editable table itself uses (one idea of "present row").
assert 'function fmtLive' in src
assert 'rowIds(live.table)' in src
def test_update_value_recomputes_live_kv_rows():
"""`updateValue` -- every cell edit's one funnel -- must call
`recomputeLiveKv`, not just `recomputeDerived`. Sliced to updateValue's
own body so a stray later call elsewhere cannot satisfy the guard."""
src = _read(APP_JS)
start = src.index('function updateValue')
end = src.find('\n\n // ---', start)
assert end != -1, 'could not find the end of updateValue\'s body'
body = src[start:end]
assert 'recomputeLiveKv(' in body, \
'updateValue no longer calls recomputeLiveKv after recomputeDerived'
def test_spec_documents_live_under_kv():
md = _read(SPEC_MD)
start = md.index('### `kv`')
nxt = md.find('\n### ', start + 1)
assert nxt != -1, 'no section follows kv in pa-web-spec.md'
section = md[start:nxt]
assert re.search(r'\[label, value, live\]', section)
assert '"live"' in section
assert '"terms"' in section and '"format"' in section
assert '"unknown"' in section
# the contract names the trigger: any key of the table, add/remove row
# included, and JS-off correctness (server value is the first paint).
assert '.present' in section
assert 'JS off' in section