feat: make mobile issue sheets read-first (#215)
This commit is contained in:
1 parent
c0cc6ec46e
commit
d09ceb8650
3 files changed
+182
-76
No files matched your search
@@ -535,6 +535,71 @@ async def test_mobile_my_work_exposes_touch_safe_milestone_lane_and_issue_editor
|
||||
assert 'buildMyWork.replaceIssueMilestone(' in html
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_mobile_issue_sheet_puts_reading_before_collapsed_planning_controls():
|
||||
html = await dashboard()
|
||||
|
||||
body = html.index('id="issue-sheet-body"')
|
||||
conversation = html.index('<h2>Full conversation</h2>', body)
|
||||
planning = html.index('id="issue-planning"', conversation)
|
||||
labels = html.index('id="issue-label-editor"', planning)
|
||||
milestone = html.index('id="issue-milestone"', planning)
|
||||
|
||||
assert '<summary>Plan & edit</summary>' in html[planning:labels]
|
||||
assert '<details class="issue-planning" id="issue-planning">' in html
|
||||
assert body < conversation < planning < labels < milestone
|
||||
|
||||
|
||||
def test_issue_planning_metadata_is_lazy_cached_and_retryable_after_failure():
|
||||
script = f"""
|
||||
const createIssueSheet = require({json.dumps(str(ISSUE_SHEET))});
|
||||
const calls = [];
|
||||
let fail = true;
|
||||
const planning = createIssueSheet.createPlanningLoader({{
|
||||
loadLabels: async item => {{ calls.push('labels:' + item.number); return [{{id:1,name:'P0'}}]; }},
|
||||
loadMilestones: async item => {{
|
||||
calls.push('milestones:' + item.number);
|
||||
if (fail) throw new Error('offline');
|
||||
return [{{id:9,title:'RC'}}];
|
||||
}},
|
||||
}});
|
||||
const item = {{repository:'stackchain/api', number:17}};
|
||||
(async () => {{
|
||||
const before = calls.slice();
|
||||
let failed = false;
|
||||
try {{ await planning.open(item); }} catch (_error) {{ failed = true; }}
|
||||
fail = false;
|
||||
const first = await planning.open(item);
|
||||
const second = await planning.open(item);
|
||||
process.stdout.write(JSON.stringify({{before, failed, calls, same:first === second, first}}));
|
||||
}})();
|
||||
"""
|
||||
result = subprocess.run(
|
||||
["node", "-e", script], check=True, capture_output=True, text=True
|
||||
)
|
||||
|
||||
assert json.loads(result.stdout) == {
|
||||
"before": [],
|
||||
"failed": True,
|
||||
"calls": ["labels:17", "milestones:17", "labels:17", "milestones:17"],
|
||||
"same": True,
|
||||
"first": {"labels": [{"id": 1, "name": "P0"}], "milestones": [{"id": 9, "title": "RC"}]},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_opening_issue_defers_planning_requests_until_disclosure_expands():
|
||||
html = await dashboard()
|
||||
open_handler = html[html.index('async function openIssueSheet'):html.index('function closeIssueSheet')]
|
||||
|
||||
assert 'loadIssueLabelEditor(' not in open_handler
|
||||
assert 'loadIssueMilestoneEditor(' not in open_handler
|
||||
assert "if (qs('#issue-planning').open) loadIssuePlanning();" in open_handler
|
||||
assert "qs('#issue-planning').addEventListener('toggle'" in html
|
||||
assert 'planningLoader.open(selectedIssue)' in html
|
||||
assert 'id="retry-issue-planning"' in html
|
||||
|
||||
|
||||
def test_my_work_reviews_filter_and_summary_are_actionable():
|
||||
items = [
|
||||
{"title": "Issue", "kind": "issue", "is_review": False, "is_assigned": True},
|
||||
|
||||
Reference in new issue
Block a user