feat: annotate mobile evidence before filing (Closes #831)
CI / lint (pull_request) Successful in 1m43s
CI / build-release (pull_request) Successful in 5s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-14 14:57:17 +00:00
1 parent f44fa6e579
commit 6ba823abd2
6 files changed
+171 -16

No files matched your search

+58
View File
@@ -41,6 +41,7 @@ const canvas={{width:0,height:0,getContext:()=>({{
assert output["snapshot"] == {
"crop": {"x": 40, "y": 30, "width": 240, "height": 180},
"redactions": [{"x": 70, "y": 60, "width": 80, "height": 40}],
"annotations": [],
}
assert output["width"] == 240
assert output["height"] == 180
@@ -77,6 +78,60 @@ controller.replace(1,image('private-edited.png'));
assert [item["uploaded"] for item in output["state"]] == [False, False, False]
def test_editor_adds_undoes_and_flattens_highlight_and_arrow_annotations():
script = f"""
const editor = require({json.dumps(str(EDITOR))});
const model = editor.createModel({{width:400,height:300}});
model.setCrop({{x:40,y:30,width:240,height:180}});
model.addHighlight({{x:60,y:50,width:100,height:60}});
model.addArrow({{startX:80,startY:150,endX:220,endY:80}});
const beforeUndo=model.snapshot();
model.undo();
const afterUndo=model.snapshot();
model.addArrow({{startX:80,startY:150,endX:220,endY:80}});
const calls=[];
const context={{
drawImage:()=>calls.push(['draw']), fillRect:(...args)=>calls.push(['fill',...args]),
save:()=>calls.push(['save']), restore:()=>calls.push(['restore']),
beginPath:()=>calls.push(['begin']), moveTo:(...args)=>calls.push(['move',...args]),
lineTo:(...args)=>calls.push(['line',...args]), stroke:()=>calls.push(['stroke']),
set fillStyle(value){{calls.push(['fillStyle',value]);}},
set strokeStyle(value){{calls.push(['strokeStyle',value]);}},
set lineWidth(value){{calls.push(['lineWidth',value]);}},
set lineCap(value){{calls.push(['lineCap',value]);}},
set lineJoin(value){{calls.push(['lineJoin',value]);}},
}};
const canvas={{width:0,height:0,getContext:()=>context}};
editor.paint({{source:{{}},model,canvas}});
process.stdout.write(JSON.stringify({{beforeUndo,afterUndo,calls}}));
"""
output = run_node(script)
assert [item["type"] for item in output["beforeUndo"]["annotations"]] == ["highlight", "arrow"]
assert [item["type"] for item in output["afterUndo"]["annotations"]] == ["highlight"]
assert ["fillStyle", "rgba(250, 204, 21, 0.38)"] in output["calls"]
assert ["fill", 20, 20, 100, 60] in output["calls"]
assert ["strokeStyle", "#facc15"] in output["calls"]
assert ["move", 40, 120] in output["calls"]
assert ["line", 180, 50] in output["calls"]
assert output["calls"].count(["stroke"]) == 1
def test_crop_clips_annotations_to_the_retained_image_area():
script = f"""
const editor = require({json.dumps(str(EDITOR))});
const model = editor.createModel({{width:300,height:200}});
model.addHighlight({{x:20,y:30,width:100,height:80}});
model.addArrow({{startX:10,startY:90,endX:120,endY:90}});
model.setCrop({{x:50,y:20,width:100,height:120}});
process.stdout.write(JSON.stringify(model.snapshot()));
"""
output = run_node(script)
assert output["annotations"] == [
{"type": "highlight", "x": 50, "y": 30, "width": 70, "height": 80},
{"type": "arrow", "startX": 50, "startY": 90, "endX": 120, "endY": 90},
]
def test_mobile_editor_dialog_is_accessible_touch_sized_and_available_offline():
html = INDEX.read_text()
css = CSS.read_text()
@@ -87,6 +142,9 @@ def test_mobile_editor_dialog_is_accessible_touch_sized_and_available_offline():
assert 'role="dialog"' in html
assert 'aria-labelledby="issue-evidence-editor-heading"' in html
assert 'id="issue-evidence-editor-canvas"' in html
assert 'id="highlight-issue-evidence"' in html
assert 'id="arrow-issue-evidence"' in html
assert 'aria-label="Screenshot editing canvas. Drag to crop, redact, highlight, or point with an arrow."' in html
assert 'aria-pressed="true"' in html
assert "issue-evidence-editor.js" in worker
assert ".issue-evidence-editor" in css