mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
5082b63082
Flows can now express double-taps declaratively:
```yaml
- tap: { on: Login, times: 2 } # selector double-tap
- tap: { x: 0.5, y: 0.57, times: 2 } # coordinate double-tap
```
The selector nests under `on` so option keys never share a map with
selector fields — zod would silently strip them; mixing errors with a
hint instead. `times: 1` normalizes to absent and the serializer emits
the minimal spelling, keeping parse/serialize exact inverses.
The taps dispatch as **one gesture** via `gesture-tap`'s new
`clickCount` (1–10): N Down/Up pairs ~100 ms apart on touch, escalating
CDP `clickCount` per click on Chromium (what makes `dblclick` actually
fire) — never N separate calls whose RPC gaps could miss the OS
double-tap window.
The recorder carries a recorded `clickCount` into `times`, so a recorded
double-tap can't silently replay as a single tap.
63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
// Capture the touch-event train the tool sends to the simulator-server — the
|
|
// multi-tap contract (N Down/Up pairs, one gesture) lives entirely in it.
|
|
interface TouchCmd {
|
|
cmd: string;
|
|
type: "Down" | "Move" | "Up";
|
|
x: number;
|
|
y: number;
|
|
}
|
|
const sent: TouchCmd[] = [];
|
|
vi.mock("../../src/utils/simulator-client", () => ({
|
|
sendCommand: (_api: unknown, cmd: TouchCmd) => {
|
|
sent.push(cmd);
|
|
},
|
|
}));
|
|
|
|
import { gestureTapTool } from "../../src/tools/gesture-tap";
|
|
|
|
const touchServices = { simulatorServer: {} } as never;
|
|
|
|
beforeEach(() => {
|
|
sent.length = 0;
|
|
});
|
|
|
|
describe("gesture-tap", () => {
|
|
it("dispatches a single Down/Up pair by default", async () => {
|
|
await gestureTapTool.execute(touchServices, { udid: "X", x: 0.5, y: 0.5 });
|
|
expect(sent.map((e) => e.type)).toEqual(["Down", "Up"]);
|
|
});
|
|
|
|
it("dispatches clickCount Down/Up pairs as ONE gesture on touch platforms", async () => {
|
|
await gestureTapTool.execute(touchServices, { udid: "X", x: 0.4, y: 0.6, clickCount: 3 });
|
|
expect(sent.map((e) => e.type)).toEqual(["Down", "Up", "Down", "Up", "Down", "Up"]);
|
|
// Every tap lands on the same point — a multi-tap, not a gesture path.
|
|
expect(sent.every((e) => e.x === 0.4 && e.y === 0.6)).toBe(true);
|
|
});
|
|
|
|
it("escalates the CDP clickCount per click on chromium so dblclick fires", async () => {
|
|
const mouse: Array<{ type: string; clickCount?: number }> = [];
|
|
const chromium = {
|
|
getViewport: () => ({ width: 1000, height: 800 }),
|
|
dispatchMouseEvent: vi.fn(async (e: { type: string; clickCount?: number }) => {
|
|
mouse.push(e);
|
|
}),
|
|
};
|
|
await gestureTapTool.execute({ chromium } as never, {
|
|
udid: "chromium-cdp-9222",
|
|
x: 0.5,
|
|
y: 0.5,
|
|
clickCount: 2,
|
|
});
|
|
// The browser's click counter drives dblclick: presses carry 1, then 2.
|
|
expect(mouse.map((e) => `${e.type}:${e.clickCount ?? ""}`)).toEqual([
|
|
"mouseMoved:",
|
|
"mousePressed:1",
|
|
"mouseReleased:1",
|
|
"mousePressed:2",
|
|
"mouseReleased:2",
|
|
]);
|
|
});
|
|
});
|