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 }); }); }); }); }); });