feat: add mobile My Work sessions (#193)
This commit is contained in:
1 parent
ecd4b55a26
commit
2072de337e
3 files changed
+272
-4
No files matched your search
@@ -345,6 +345,100 @@ process.stdout.write(JSON.stringify({{
|
||||
assert output["summary"] == "1 review · 2 assigned"
|
||||
|
||||
|
||||
def test_mobile_work_session_follows_filter_and_reconciles_by_identity():
|
||||
items = [
|
||||
{"kind": "issue", "repository": "stackchain/api", "number": 1, "title": "First"},
|
||||
{"kind": "pull", "repository": "stackchain/web", "number": 2, "title": "Second"},
|
||||
{"kind": "issue", "repository": "stackchain/api", "number": 3, "title": "Third"},
|
||||
]
|
||||
script = f"""
|
||||
const buildMyWork = require({json.dumps(str(MY_WORK))});
|
||||
let items = {json.dumps(items)};
|
||||
let filter = 'issue';
|
||||
const opened = [];
|
||||
const progress = [];
|
||||
let finished = 0;
|
||||
const session = buildMyWork.createWorkSession({{
|
||||
getItems: () => items,
|
||||
getFilter: () => filter,
|
||||
onOpen: item => opened.push(item.title),
|
||||
onProgress: state => progress.push(state),
|
||||
onFinish: () => {{ finished += 1; }},
|
||||
}});
|
||||
session.start();
|
||||
items = [items[2], items[1], items[0]];
|
||||
session.reconcile();
|
||||
session.previous();
|
||||
items = items.filter(item => item.number !== 3);
|
||||
session.complete();
|
||||
items = [];
|
||||
session.complete();
|
||||
process.stdout.write(JSON.stringify({{opened, progress, finished, active:session.active()}}));
|
||||
"""
|
||||
result = subprocess.run(
|
||||
["node", "-e", script], check=True, capture_output=True, text=True
|
||||
)
|
||||
output = json.loads(result.stdout)
|
||||
|
||||
assert output["opened"] == ["First", "Third", "First"]
|
||||
assert output["progress"] == [
|
||||
{"index": 1, "total": 2, "can_previous": False, "can_next": True},
|
||||
{"index": 2, "total": 2, "can_previous": True, "can_next": False},
|
||||
{"index": 1, "total": 2, "can_previous": False, "can_next": True},
|
||||
{"index": 1, "total": 1, "can_previous": False, "can_next": False},
|
||||
]
|
||||
assert output["finished"] == 1
|
||||
assert output["active"] is False
|
||||
|
||||
|
||||
def test_mobile_work_session_completion_finishes_when_current_item_is_last():
|
||||
script = f"""
|
||||
const buildMyWork = require({json.dumps(str(MY_WORK))});
|
||||
const items = [{{kind:'pull',repository:'stackchain/api',number:9,is_review:true}}];
|
||||
let finished = 0;
|
||||
const session = buildMyWork.createWorkSession({{
|
||||
getItems: () => items, getFilter: () => 'review', onOpen: () => {{}},
|
||||
onProgress: () => {{}}, onFinish: () => {{ finished += 1; }},
|
||||
}});
|
||||
session.start();
|
||||
session.complete();
|
||||
process.stdout.write(JSON.stringify({{finished,active:session.active()}}));
|
||||
"""
|
||||
result = subprocess.run(
|
||||
["node", "-e", script], check=True, capture_output=True, text=True
|
||||
)
|
||||
assert json.loads(result.stdout) == {"finished": 1, "active": False}
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_mobile_work_session_renders_touch_safe_controls_for_every_work_sheet():
|
||||
html = await dashboard()
|
||||
|
||||
assert 'id="start-work-session"' in html
|
||||
assert html.count('class="work-session-nav"') == 4
|
||||
assert html.count('<span class="small" aria-live="polite" data-work-session-progress>') == 4
|
||||
assert html.count('<button type="button" data-work-session-previous>') == 4
|
||||
assert html.count('<button type="button" data-work-session-next>') == 4
|
||||
assert '.work-session-nav button { min-height:44px;' in html
|
||||
assert 'padding-bottom:calc(10px + env(safe-area-inset-bottom))' in html
|
||||
assert 'aria-live="polite" data-work-session-progress' in html
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_dashboard_wires_work_session_to_existing_sheet_flows_and_completion_actions():
|
||||
html = await dashboard()
|
||||
|
||||
assert 'const workSession = createWorkSession({' in html
|
||||
assert 'function openWorkSessionItem(item)' in html
|
||||
assert "qs('#start-work-session').addEventListener('click'" in html
|
||||
assert "document.querySelectorAll('[data-work-session-previous]')" in html
|
||||
assert "document.querySelectorAll('[data-work-session-next]')" in html
|
||||
assert 'workSession.complete();' in html
|
||||
assert 'workSession.reconcile();' in html
|
||||
for opener in ('openIssueSheet(item', 'openPullSheet(item', 'openReviewSheet(item', 'notificationReader.open(item'):
|
||||
assert opener in html
|
||||
|
||||
|
||||
def test_my_work_filter_counts_distinguish_prs_from_review_requests():
|
||||
items = [
|
||||
{"kind": "issue", "is_review": False},
|
||||
|
||||
Reference in new issue
Block a user