diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-15 12:43:53 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-15 17:24:42 -0300 |
| commit | c787d59a987ec601cd7b65399543afe6d37a615d (patch) | |
| tree | b593436d7aa4c37cb0e59eef5412dbb77ae5faad /test/web-snapshots | |
| parent | 8b0bed0427064794725f95cb7b020d7d96956975 (diff) | |
| download | pardes-c787d59a987ec601cd7b65399543afe6d37a615d.tar.gz pardes-c787d59a987ec601cd7b65399543afe6d37a615d.zip | |
Route mouse thumb buttons to jump history
Diffstat (limited to 'test/web-snapshots')
| -rw-r--r-- | test/web-snapshots/touch.mjs | 78 |
1 files changed, 74 insertions, 4 deletions
diff --git a/test/web-snapshots/touch.mjs b/test/web-snapshots/touch.mjs index 1a233e68..8c34b185 100644 --- a/test/web-snapshots/touch.mjs +++ b/test/web-snapshots/touch.mjs @@ -1,7 +1,8 @@ import assert from "node:assert/strict"; function tags(frame) { - return frame.styleRows.flatMap((cells, y) => y > 0 && cells.some((cell) => cell[2] & 128) ? [y] : []); + // Pane tags have a gutter; the workspace and column bars do not. + return frame.styleRows.flatMap((cells, y) => /^\s{2}\S/.test(frame.lines[y]) && cells.some((cell) => cell[2] & 128) ? [y] : []); } function pane(frame, name) { @@ -15,9 +16,9 @@ function pane(frame, name) { function styled(frame) { const source = pane(frame, "touch-fixture.zig"); for (const [line, word, fg, bold] of [ - ["pub fn choose", "fn", 0xcf87e8, true], + ["pub fn choose", "fn", 0xcf87e8, false], ["pub fn choose", "choose", 0xbdbdbd, false], - ["if (value", "if", 0xcf87e8, true], + ["if (value", "if", 0xcf87e8, false], ["if (value", "42", 0xe3c78a, false], ["if (value", '"touch fixture"', 0xe3c78a, false], ]) { @@ -39,7 +40,7 @@ function styled(frame) { } } -export default async function ({ grid, touch, wait, stable, delay }) { +export default async function ({ grid, touch, wait, stable, delay, evaluate, mouse }) { await stable(100, 5000); let frame = await grid(); assert.equal(tags(frame).length, 1); @@ -96,4 +97,73 @@ export default async function ({ grid, touch, wait, stable, delay }) { assert.notEqual(scrolled.lines[0], beforeScroll, "source must scroll"); assert(Number(scrolled.lines[0].trim().split(/\s+/)[0]) > 1, "scroll advances source line numbers"); assert.deepEqual(pane(frame, link).lines, reflectedBeforeScroll, "scrolling the source must leave its neighbor alone"); + + const sourceRow = scrolled.top + 2; + const reflectedRow = pane(frame, link).top + 2; + const point = await evaluate(`(() => { + const runtime = pardes.runtime; + const root = runtime.root; + const wasm = runtime.wasm; + const events = []; + const canceled = []; + const pointerDownCanceled = []; + const click = (row) => { + wasm.pardes_mouse(0, 0, 10, row, 0); + wasm.pardes_mouse(0, 1, 10, row, 0); + wasm.pardes_tick(); + runtime.renderer.render(); + }; + click(${sourceRow}); + click(${reflectedRow}); + runtime.wasm = { ...wasm, pardes_mouse: (...args) => { + events.push(args.slice(0, 2)); + wasm.pardes_mouse(...args); + } }; + const observe = (event) => { + if (event.type === "pointerdown") pointerDownCanceled.push(event.defaultPrevented); + else if (event.button === 3 || event.button === 4) canceled.push(event.defaultPrevented); + }; + for (const type of ["pointerdown", "mousedown", "auxclick"]) root.addEventListener(type, observe); + pardes.thumbTest = { wasm, observe, events, canceled, pointerDownCanceled }; + return runtime.cellPoint(10, ${sourceRow}); + })()`); + const thumb = async (button, held = false) => { + const mask = button === "back" ? 8 : 16; + await mouse({ type: "mousePressed", button, buttons: mask | Number(held), ...point, clickCount: 1 }); + await mouse({ type: "mouseReleased", button, buttons: Number(held), ...point, clickCount: 1 }); + await stable(100, 5000); + return (await grid()).cursorY; + }; + try { + const backRow = await thumb("back"); + const forwardRow = await thumb("forward"); + assert(backRow > scrolled.top && backRow < scrolled.bottom, "Back returns to the source pane"); + const reflectedAfter = pane(await grid(), link); + assert(forwardRow > reflectedAfter.top && forwardRow < reflectedAfter.bottom, "Forward returns to the reflected pane"); + + await mouse({ type: "mousePressed", button: "left", buttons: 1, ...point, clickCount: 1 }); + await evaluate("pardes.thumbTest.heldPointer = pardes.runtime.pointer"); + await thumb("back", true); + await thumb("forward", true); + const navigation = await evaluate(`({ + events: pardes.thumbTest.events, + canceled: pardes.thumbTest.canceled, + pointerDownCanceled: pardes.thumbTest.pointerDownCanceled, + keptPointer: pardes.thumbTest.heldPointer !== null && pardes.runtime.pointer === pardes.thumbTest.heldPointer, + })`); + const presses = navigation.events.filter((event) => event[1] === 0 && (event[0] === 8 || event[0] === 9)); + assert.deepEqual(presses, [[8, 0], [9, 0], [8, 0], [9, 0]], "each physical thumb press navigates once"); + assert(!navigation.events.some((event) => event[0] === 1 || (event[0] === 0 && event[1] === 3)), "thumb buttons must not become selection drags or middle clicks"); + assert(navigation.canceled.length >= 4 && navigation.canceled.every(Boolean), "thumb mouse and auxclick events must cancel browser defaults"); + assert(navigation.pointerDownCanceled.every((value) => !value), "mouse pointerdown must permit subsequent mousedown events"); + assert(navigation.keptPointer, "thumb navigation must retain the held selection pointer"); + } finally { + await mouse({ type: "mouseReleased", button: "left", buttons: 0, ...point, clickCount: 1 }); + await evaluate(`(() => { + for (const type of ["pointerdown", "mousedown", "auxclick"]) + pardes.runtime.root.removeEventListener(type, pardes.thumbTest.observe); + pardes.runtime.wasm = pardes.thumbTest.wasm; + delete pardes.thumbTest; + })()`); + } } |
