atagen

malice

public
Star0
Watch0
d9be72fdb39386b8e5863ac7f41631066c55cb22
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/test/longpress.test.ts

0e50e0d137afatagen2026-10-26 05:50 UTC1
import assert from 'node:assert/strict';
0e50e0d137afatagen2026-10-26 05:50 UTC2
import { test } from 'node:test';
0e50e0d137afatagen2026-10-26 05:50 UTC3
import { PressTracker, type Timers } from '../src/lib/longpress.ts';
0e50e0d137afatagen2026-10-26 05:50 UTC4
0e50e0d137afatagen2026-10-26 05:50 UTC5
function clock() {
0e50e0d137afatagen2026-10-26 05:50 UTC6
  let now = 0;
0e50e0d137afatagen2026-10-26 05:50 UTC7
  let next = 1;
0e50e0d137afatagen2026-10-26 05:50 UTC8
  const queue = new Map<number, { at: number; fn: () => void }>();
0e50e0d137afatagen2026-10-26 05:50 UTC9
  const timers: Timers = {
0e50e0d137afatagen2026-10-26 05:50 UTC10
    set(fn, ms) {
0e50e0d137afatagen2026-10-26 05:50 UTC11
      const id = next++;
0e50e0d137afatagen2026-10-26 05:50 UTC12
      queue.set(id, { at: now + ms, fn });
0e50e0d137afatagen2026-10-26 05:50 UTC13
      return id;
0e50e0d137afatagen2026-10-26 05:50 UTC14
    },
0e50e0d137afatagen2026-10-26 05:50 UTC15
    clear(handle) {
0e50e0d137afatagen2026-10-26 05:50 UTC16
      queue.delete(handle as number);
0e50e0d137afatagen2026-10-26 05:50 UTC17
    }
0e50e0d137afatagen2026-10-26 05:50 UTC18
  };
0e50e0d137afatagen2026-10-26 05:50 UTC19
  const advance = (ms: number) => {
0e50e0d137afatagen2026-10-26 05:50 UTC20
    now += ms;
0e50e0d137afatagen2026-10-26 05:50 UTC21
    for (const [id, t] of [...queue]) {
0e50e0d137afatagen2026-10-26 05:50 UTC22
      if (t.at <= now) {
0e50e0d137afatagen2026-10-26 05:50 UTC23
        queue.delete(id);
0e50e0d137afatagen2026-10-26 05:50 UTC24
        t.fn();
0e50e0d137afatagen2026-10-26 05:50 UTC25
      }
0e50e0d137afatagen2026-10-26 05:50 UTC26
    }
0e50e0d137afatagen2026-10-26 05:50 UTC27
  };
0e50e0d137afatagen2026-10-26 05:50 UTC28
  return { timers, advance };
0e50e0d137afatagen2026-10-26 05:50 UTC29
}
0e50e0d137afatagen2026-10-26 05:50 UTC30
0e50e0d137afatagen2026-10-26 05:50 UTC31
function setup() {
0e50e0d137afatagen2026-10-26 05:50 UTC32
  const c = clock();
0e50e0d137afatagen2026-10-26 05:50 UTC33
  const fires: Array<[number, number]> = [];
0e50e0d137afatagen2026-10-26 05:50 UTC34
  const tracker = new PressTracker((x, y) => fires.push([x, y]), c.timers);
0e50e0d137afatagen2026-10-26 05:50 UTC35
  return { ...c, tracker, fires };
0e50e0d137afatagen2026-10-26 05:50 UTC36
}
0e50e0d137afatagen2026-10-26 05:50 UTC37
0e50e0d137afatagen2026-10-26 05:50 UTC38
test('fires with the press origin after the delay', () => {
0e50e0d137afatagen2026-10-26 05:50 UTC39
  const { tracker, advance, fires } = setup();
0e50e0d137afatagen2026-10-26 05:50 UTC40
  tracker.start(10, 20);
0e50e0d137afatagen2026-10-26 05:50 UTC41
  advance(449);
0e50e0d137afatagen2026-10-26 05:50 UTC42
  assert.deepEqual(fires, []);
0e50e0d137afatagen2026-10-26 05:50 UTC43
  advance(1);
0e50e0d137afatagen2026-10-26 05:50 UTC44
  assert.deepEqual(fires, [[10, 20]]);
0e50e0d137afatagen2026-10-26 05:50 UTC45
  assert.equal(tracker.fired, true);
0e50e0d137afatagen2026-10-26 05:50 UTC46
});
0e50e0d137afatagen2026-10-26 05:50 UTC47
0e50e0d137afatagen2026-10-26 05:50 UTC48
test('release before the delay cancels', () => {
0e50e0d137afatagen2026-10-26 05:50 UTC49
  const { tracker, advance, fires } = setup();
0e50e0d137afatagen2026-10-26 05:50 UTC50
  tracker.start(0, 0);
0e50e0d137afatagen2026-10-26 05:50 UTC51
  advance(200);
0e50e0d137afatagen2026-10-26 05:50 UTC52
  tracker.cancel();
0e50e0d137afatagen2026-10-26 05:50 UTC53
  advance(1000);
0e50e0d137afatagen2026-10-26 05:50 UTC54
  assert.deepEqual(fires, []);
0e50e0d137afatagen2026-10-26 05:50 UTC55
  assert.equal(tracker.fired, false);
0e50e0d137afatagen2026-10-26 05:50 UTC56
});
0e50e0d137afatagen2026-10-26 05:50 UTC57
0e50e0d137afatagen2026-10-26 05:50 UTC58
test('small jitter is tolerated, a drag cancels', () => {
0e50e0d137afatagen2026-10-26 05:50 UTC59
  const a = setup();
0e50e0d137afatagen2026-10-26 05:50 UTC60
  a.tracker.start(0, 0);
0e50e0d137afatagen2026-10-26 05:50 UTC61
  a.tracker.move(4, 4);
0e50e0d137afatagen2026-10-26 05:50 UTC62
  a.advance(450);
0e50e0d137afatagen2026-10-26 05:50 UTC63
  assert.equal(a.fires.length, 1);
0e50e0d137afatagen2026-10-26 05:50 UTC64
  const b = setup();
0e50e0d137afatagen2026-10-26 05:50 UTC65
  b.tracker.start(0, 0);
0e50e0d137afatagen2026-10-26 05:50 UTC66
  b.tracker.move(9, 0);
0e50e0d137afatagen2026-10-26 05:50 UTC67
  b.advance(450);
0e50e0d137afatagen2026-10-26 05:50 UTC68
  assert.equal(b.fires.length, 0);
0e50e0d137afatagen2026-10-26 05:50 UTC69
});
0e50e0d137afatagen2026-10-26 05:50 UTC70
0e50e0d137afatagen2026-10-26 05:50 UTC71
test('a new press clears the fired flag', () => {
0e50e0d137afatagen2026-10-26 05:50 UTC72
  const { tracker, advance } = setup();
0e50e0d137afatagen2026-10-26 05:50 UTC73
  tracker.start(0, 0);
0e50e0d137afatagen2026-10-26 05:50 UTC74
  advance(450);
0e50e0d137afatagen2026-10-26 05:50 UTC75
  tracker.start(5, 5);
0e50e0d137afatagen2026-10-26 05:50 UTC76
  assert.equal(tracker.fired, false);
0e50e0d137afatagen2026-10-26 05:50 UTC77
  assert.equal(tracker.pending, true);
0e50e0d137afatagen2026-10-26 05:50 UTC78
});
0e50e0d137afatagen2026-10-26 05:50 UTC79
0e50e0d137afatagen2026-10-26 05:50 UTC80
test('flush fires a pending press once and ignores an idle tracker', () => {
0e50e0d137afatagen2026-10-26 05:50 UTC81
  const { tracker, advance, fires } = setup();
0e50e0d137afatagen2026-10-26 05:50 UTC82
  tracker.flush();
0e50e0d137afatagen2026-10-26 05:50 UTC83
  assert.equal(fires.length, 0);
0e50e0d137afatagen2026-10-26 05:50 UTC84
  tracker.start(3, 4);
0e50e0d137afatagen2026-10-26 05:50 UTC85
  tracker.flush();
0e50e0d137afatagen2026-10-26 05:50 UTC86
  advance(1000);
0e50e0d137afatagen2026-10-26 05:50 UTC87
  assert.deepEqual(fires, [[3, 4]]);
0e50e0d137afatagen2026-10-26 05:50 UTC88
  assert.equal(tracker.fired, true);
0e50e0d137afatagen2026-10-26 05:50 UTC89
});