clipper/frontend/src/HudCanvasState.test.ts

372 lines
12 KiB
TypeScript

import {
stateReducer,
SelectionMode,
EmptySelectionAction,
HoverState,
} from './HudCanvasState';
const initialState = {
width: 5000,
emptySelectionAction: EmptySelectionAction.SelectNothing,
hoverX: 0,
selection: { start: 0, end: 0 },
origSelection: { start: 0, end: 0 },
mousedownX: 0,
mode: SelectionMode.Normal,
prevMode: SelectionMode.Normal,
cursorClass: 'cursor-auto',
hoverState: HoverState.Normal,
shouldPublish: false,
};
describe('stateReducer', () => {
describe('setselection', () => {
it('sets the selection', () => {
const state = stateReducer(
{ ...initialState },
{ type: 'setselection', x: 0, selection: { start: 100, end: 200 } }
);
expect(state.selection).toEqual({ start: 100, end: 200 });
});
});
describe('mousedown', () => {
describe('when hovering over the selection start', () => {
it('updates the state', () => {
const state = stateReducer(
{ ...initialState, selection: { start: 1000, end: 2000 } },
{ type: 'mousedown', x: 995 }
);
expect(state.mode).toEqual(SelectionMode.ResizingStart);
expect(state.selection).toEqual({ start: 1000, end: 2000 });
expect(state.mousedownX).toEqual(995);
});
});
describe('when hovering over the selection end', () => {
it('updates the state', () => {
const state = stateReducer(
{ ...initialState, selection: { start: 1000, end: 2000 } },
{ type: 'mousedown', x: 2003 }
);
expect(state.mode).toEqual(SelectionMode.ResizingEnd);
expect(state.selection).toEqual({ start: 1000, end: 2000 });
expect(state.mousedownX).toEqual(2003);
});
});
describe('when hovering over the selection', () => {
it('updates the state', () => {
const state = stateReducer(
{ ...initialState, selection: { start: 1000, end: 2000 } },
{ type: 'mousedown', x: 1500 }
);
expect(state.mode).toEqual(SelectionMode.Dragging);
expect(state.selection).toEqual({ start: 1000, end: 2000 });
expect(state.mousedownX).toEqual(1500);
});
});
describe('when not hovering over the selection', () => {
it('updates the state', () => {
const state = stateReducer(
{ ...initialState, selection: { start: 1000, end: 2000 } },
{ type: 'mousedown', x: 3000 }
);
expect(state.mode).toEqual(SelectionMode.Selecting);
expect(state.selection).toEqual({ start: 3000, end: 3000 });
expect(state.mousedownX).toEqual(3000);
});
});
});
describe('mouseup', () => {
describe('when re-entering normal mode', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 2000 },
mode: SelectionMode.Selecting,
mousedownX: 1200,
},
{ type: 'mouseup', x: 0 }
);
expect(state.mode).toEqual(SelectionMode.Normal);
expect(state.selection).toEqual({ start: 1000, end: 2000 });
expect(state.mousedownX).toEqual(1200);
});
});
describe('nothing is selected and emptySelectionAction is SelectNothing', () => {
it('clears the selection at the mouse x coord', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 1000 },
mode: SelectionMode.Selecting,
emptySelectionAction: EmptySelectionAction.SelectNothing,
},
{ type: 'mouseup', x: 500 }
);
expect(state.mode).toEqual(SelectionMode.Normal);
expect(state.selection).toEqual({ start: 500, end: 500 });
});
});
describe('nothing is selected and emptySelectionAction is SelectPrevious', () => {
it('reverts to the previous selection', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 2000 },
mode: SelectionMode.Selecting,
emptySelectionAction: EmptySelectionAction.SelectNothing,
},
{ type: 'mouseup', x: 0 }
);
expect(state.mode).toEqual(SelectionMode.Normal);
expect(state.selection).toEqual({ start: 1000, end: 2000 });
});
});
});
describe('mouseup', () => {
it('sets the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 2000, end: 3000 },
mode: SelectionMode.Dragging,
mousedownX: 475,
},
{ type: 'mouseleave', x: 500 }
);
expect(state.mode).toEqual(SelectionMode.Dragging);
expect(state.selection).toEqual({ start: 2000, end: 3000 });
expect(state.mousedownX).toEqual(475);
});
});
describe('mousemove', () => {
describe('in normal mode', () => {
describe('when hovering over the selection start', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 3000 },
mode: SelectionMode.Normal,
},
{ type: 'mousemove', x: 997 }
);
expect(state.mode).toEqual(SelectionMode.Normal);
expect(state.selection).toEqual({ start: 1000, end: 3000 });
expect(state.hoverState).toEqual(HoverState.OverSelectionStart);
});
});
describe('when hovering over the selection end', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 3000 },
mode: SelectionMode.Normal,
},
{ type: 'mousemove', x: 3009 }
);
expect(state.mode).toEqual(SelectionMode.Normal);
expect(state.selection).toEqual({ start: 1000, end: 3000 });
expect(state.hoverState).toEqual(HoverState.OverSelectionEnd);
});
});
describe('when hovering over the selection', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 3000 },
mode: SelectionMode.Normal,
},
{ type: 'mousemove', x: 1200 }
);
expect(state.mode).toEqual(SelectionMode.Normal);
expect(state.selection).toEqual({ start: 1000, end: 3000 });
expect(state.hoverState).toEqual(HoverState.OverSelection);
});
});
describe('when hovering elsewhere', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 3000 },
mode: SelectionMode.Normal,
},
{ type: 'mousemove', x: 10 }
);
expect(state.mode).toEqual(SelectionMode.Normal);
expect(state.selection).toEqual({ start: 1000, end: 3000 });
expect(state.hoverState).toEqual(HoverState.Normal);
});
});
});
describe('in selecting mode', () => {
describe('a normal selection', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 2000, end: 3000 },
mode: SelectionMode.Selecting,
mousedownX: 2000,
},
{ type: 'mousemove', x: 3005 }
);
expect(state.mode).toEqual(SelectionMode.Selecting);
expect(state.selection).toEqual({ start: 2000, end: 3005 });
});
});
describe('when crossing over', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 2000, end: 2002 },
mode: SelectionMode.Selecting,
mousedownX: 2000,
},
{ type: 'mousemove', x: 1995 }
);
expect(state.mode).toEqual(SelectionMode.Selecting);
expect(state.selection).toEqual({ start: 1995, end: 2000 });
});
});
});
describe('in dragging mode', () => {
describe('in the middle of the canvas', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 1500 },
origSelection: { start: 1000, end: 1500 },
mode: SelectionMode.Dragging,
mousedownX: 1200,
},
{ type: 'mousemove', x: 1220 }
);
expect(state.mode).toEqual(SelectionMode.Dragging);
expect(state.selection).toEqual({ start: 1020, end: 1520 });
});
});
describe('at the start of the canvas', () => {
it('constrains the movement and updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 10, end: 210 },
origSelection: { start: 10, end: 210 },
mode: SelectionMode.Dragging,
mousedownX: 50,
},
{ type: 'mousemove', x: 30 }
);
expect(state.mode).toEqual(SelectionMode.Dragging);
expect(state.selection).toEqual({ start: 0, end: 200 });
});
});
describe('at the end of the canvas', () => {
it('constrains the movement and updates the state', () => {
const state = stateReducer(
{
...initialState,
width: 3000,
selection: { start: 2800, end: 2900 },
origSelection: { start: 2800, end: 2900 },
mode: SelectionMode.Dragging,
mousedownX: 1200,
},
{ type: 'mousemove', x: 1350 }
);
expect(state.mode).toEqual(SelectionMode.Dragging);
expect(state.selection).toEqual({ start: 2900, end: 3000 });
});
});
});
describe('in resizing start mode', () => {
describe('a normal resize', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 2000, end: 3000 },
origSelection: { start: 2000, end: 3000 },
mode: SelectionMode.ResizingStart,
},
{ type: 'mousemove', x: 2020 }
);
expect(state.mode).toEqual(SelectionMode.ResizingStart);
expect(state.selection).toEqual({ start: 2020, end: 3000 });
});
});
describe('when crossing over', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 2000, end: 2002 },
origSelection: { start: 2000, end: 2002 },
mode: SelectionMode.ResizingStart,
},
{ type: 'mousemove', x: 2010 }
);
expect(state.mode).toEqual(SelectionMode.ResizingStart);
expect(state.selection).toEqual({ start: 2002, end: 2010 });
});
});
});
describe('in resizing end mode', () => {
describe('a normal resize', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 1000, end: 2000 },
origSelection: { start: 1000, end: 2000 },
mode: SelectionMode.ResizingEnd,
},
{ type: 'mousemove', x: 2007 }
);
expect(state.mode).toEqual(SelectionMode.ResizingEnd);
expect(state.selection).toEqual({ start: 1000, end: 2007 });
});
});
describe('when crossing over', () => {
it('updates the state', () => {
const state = stateReducer(
{
...initialState,
selection: { start: 2000, end: 2002 },
origSelection: { start: 2000, end: 2002 },
mode: SelectionMode.ResizingEnd,
},
{ type: 'mousemove', x: 1995 }
);
expect(state.mode).toEqual(SelectionMode.ResizingEnd);
expect(state.selection).toEqual({ start: 1995, end: 2000 });
});
});
});
});
});