chore: восстановление репозитория из снапшота v0.3.1
Прежняя git-история утрачена при переносе проекта на машину владельца (снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной истории. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
1c85091186
184 changed files with 33303 additions and 0 deletions
79
packages/board/src/input.test.ts
Normal file
79
packages/board/src/input.test.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* Тесты редьюсера тач-ввода: вся таблица переходов.
|
||||
* tap → pixelToPoint; pending/commit/cancel/перенос по контракту.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { Point } from '@go-learn/core';
|
||||
import { computeGeometry, pointToPixel } from './geometry.js';
|
||||
import type { InputEvent, InputState } from './input.js';
|
||||
import { reduceInput } from './input.js';
|
||||
|
||||
const geo = computeGeometry(9, 450, false);
|
||||
const IDLE: InputState = { pending: null };
|
||||
|
||||
function tap(point: Point): InputEvent {
|
||||
const { x, y } = pointToPixel(geo, point);
|
||||
return { type: 'tap', px: x, py: y };
|
||||
}
|
||||
|
||||
const A: Point = { x: 3, y: 3 };
|
||||
const B: Point = { x: 5, y: 6 };
|
||||
|
||||
describe('reduceInput: tap', () => {
|
||||
it('тап при pending=null → pending=точка, commit=null', () => {
|
||||
const result = reduceInput(IDLE, tap(A), geo);
|
||||
expect(result.commit).toBeNull();
|
||||
expect(result.state.pending).toEqual(A);
|
||||
});
|
||||
|
||||
it('повторный тап по той же точке → commit=точка, pending=null', () => {
|
||||
const result = reduceInput({ pending: A }, tap(A), geo);
|
||||
expect(result.commit).toEqual(A);
|
||||
expect(result.state.pending).toBeNull();
|
||||
});
|
||||
|
||||
it('тап по другой точке → перенос pending, commit=null', () => {
|
||||
const result = reduceInput({ pending: A }, tap(B), geo);
|
||||
expect(result.commit).toBeNull();
|
||||
expect(result.state.pending).toEqual(B);
|
||||
});
|
||||
|
||||
it('тап мимо доски → состояние не меняется, commit=null', () => {
|
||||
const miss: InputEvent = { type: 'tap', px: -20, py: 450 + 20 };
|
||||
const fromIdle = reduceInput(IDLE, miss, geo);
|
||||
expect(fromIdle.state).toBe(IDLE);
|
||||
expect(fromIdle.commit).toBeNull();
|
||||
const withPending: InputState = { pending: A };
|
||||
const fromPending = reduceInput(withPending, miss, geo);
|
||||
expect(fromPending.state).toBe(withPending);
|
||||
expect(fromPending.commit).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reduceInput: confirm', () => {
|
||||
it('confirm при pending → commit=pending, pending=null', () => {
|
||||
const result = reduceInput({ pending: A }, { type: 'confirm' }, geo);
|
||||
expect(result.commit).toEqual(A);
|
||||
expect(result.state.pending).toBeNull();
|
||||
});
|
||||
|
||||
it('confirm без pending → commit=null, pending=null', () => {
|
||||
const result = reduceInput(IDLE, { type: 'confirm' }, geo);
|
||||
expect(result.commit).toBeNull();
|
||||
expect(result.state.pending).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reduceInput: cancel', () => {
|
||||
it('cancel при pending → сброс, commit=null', () => {
|
||||
const result = reduceInput({ pending: A }, { type: 'cancel' }, geo);
|
||||
expect(result.commit).toBeNull();
|
||||
expect(result.state.pending).toBeNull();
|
||||
});
|
||||
|
||||
it('cancel без pending → commit=null, pending=null', () => {
|
||||
const result = reduceInput(IDLE, { type: 'cancel' }, geo);
|
||||
expect(result.commit).toBeNull();
|
||||
expect(result.state.pending).toBeNull();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue