d1aed8e722
上游 ai-kefu → phase1 吸收(Task 11 unit 12): - 拷入 7 个测试文件,import/夹具按目标库重锚(app.engine.* / conftest async_db+build_jiancai_runtime / seed_profiles 提示词锚点) - 补实现(同步自上游): chat_rest 服务端可信 IP(_server_ip/ _merge_client_info,直连场景自报假 IP 不再原样落库);widget.js 与 chat.js 的 data-placeholder 读取(叠加 Task 10 管道:data-* > brand > 中性兜底,tests/test_placeholder_static.py 守卫) - 断言重锚以 jc 主线为准: ev.contact_info 存裸号+等待尾注(e164 走 _cc 派生)、source 值 fallback/customer_stated 口径、推送标注键 号码补全说明、prompt 静态锚按租户(seed_profiles)双测 - 全量回归 459 passed(基线 421 + 吸收 38) Co-Authored-By: Claude Code <noreply@anthropic.com>
71 lines
3.1 KiB
Python
71 lines
3.1 KiB
Python
"""placeholder 配置静态守卫(同步自上游 ai-kefu tests/test_placeholder_static.py)。
|
|
|
|
上游断言读取行自带 `|| "Type a message..."` 默认值;jc(Task 10 值管道)
|
|
优先级为 data-* > brand > 中性兜底——默认值挪进 boot()/applyBrand 的推导
|
|
链尾(读取行给默认会让 brand.placeholder 永远无法生效),读取行保持裸读。
|
|
守卫语义不变: 读取-推导-赋值链路在场、默认值不漂移、chat.html 静态兜底
|
|
不误删、写入侧赋值行不被重构删掉。
|
|
"""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
STATIC = Path(__file__).resolve().parent.parent / "static"
|
|
DEFAULT = "Type a message..."
|
|
|
|
|
|
def _read(rel):
|
|
return (STATIC / rel).read_text(encoding="utf-8")
|
|
|
|
|
|
def _widget_chain_default(src):
|
|
"""提取 widget.js boot 的优先级推导链尾默认值(data-* > brand > 默认)。"""
|
|
m = re.search(
|
|
r'placeholder\s*=\s*placeholderAttr\s*\|\|\s*b\.placeholder\s*\|\|\s*"([^"]*)"',
|
|
src)
|
|
assert m, "widget.js 缺 placeholder 优先级推导链(data-placeholder > brand > 默认)"
|
|
return m.group(1)
|
|
|
|
|
|
def test_widget_reads_data_placeholder_with_default():
|
|
src = _read("widget.js")
|
|
assert 'getAttribute("data-placeholder")' in src, "widget.js 缺 data-placeholder 读取"
|
|
assert _widget_chain_default(src) == DEFAULT, "widget.js 默认值漂移"
|
|
|
|
|
|
def test_chat_js_reads_data_placeholder_with_default():
|
|
src = _read("js/chat.js")
|
|
assert 'getAttribute("data-placeholder")' in src, "chat.js 缺 data-placeholder 读取"
|
|
# chat 端链尾为空串 = 无配置不触碰输入框(chat.html 静态兜底持有可见默认值)
|
|
assert re.search(
|
|
r'placeholderText\s*=\s*placeholderAttr\s*\|\|\s*b\.placeholder\s*\|\|\s*""',
|
|
src), "chat.js 缺 placeholder 优先级推导链(data-placeholder > brand > 不动静态值)"
|
|
|
|
|
|
def test_both_ends_default_identical():
|
|
# 两端用户可见默认值: widget 推导链尾 vs chat.html 静态兜底
|
|
a = _widget_chain_default(_read("widget.js"))
|
|
b = re.search(r'<input id="input"[^>]*placeholder="([^"]*)"',
|
|
_read("chat.html")).group(1)
|
|
assert a == b == DEFAULT, f"两端默认值漂移: {a!r} vs {b!r}"
|
|
|
|
|
|
def test_chat_html_static_fallback_present():
|
|
assert 'placeholder="Type a message..."' in _read("chat.html"), \
|
|
"chat.html 静态兜底被误删(禁用 JS 场景退化)"
|
|
|
|
|
|
def test_widget_template_default_present():
|
|
# jc 模板注入变量(esc(placeholder)),默认值字面量由推导链尾持有
|
|
assert DEFAULT in _read("widget.js"), "widget.js 默认值字面量被误删"
|
|
|
|
|
|
def test_both_ends_apply_assignment():
|
|
"""写入侧守卫(防'读属性仍在、赋值被重构删除'的静默失效,上游断言6)。
|
|
|
|
chat.js 显式赋值行;widget.js 由模板注入 placeholder 变量(等价写入侧)。
|
|
"""
|
|
assert "inputEl.placeholder = placeholderText;" in _read("js/chat.js"), \
|
|
"js/chat.js 缺赋值行 inputEl.placeholder = placeholderText;"
|
|
assert 'placeholder="\' + esc(placeholder) + \'"' in _read("widget.js"), \
|
|
"widget.js 缺模板注入 placeholder 变量"
|