From a855d589f3a1159829e70eb485942e088284278c Mon Sep 17 00:00:00 2001 From: Rob Watson Date: Thu, 3 Feb 2022 19:44:28 +0100 Subject: [PATCH] Refactor HudCanvasState tests --- frontend/src/HudCanvasState.test.ts | 540 ++++++++++++---------------- 1 file changed, 220 insertions(+), 320 deletions(-) diff --git a/frontend/src/HudCanvasState.test.ts b/frontend/src/HudCanvasState.test.ts index 8a04a3f..ae42cf0 100644 --- a/frontend/src/HudCanvasState.test.ts +++ b/frontend/src/HudCanvasState.test.ts @@ -31,110 +31,91 @@ describe('stateReducer', () => { }); }); - 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); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - 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); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - 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); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - 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); - expect(state.shouldPublish).toBeTruthy(); - }); + describe.each([ + { + name: 'entering resizing start', + x: 995, + selection: { start: 1000, end: 2000 }, + wantMode: SelectionMode.ResizingStart, + wantSelection: { start: 1000, end: 2000 }, + }, + { + name: 'entering resizing end', + x: 2003, + selection: { start: 1000, end: 2000 }, + wantMode: SelectionMode.ResizingEnd, + wantSelection: { start: 1000, end: 2000 }, + }, + { + name: 'entering dragging', + x: 1500, + selection: { start: 1000, end: 2000 }, + wantMode: SelectionMode.Dragging, + wantSelection: { start: 1000, end: 2000 }, + }, + { + name: 'entering selecting', + x: 10, + selection: { start: 1000, end: 2000 }, + wantMode: SelectionMode.Selecting, + wantSelection: { start: 10, end: 10 }, + }, + ])('mousedown', ({ name, x, selection, wantMode, wantSelection }) => { + test(`${name} generates the expected state`, () => { + const state = stateReducer( + { ...initialState, selection: selection }, + { type: 'mousedown', x: x } + ); + expect(state.mode).toEqual(wantMode); + expect(state.selection).toEqual(wantSelection); + expect(state.mousedownX).toEqual(x); + expect(state.shouldPublish).toBeTruthy(); }); }); - describe('mouseup', () => { - describe('when re-entering normal mode', () => { - it('updates the state', () => { + describe.each([ + { + name: 're-entering normal mode', + x: 1200, + selection: { start: 1000, end: 2000 }, + emptySelectionAction: EmptySelectionAction.SelectNothing, + wantSelection: { start: 1000, end: 2000 }, + }, + { + name: 'when nothing is selected and emptySelectionAction is SelectNothing', + x: 1200, + selection: { start: 1000, end: 1000 }, + emptySelectionAction: EmptySelectionAction.SelectNothing, + wantSelection: { start: 1200, end: 1200 }, + }, + { + // TODO: broken + name: 'when nothing is selected and emptySelectionAction is SelectPrevious', + x: 1200, + selection: { start: 1000, end: 2000 }, + emptySelectionAction: EmptySelectionAction.SelectPrevious, + wantSelection: { start: 1000, end: 2000 }, + }, + ])( + 'mouseup', + ({ name, x, selection, emptySelectionAction, wantSelection }) => { + test(`${name} generates the expected state`, () => { const state = stateReducer( { ...initialState, - selection: { start: 1000, end: 2000 }, + selection: selection, mode: SelectionMode.Selecting, - mousedownX: 1200, + emptySelectionAction: emptySelectionAction, }, - { type: 'mouseup', x: 0 } + { type: 'mouseup', x: x } ); expect(state.mode).toEqual(SelectionMode.Normal); - expect(state.selection).toEqual({ start: 1000, end: 2000 }); - expect(state.mousedownX).toEqual(1200); + expect(state.prevMode).toEqual(SelectionMode.Selecting); + expect(state.selection).toEqual(wantSelection); expect(state.shouldPublish).toBeTruthy(); }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - }); + } + ); describe('mouseleave', () => { it('sets the state', () => { @@ -155,239 +136,158 @@ describe('stateReducer', () => { }); describe('mousemove', () => { - describe('in normal mode', () => { - describe('when hovering over the selection start', () => { - it('updates the state', () => { + describe.each([ + // Normal mode + { + name: 'hovering over selection start', + mode: SelectionMode.Normal, + x: 997, + selection: { start: 1000, end: 3000 }, + wantHoverState: HoverState.OverSelectionStart, + shouldPublish: false, + }, + { + name: 'hovering over selection end', + mode: SelectionMode.Normal, + x: 3009, + selection: { start: 1000, end: 3000 }, + wantHoverState: HoverState.OverSelectionEnd, + shouldPublish: false, + }, + { + name: 'hovering over selection', + mode: SelectionMode.Normal, + x: 1200, + selection: { start: 1000, end: 3000 }, + wantHoverState: HoverState.OverSelection, + shouldPublish: false, + }, + { + name: 'hovering elsewhere', + mode: SelectionMode.Normal, + x: 300, + selection: { start: 1000, end: 3000 }, + wantHoverState: HoverState.Normal, + shouldPublish: false, + }, + // Selecting mode + { + name: 'when not crossing over', + mode: SelectionMode.Selecting, + x: 3005, + mousedownX: 2000, + selection: { start: 2000, end: 3000 }, + wantSelection: { start: 2000, end: 3005 }, + shouldPublish: true, + }, + { + name: 'when crossing over', + mode: SelectionMode.Selecting, + x: 1995, + mousedownX: 2000, + selection: { start: 2000, end: 2002 }, + wantSelection: { start: 1995, end: 2000 }, + shouldPublish: true, + }, + // Dragging mode + { + name: 'in the middle of the canvas', + mode: SelectionMode.Dragging, + x: 1220, + mousedownX: 1200, + selection: { start: 1000, end: 1500 }, + origSelection: { start: 1000, end: 1500 }, + wantSelection: { start: 1020, end: 1520 }, + shouldPublish: true, + }, + { + name: 'at the start of the canvas', + mode: SelectionMode.Dragging, + x: 30, + mousedownX: 50, + selection: { start: 10, end: 210 }, + origSelection: { start: 10, end: 210 }, + wantSelection: { start: 0, end: 200 }, + shouldPublish: true, + }, + { + name: 'at the end of the canvas', + mode: SelectionMode.Dragging, + x: 1400, + mousedownX: 1250, + selection: { start: 4800, end: 4900 }, + origSelection: { start: 4800, end: 4900 }, + wantSelection: { start: 4900, end: 5000 }, + shouldPublish: true, + }, + // ResizingStart mode + { + name: 'when not crossing over', + mode: SelectionMode.ResizingStart, + x: 2020, + selection: { start: 2000, end: 3000 }, + origSelection: { start: 2000, end: 3000 }, + wantSelection: { start: 2020, end: 3000 }, + shouldPublish: true, + }, + { + name: 'when crossing over', + mode: SelectionMode.ResizingStart, + x: 2010, + selection: { start: 2000, end: 2002 }, + origSelection: { start: 2000, end: 2002 }, + wantSelection: { start: 2002, end: 2010 }, + shouldPublish: true, + }, + // ResizingEnd mode + { + name: 'when not crossing over', + mode: SelectionMode.ResizingEnd, + x: 2007, + selection: { start: 1000, end: 2000 }, + origSelection: { start: 1000, end: 2000 }, + wantSelection: { start: 1000, end: 2007 }, + shouldPublish: true, + }, + { + name: 'when crossing over', + mode: SelectionMode.ResizingEnd, + x: 1995, + selection: { start: 2000, end: 2002 }, + origSelection: { start: 2000, end: 2002 }, + wantSelection: { start: 1995, end: 2000 }, + shouldPublish: true, + }, + ])( + 'mousemove', + ({ + name, + mode, + x, + mousedownX = 0, + selection, + origSelection = { start: 0, end: 0 }, + wantSelection = selection, + wantHoverState = HoverState.Normal, + shouldPublish, + }) => { + test(`${SelectionMode[mode]} mode: ${name} generates the expected state`, () => { const state = stateReducer( { ...initialState, - selection: { start: 1000, end: 3000 }, - mode: SelectionMode.Normal, + selection: selection, + origSelection: origSelection, + mode: mode, + mousedownX: mousedownX, }, - { type: 'mousemove', x: 997 } + { type: 'mousemove', x: x } ); - expect(state.mode).toEqual(SelectionMode.Normal); - expect(state.selection).toEqual({ start: 1000, end: 3000 }); - expect(state.hoverState).toEqual(HoverState.OverSelectionStart); - expect(state.shouldPublish).toBeFalsy(); + expect(state.mode).toEqual(mode); + expect(state.selection).toEqual(wantSelection); + expect(state.hoverState).toEqual(wantHoverState); + expect(state.shouldPublish).toEqual(shouldPublish); }); - }); - - 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); - expect(state.shouldPublish).toBeFalsy(); - }); - }); - - 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); - expect(state.shouldPublish).toBeFalsy(); - }); - }); - - 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); - expect(state.shouldPublish).toBeFalsy(); - }); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - - 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 }); - expect(state.shouldPublish).toBeTruthy(); - }); - }); - }); + } + ); }); });