111 lines
4.2 KiB
Python
111 lines
4.2 KiB
Python
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from tests.dashboard_bundle import dashboard
|
|
|
|
|
|
GESTURE = Path(__file__).resolve().parents[1] / "frontend" / "update-triage-gesture.js"
|
|
|
|
|
|
def run_gesture(script):
|
|
source = f"const createGesture = require({json.dumps(str(GESTURE))});\n" + script
|
|
result = subprocess.run(["node", "-e", source], capture_output=True, text=True)
|
|
assert result.returncode == 0, result.stderr
|
|
return json.loads(result.stdout)
|
|
|
|
|
|
def test_committed_horizontal_swipes_decide_once_and_lock_while_pending():
|
|
result = run_gesture(r"""
|
|
class Surface {
|
|
constructor() { this.listeners = {}; this.dataset = {}; }
|
|
addEventListener(name, callback) { this.listeners[name] = callback; }
|
|
removeEventListener(name) { delete this.listeners[name]; }
|
|
setPointerCapture() {}
|
|
releasePointerCapture() {}
|
|
}
|
|
const surface = new Surface();
|
|
const calls = [];
|
|
let enabled = true;
|
|
let resolveRead;
|
|
let lockedCalls;
|
|
const gesture = createGesture({
|
|
surface,
|
|
enabled: () => enabled,
|
|
keepUnread: () => calls.push('keep'),
|
|
markRead: () => new Promise(resolve => { calls.push('read'); resolveRead = resolve; }),
|
|
viewportWidth: () => 390,
|
|
});
|
|
const target = {closest: () => null, parentElement: null, scrollWidth: 100, clientWidth: 100};
|
|
const event = (x, y, id=1) => ({pointerId:id, pointerType:'touch', clientX:x, clientY:y, target, preventDefault(){}});
|
|
surface.listeners.pointerdown(event(180, 200));
|
|
surface.listeners.pointermove(event(250, 205));
|
|
surface.listeners.pointerup(event(270, 206));
|
|
surface.listeners.pointerdown(event(280, 200));
|
|
surface.listeners.pointermove(event(205, 204));
|
|
surface.listeners.pointerup(event(190, 205));
|
|
surface.listeners.pointerdown(event(280, 200));
|
|
surface.listeners.pointermove(event(190, 203));
|
|
surface.listeners.pointerup(event(180, 203));
|
|
Promise.resolve().then(() => {
|
|
lockedCalls = [...calls];
|
|
resolveRead();
|
|
return Promise.resolve();
|
|
}).then(() => process.stdout.write(JSON.stringify({calls, lockedCalls, direction:surface.dataset.triageGesture || null})));
|
|
""")
|
|
|
|
assert result == {
|
|
"calls": ["keep", "read"],
|
|
"lockedCalls": ["keep", "read"],
|
|
"direction": None,
|
|
}
|
|
|
|
|
|
def test_scrolls_short_drags_edges_and_interactive_targets_never_decide():
|
|
result = run_gesture(r"""
|
|
class Surface {
|
|
constructor() { this.listeners = {}; this.dataset = {}; }
|
|
addEventListener(name, callback) { this.listeners[name] = callback; }
|
|
removeEventListener(name) { delete this.listeners[name]; }
|
|
setPointerCapture() {}
|
|
releasePointerCapture() {}
|
|
}
|
|
const surface = new Surface();
|
|
const calls = [];
|
|
createGesture({surface, enabled:()=>true, keepUnread:()=>calls.push('keep'), markRead:()=>calls.push('read'), viewportWidth:()=>390});
|
|
const plain = {closest: () => null, parentElement: null, scrollWidth:100, clientWidth:100};
|
|
const interactive = {closest: selector => selector.includes('button') ? {} : null, parentElement:null, scrollWidth:100, clientWidth:100};
|
|
const scroller = {closest: () => null, parentElement:null, scrollWidth:400, clientWidth:100};
|
|
const event = (x,y,target=plain,id=1) => ({pointerId:id,pointerType:'touch',clientX:x,clientY:y,target,preventDefault(){}});
|
|
function drag(fromX, fromY, toX, toY, target=plain) {
|
|
surface.listeners.pointerdown(event(fromX,fromY,target));
|
|
surface.listeners.pointermove(event(toX,toY,target));
|
|
surface.listeners.pointerup(event(toX,toY,target));
|
|
}
|
|
drag(180,100,205,104);
|
|
drag(180,100,220,190);
|
|
drag(8,100,120,104);
|
|
drag(180,100,280,104,interactive);
|
|
drag(180,100,280,104,scroller);
|
|
surface.listeners.pointerdown(event(180,100));
|
|
surface.listeners.pointercancel(event(280,104));
|
|
process.stdout.write(JSON.stringify({calls, direction:surface.dataset.triageGesture || null}));
|
|
""")
|
|
|
|
assert result == {"calls": [], "direction": None}
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_dashboard_wires_accessible_phone_only_update_swipe_triage():
|
|
html = await dashboard()
|
|
|
|
assert '<script src="static/update-triage-gesture.js"></script>' in html
|
|
assert 'id="update-gesture-status"' in html
|
|
assert "createUpdateTriageGesture({" in html
|
|
assert "qs('#keep-update-unread').click()" in html
|
|
assert "qs('#mark-update-read-next').click()" in html
|
|
assert "data-triage-gesture" in html
|
|
assert "prefers-reduced-motion: reduce" in html
|