summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-15 12:43:53 -0300
committerGabriel Schneider <[email protected]>2026-09-15 17:24:42 -0300
commitc787d59a987ec601cd7b65399543afe6d37a615d (patch)
treeb593436d7aa4c37cb0e59eef5412dbb77ae5faad /test
parent8b0bed0427064794725f95cb7b020d7d96956975 (diff)
downloadpardes-c787d59a987ec601cd7b65399543afe6d37a615d.tar.gz
pardes-c787d59a987ec601cd7b65399543afe6d37a615d.zip
Route mouse thumb buttons to jump history
Diffstat (limited to 'test')
-rw-r--r--test/web-snapshots/touch.mjs78
-rw-r--r--test/web_snapshot.mjs3
2 files changed, 76 insertions, 5 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;
+ })()`);
+ }
}
diff --git a/test/web_snapshot.mjs b/test/web_snapshot.mjs
index a9cd8dff..61467c4d 100644
--- a/test/web_snapshot.mjs
+++ b/test/web_snapshot.mjs
@@ -82,7 +82,8 @@ async function main() {
if (scenarioModule) {
const scenario = await import(pathToFileURL(scriptPath));
- await scenario.default({ grid, touch: dispatchTouch, wait: waitUntil, stable: waitStable, delay });
+ await scenario.default({ grid, touch: dispatchTouch, wait: waitUntil, stable: waitStable, delay, evaluate,
+ mouse: (event) => client.send("Input.dispatchMouseEvent", event) });
console.error(`web test ok: ${path.relative(process.cwd(), scriptPath)}`);
return;
}