Load comment actions on conversation demand
This commit is contained in:
1 parent
04f06042b8
commit
f094438dab
7 files changed
+230
-21
No files matched your search
@@ -0,0 +1,120 @@
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
FRONTEND = Path(__file__).parents[1] / "frontend"
|
||||
HYDRATOR = FRONTEND / "conversation-action-hydrator.js"
|
||||
|
||||
|
||||
def run_node(script: str):
|
||||
result = subprocess.run(["node", "-e", script], check=True, capture_output=True, text=True)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def test_conversation_paints_before_optional_actions_load_and_hydrates_once():
|
||||
script = f"""
|
||||
const createConversationActionHydrator = require({json.dumps(str(HYDRATOR))});
|
||||
const events = [];
|
||||
let finishLoad;
|
||||
const hydrator = createConversationActionHydrator({{
|
||||
load: () => {{
|
||||
events.push('load');
|
||||
return new Promise(resolve => {{ finishLoad = resolve; }});
|
||||
}},
|
||||
activate: () => ({{name:'actions'}}),
|
||||
}});
|
||||
const root = {{}};
|
||||
const retry = {{hidden:false}};
|
||||
const status = {{textContent:'2 messages loaded.'}};
|
||||
const state = {{comments:[1,2]}};
|
||||
const pending = hydrator.show({{
|
||||
root, state, retry, status,
|
||||
paint: (_state, actions) => events.push(actions ? 'paint-actions' : 'paint-core'),
|
||||
wire: () => events.push('wire'),
|
||||
}});
|
||||
events.push('returned');
|
||||
finishLoad();
|
||||
pending.then(() => {{
|
||||
hydrator.show({{
|
||||
root, state, retry, status,
|
||||
paint: (_state, actions) => events.push(actions ? 'paint-actions-again' : 'paint-core-again'),
|
||||
wire: () => events.push('wire-again'),
|
||||
}}).then(() => process.stdout.write(JSON.stringify({{events,retry,status:status.textContent}})));
|
||||
}});
|
||||
"""
|
||||
output = run_node(script)
|
||||
|
||||
assert output == {
|
||||
"events": [
|
||||
"paint-core", "load", "returned", "wire", "paint-actions",
|
||||
"paint-actions-again",
|
||||
],
|
||||
"retry": {"hidden": True},
|
||||
"status": "2 messages loaded.",
|
||||
}
|
||||
|
||||
|
||||
def test_failed_comment_actions_keep_conversation_usable_and_retry_in_place():
|
||||
script = f"""
|
||||
const createConversationActionHydrator = require({json.dumps(str(HYDRATOR))});
|
||||
const events = [];
|
||||
let attempt = 0;
|
||||
const hydrator = createConversationActionHydrator({{
|
||||
load: async () => {{
|
||||
attempt += 1;
|
||||
if (attempt === 1) throw new Error('chunk unavailable');
|
||||
}},
|
||||
activate: () => ({{name:'actions'}}),
|
||||
}});
|
||||
const root = {{}};
|
||||
const retry = {{hidden:true}};
|
||||
const status = {{textContent:'2 messages loaded.'}};
|
||||
const options = {{
|
||||
root, retry, status, state:{{comments:[1,2]}},
|
||||
paint: (_state, actions) => events.push(actions ? 'actions' : 'core'),
|
||||
wire: () => events.push('wire'),
|
||||
}};
|
||||
(async () => {{
|
||||
const failed = await hydrator.show(options);
|
||||
events.push('reply-still-usable');
|
||||
const recovered = await hydrator.show(options);
|
||||
process.stdout.write(JSON.stringify({{
|
||||
failed, recovered, attempt, events, retry, status:status.textContent,
|
||||
}}));
|
||||
}})();
|
||||
"""
|
||||
output = run_node(script)
|
||||
|
||||
assert output == {
|
||||
"failed": False,
|
||||
"recovered": True,
|
||||
"attempt": 2,
|
||||
"events": ["core", "reply-still-usable", "core", "wire", "actions"],
|
||||
"retry": {"hidden": True},
|
||||
"status": "2 messages loaded.",
|
||||
}
|
||||
|
||||
|
||||
def test_issue_pull_and_update_conversations_trigger_optional_actions_not_startup():
|
||||
html = (FRONTEND / "index.html").read_text()
|
||||
javascript = (FRONTEND / "dashboard.js").read_text()
|
||||
|
||||
assert '<script src="static/conversation-action-hydrator.js"></script>' in html
|
||||
assert html.index("static/conversation-action-hydrator.js") < html.index("static/dashboard.js")
|
||||
assert "await commentActionFeatures.run('comment-actions'" not in javascript
|
||||
assert "load: () => commentActionFeatures.load('comment-actions')" in javascript
|
||||
assert "createConversationActionHydrator" in javascript
|
||||
for kind in ("issue", "pull", "update"):
|
||||
assert f"retry-{kind}-comment-actions" in html
|
||||
assert f"showConversationWithActions('{kind}'" in javascript
|
||||
assert f"qs('#retry-{kind}-comment-actions').addEventListener" in javascript
|
||||
|
||||
|
||||
def test_comment_action_retry_is_a_phone_sized_inline_control():
|
||||
css = (FRONTEND / "dashboard.css").read_text()
|
||||
|
||||
assert ".conversation-actions-retry" in css
|
||||
rule = css.split(".conversation-actions-retry", 1)[1].split("}", 1)[0]
|
||||
assert "min-height:44px" in rule
|
||||
assert "max-width:100%" in rule
|
||||
@@ -787,6 +787,7 @@ def test_install_precaches_complete_subpath_scoped_app_shell():
|
||||
"/dashboard/static/icons/stackchain-512.png",
|
||||
"/dashboard/static/session.js",
|
||||
"/dashboard/static/feature-loader.js",
|
||||
"/dashboard/static/conversation-action-hydrator.js",
|
||||
"/dashboard/static/security-center.js",
|
||||
"/dashboard/static/markdown.js",
|
||||
"/dashboard/static/commands.js",
|
||||
|
||||
Reference in new issue
Block a user