diff --git a/test/unit/view/connected-draggable.spec.old.js b/test/unit/view/connected-draggable.spec.old.js deleted file mode 100644 index 799a7f467d..0000000000 --- a/test/unit/view/connected-draggable.spec.old.js +++ /dev/null @@ -1,1249 +0,0 @@ -// @flow -/* eslint-disable react/no-multi-comp */ -import React, { Component } from 'react'; -import { mount } from 'enzyme'; -import { type Position } from 'css-box-model'; -import Draggable, { makeMapStateToProps } from '../../../src/view/draggable/connected-draggable'; -import { getPreset } from '../../utils/dimension'; -import { negate, add } from '../../../src/state/position'; -import createDimensionMarshal from '../../../src/state/dimension-marshal/dimension-marshal'; -import getStatePreset from '../../utils/get-simple-state-preset'; -import { -combine, - withStore, - withDroppableId, - withDimensionMarshal, - withStyleContext, - withCanLift, -} from '../../utils/get-context-options'; -import forceUpdate from '../../utils/force-update'; -import getHomeImpact from '../../../src/state/get-home-impact'; -import noImpact from '../../../src/state/no-impact'; -import getPageItemPositions from '../../../src/state/get-page-item-positions'; -import type { DimensionMarshal } from '../../../src/state/dimension-marshal/dimension-marshal-types'; -import type { - Selector, - OwnProps, - MapProps, - Provided, -} from '../../../src/view/draggable/draggable-types'; -import type { - State, - ItemPositions, - DragImpact, - DraggableDimension, - DraggableLocation, - DraggingState, - CollectingState, - DropPendingState, -} from '../../../src/types'; - -const preset = getPreset(); -const state = getStatePreset(); - -type IsDraggingState = DraggingState | CollectingState | DropPendingState - -const move = (previous: IsDraggingState, offset: Position): IsDraggingState => { - const client: ItemPositions = { - offset, - selection: add(previous.initial.client.selection, offset), - borderBoxCenter: add(previous.initial.client.borderBoxCenter, offset), - }; - const page: ItemPositions = getPageItemPositions(client, previous.viewport.scroll.current); - - return { - // appeasing flow - phase: 'DRAGGING', - ...previous, - // eslint-disable-next-line - phase: previous.phase, - current: { - client, page, - }, - }; -}; - -const getOwnProps = (dimension: DraggableDimension): OwnProps => ({ - draggableId: dimension.descriptor.id, - index: dimension.descriptor.index, - isDragDisabled: false, - disableInteractiveElementBlocking: false, - children: () => null, -}); - -describe('Connected Draggable', () => { - beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(() => { }); - }); - - afterEach(() => { - console.error.mockRestore(); - }); - - describe.only('is currently dragging', () => { - const ownProps: OwnProps = getOwnProps(preset.inHome1); - const draggingStates: IsDraggingState[] = [ - state.dragging(), - state.collecting(), - state.dropPending(), - ]; - - draggingStates.forEach((current: IsDraggingState) => { - describe(`in phase: ${current.phase}`, () => { - it('should move the dragging item to the current offset', () => { - const selector: Selector = makeMapStateToProps(); - - const result: MapProps = selector( - move(current, { x: 20, y: 30 }), - ownProps - ); - - const expected: MapProps = { - isDropAnimating: false, - isDragging: true, - offset: { x: 20, y: 30 }, - shouldAnimateDragMovement: false, - shouldAnimateDisplacement: false, - dimension: preset.inHome1, - draggingOver: preset.home.descriptor.id, - }; - expect(result).toEqual(expected); - }); - - it('should control drag animation', () => { - const selector: Selector = makeMapStateToProps(); - const withAnimation: IsDraggingState = ({ - ...current, - shouldAnimate: true, - }: any); - - expect(selector(withAnimation, ownProps).shouldAnimateDragMovement).toBe(true); - - const withoutAnimation: IsDraggingState = ({ - ...current, - shouldAnimate: false, - }: any); - - expect(selector(withoutAnimation, ownProps).shouldAnimateDragMovement).toBe(false); - }); - - it('should not break memoization on multiple calls to the same offset', () => { - const selector: Selector = makeMapStateToProps(); - - const result1: MapProps = selector( - move(current, { x: 100, y: 200 }), - ownProps - ); - const result2: MapProps = selector( - move(current, { x: 100, y: 200 }), - ownProps - ); - - expect(result1).toBe(result2); - - // also checking with new top level reference - const newCurrent: IsDraggingState = ({ ...current }: any); - const result3: MapProps = selector( - move(newCurrent, { x: 100, y: 200 }), - ownProps - ); - - expect(result1).toBe(result3); - }); - - it('should break memoization on multiple calls if moving to a new position', () => { - const selector: Selector = makeMapStateToProps(); - - const result1: MapProps = selector( - move(current, { x: 100, y: 200 }), - ownProps - ); - const result2: MapProps = selector( - move(current, { x: 101, y: 200 }), - ownProps - ); - - expect(result1).not.toBe(result2); - expect(result1).not.toEqual(result2); - }); - - it('should indicate when over a droppable', () => { - const selector: Selector = makeMapStateToProps(); - - const inHome: IsDraggingState = ({ - ...current, - impact: getHomeImpact(state.critical, preset.dimensions), - }: any); - const noWhere: IsDraggingState = ({ - ...current, - impact: noImpact, - }: any); - - expect(selector(inHome, ownProps).draggingOver).toBe(state.critical.droppable.id), - expect(selector(noWhere, ownProps).draggingOver).toBe(null); - }) - }); - }); - - it('should not break memoization when moving between dragging phases', () => { - const selector: Selector = makeMapStateToProps(); - - const first: MapProps = selector(state.dragging(), ownProps); - const second: MapProps = selector(state.collecting(), ownProps); - const third: MapProps = selector(state.dropPending(), ownProps); - - expect(first).toBe(second); - expect(second).toBe(third); - }); - - describe('is not over a droppable', () => { - it('should move the dragging item to the current offset', () => { - const selector: Selector = makeMapStateToProps(); - - const result: MapProps = selector( - move(state.dragging(), { x: 20, y: 30 }), - ownProps - ); - - const expected: MapProps = { - isDropAnimating: false, - isDragging: true, - offset: { x: 20, y: 30 }, - shouldAnimateDragMovement: false, - shouldAnimateDisplacement: false, - dimension: preset.inHome1, - draggingOver: preset.home.descriptor.id, - }; - expect(result).toEqual(expected); - }); - - it('should control whether drag movement is allowed based the current state', () => { - const selector: Selector = makeMapStateToProps(); - const previous: State = move(state.dragging(), { x: 20, y: 30 }); - - // drag animation is allowed - const allowed: State = { - ...previous, - drag: { - ...previous.drag, - current: { - // $ExpectError - not checking for null - ...previous.drag.current, - shouldAnimate: true, - }, - }, - }; - expect(selector(allowed, ownProps).shouldAnimateDragMovement).toBe(true); - - // drag animation is not allowed - const notAllowed: State = { - ...previous, - drag: { - ...previous.drag, - current: { - // $ExpectError - not checking for null - ...previous.drag.current, - shouldAnimate: false, - }, - }, - }; - expect(selector(notAllowed, ownProps).shouldAnimateDragMovement).toBe(false); - }); - - it('should not break memoization on multiple calls to the same offset', () => { - const selector: Selector = makeMapStateToProps(); - - const result1: MapProps = selector( - move(state.dragging(), { x: 100, y: 200 }), - ownProps - ); - const result2: MapProps = selector( - move(state.dragging(), { x: 100, y: 200 }), - ownProps - ); - - expect(result1).toBe(result2); - expect(selector.recomputations()).toBe(1); - }); - - it('should break memoization on multiple calls if moving to a new position', () => { - const selector: Selector = makeMapStateToProps(); - - const result1: MapProps = selector( - move(state.dragging(), { x: 100, y: 200 }), - ownProps - ); - const result2: MapProps = selector( - move({ ...state.dragging() }, { x: 101, y: 200 }), - ownProps - ); - - expect(result1).not.toBe(result2); - expect(result1).not.toEqual(result2); - expect(selector.recomputations()).toBe(2); - }); - - describe('drop animating', () => { - it('should log an error when there is invalid drag state', () => { - const invalid: State = { - ...state.dropAnimating(), - drop: null, - }; - const selector: Selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - - const result: MapProps = selector(invalid, ownProps); - - expect(result).toBe(defaultMapProps); - expect(console.error).toHaveBeenCalled(); - }); - - it('should move the draggable to the new offset', () => { - const selector: Selector = makeMapStateToProps(); - const current: State = state.dropAnimating(); - - const result: MapProps = selector( - current, - ownProps, - ); - - expect(result).toEqual({ - // no longer dragging - isDragging: false, - // is now drop animating - isDropAnimating: true, - // $ExpectError - not testing for null - offset: current.drop.pending.newHomeOffset, - dimension: preset.inHome1, - direction: null, - // animation now controlled by isDropAnimating flag - shouldAnimateDisplacement: false, - shouldAnimateDragMovement: false, - draggingOver: null, - }); - }); - }); - - describe('user cancel', () => { - it('should move the draggable to the new offset', () => { - const selector: Selector = makeMapStateToProps(); - const current: State = state.userCancel(); - - const result: MapProps = selector( - current, - ownProps, - ); - - expect(result).toEqual({ - // no longer dragging - isDragging: false, - // is now drop animating - isDropAnimating: true, - // $ExpectError - not testing for null - offset: current.drop.pending.newHomeOffset, - dimension: preset.inHome1, - direction: null, - // animation now controlled by isDropAnimating flag - shouldAnimateDisplacement: false, - shouldAnimateDragMovement: false, - draggingOver: null, - }); - }); - }); - }); - - describe('is over a droppable (test subset)', () => { - it('should move the dragging item to the current offset', () => { - const selector: Selector = makeMapStateToProps(); - - const result: MapProps = selector( - withImpact( - move(state.dragging(), { x: 20, y: 30 }), - getInitialImpact(preset.inHome1), - ), - ownProps - ); - - expect(result).toEqual({ - isDropAnimating: false, - isDragging: true, - offset: { x: 20, y: 30 }, - shouldAnimateDragMovement: false, - shouldAnimateDisplacement: false, - dimension: preset.inHome1, - direction: preset.home.axis.direction, - draggingOver: preset.home.descriptor.id, - }); - }); - - it('should not break memoization on multiple calls to the same offset', () => { - const selector: Selector = makeMapStateToProps(); - - const result1: MapProps = selector( - withImpact( - move(state.dragging(), { x: 100, y: 200 }), - getInitialImpact(preset.inHome1), - ), - ownProps - ); - const result2: MapProps = selector( - withImpact( - move(state.dragging(), { x: 100, y: 200 }), - getInitialImpact(preset.inHome1), - ), - ownProps - ); - - expect(result1).toBe(result2); - expect(selector.recomputations()).toBe(1); - }); - - it('should break memoization on multiple calls if moving to a new position', () => { - const selector: Selector = makeMapStateToProps(); - - const result1: MapProps = selector( - withImpact( - move(state.dragging(), { x: 100, y: 200 }), - getInitialImpact(preset.inHome1) - ), - ownProps - ); - const result2: MapProps = selector( - withImpact( - move({ ...state.dragging() }, { x: 101, y: 200 }), - getInitialImpact(preset.inHome1), - ), - ownProps - ); - - expect(result1).not.toBe(result2); - expect(result1).not.toEqual(result2); - expect(selector.recomputations()).toBe(2); - }); - - describe('drop animating', () => { - it('should move the draggable to the new offset', () => { - const selector: Selector = makeMapStateToProps(); - const destination: DraggableLocation = { - index: preset.inHome1.descriptor.index, - droppableId: preset.inHome1.descriptor.droppableId, - }; - const current: State = withImpact( - state.dropAnimating(), - getInitialImpact(preset.inHome1) - ); - if (!current.drop || !current.drop.pending) { - throw new Error('invalid test setup'); - } - current.drop.pending.result.destination = destination; - - const result: MapProps = selector( - current, - ownProps, - ); - - expect(result).toEqual({ - // no longer dragging - isDragging: false, - // is now drop animating - isDropAnimating: true, - // $ExpectError - not testing for null - offset: current.drop.pending.newHomeOffset, - dimension: preset.inHome1, - direction: preset.home.axis.direction, - draggingOver: preset.home.descriptor.id, - // animation now controlled by isDropAnimating flag - shouldAnimateDisplacement: false, - shouldAnimateDragMovement: false, - }); - }); - }); - - describe('user cancel', () => { - it('should move the draggable to the new offset', () => { - const selector: Selector = makeMapStateToProps(); - const destination: DraggableLocation = { - index: preset.inHome1.descriptor.index, - droppableId: preset.inHome1.descriptor.droppableId, - }; - const current: State = withImpact( - state.userCancel(), - getInitialImpact(preset.inHome1) - ); - if (!current.drop || !current.drop.pending) { - throw new Error('invalid test setup'); - } - current.drop.pending.result.destination = destination; - - const result: MapProps = selector( - current, - ownProps, - ); - - expect(result).toEqual({ - // no longer dragging - isDragging: false, - // is now drop animating - isDropAnimating: true, - // $ExpectError - not testing for null - offset: current.drop.pending.newHomeOffset, - dimension: preset.inHome1, - direction: preset.home.axis.direction, - draggingOver: preset.home.descriptor.id, - // animation now controlled by isDropAnimating flag - shouldAnimateDisplacement: false, - shouldAnimateDragMovement: false, - }); - }); - }); - }); - }); - - describe('something else is dragging', () => { - describe('nothing impacted by drag', () => { - const ownProps: OwnProps = getOwnProps(preset.inHome2); - - it('should log an error when there is invalid drag state', () => { - const invalid: State = { - ...state.dragging(), - drag: null, - }; - const selector: Selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - - const result: MapProps = selector(invalid, ownProps); - - expect(result).toBe(defaultMapProps); - expect(console.error).toHaveBeenCalled(); - }); - - it('should return the default map props', () => { - const selector: Selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - - const result: MapProps = selector( - state.dragging(preset.inHome1.descriptor.id), - ownProps - ); - - expect(result).toBe(defaultMapProps); - }); - - it('should not break memoization on multiple calls', () => { - const selector: Selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - - const result1: MapProps = selector( - move(state.dragging(preset.inHome1.descriptor.id), { x: 10, y: 40 }), - ownProps - ); - const result2: MapProps = selector( - move(state.dragging(preset.inHome1.descriptor.id), { x: 15, y: 60 }), - ownProps - ); - - expect(result1).toBe(defaultMapProps); - expect(result1).toBe(result2); - expect(selector.recomputations()).toBe(1); - }); - }); - - describe('other draggables impacted - but not this one', () => { - it('should return the default props', () => { - // looking at inHome3 - const ownProps: OwnProps = getOwnProps(preset.inHome3); - const selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - // moving inHome1 down beyond inHome2 - const impact: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount: { y: preset.inHome1.client.marginBox.height, x: 0 }, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - const previous: State = state.dragging(preset.inHome1.descriptor.id); - const current: State = { - ...previous, - drag: { - ...previous.drag, - impact, - }, - }; - - const result: MapProps = selector(current, ownProps); - - expect(result).toEqual(defaultMapProps); - }); - - it('should not break memoization if not needing to move - even if other things draggables are', () => { - // looking at inHome4 - const ownProps: OwnProps = { - draggableId: preset.inHome4.descriptor.id, - index: preset.inHome4.descriptor.index, - isDragDisabled: false, - disableInteractiveElementBlocking: false, - children: () => null, - }; - - const selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - // moving inHome1 down beyond inHome2 - const impact1: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount: { y: preset.inHome1.client.marginBox.height, x: 0 }, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - // moving inHome1 down beyond inHome3 - const impact2: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 2, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount: { y: preset.inHome1.client.marginBox.height, x: 0 }, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - { - draggableId: preset.inHome3.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - const original: State = state.dragging(preset.inHome1.descriptor.id); - const first: State = { - ...original, - drag: { - ...original.drag, - impact: impact1, - }, - }; - const second: State = { - ...first, - drag: { - ...first.drag, - impact: impact2, - }, - }; - - const result1: MapProps = selector(first, ownProps); - const result2: MapProps = selector(second, ownProps); - - expect(result1).toEqual(defaultMapProps); - expect(result1).toBe(result2); - }); - }); - - describe('impacted by the drag', () => { - it('should move in backwards if the dragging item is moving beyond its start position', () => { - // looking at inHome2 - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const selector = makeMapStateToProps(); - const amount: Position = { y: preset.inHome1.client.marginBox.height, x: 0 }; - // moving inHome1 down beyond inHome2 - const impact: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - const previous: State = state.dragging(preset.inHome1.descriptor.id); - const current: State = { - ...previous, - drag: { - ...previous.drag, - impact, - }, - }; - - const result: MapProps = selector(current, ownProps); - - expect(result).toEqual({ - isDragging: false, - isDropAnimating: false, - // moving backwards - offset: negate(amount), - shouldAnimateDisplacement: true, - shouldAnimateDragMovement: false, - dimension: null, - direction: null, - draggingOver: null, - }); - }); - - it('should move forwards if the dragging item is not beyond its start position', () => { - // looking at inHome1 - const ownProps: OwnProps = getOwnProps(preset.inHome1); - const selector = makeMapStateToProps(); - const amount: Position = { y: preset.inHome2.client.marginBox.height, x: 0 }; - // moving inHome2 up beyond inHome1 - const impact: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 0, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: false, - displaced: [ - { - draggableId: preset.inHome1.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - const previous: State = state.dragging(preset.inHome2.descriptor.id); - const current: State = { - ...previous, - drag: { - ...previous.drag, - impact, - }, - }; - - const result: MapProps = selector(current, ownProps); - - expect(result).toEqual({ - isDragging: false, - isDropAnimating: false, - // moving forwards - offset: amount, - shouldAnimateDisplacement: true, - shouldAnimateDragMovement: false, - dimension: null, - direction: null, - draggingOver: null, - }); - }); - - it('should not move the item and return the default map props if the displacement is not visible', () => { - // looking at inHome2 - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - const amount: Position = { y: preset.inHome1.client.marginBox.height, x: 0 }; - // moving inHome1 down beyond inHome2 - const impact: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: false, - shouldAnimate: true, - }, - ], - }, - }; - const previous: State = state.dragging(preset.inHome1.descriptor.id); - const current: State = { - ...previous, - drag: { - ...previous.drag, - impact, - }, - }; - - const result: MapProps = selector(current, ownProps); - - expect(result).toBe(defaultMapProps); - }); - - it('should indicate whether the displacement should be animated based on the drag impact', () => { - // looking at inHome2 - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const selector = makeMapStateToProps(); - const amount: Position = { y: preset.inHome1.client.marginBox.height, x: 0 }; - // moving inHome1 down beyond inHome2 - const impact: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: false, - }, - ], - }, - }; - const previous: State = state.dragging(preset.inHome1.descriptor.id); - const current: State = { - ...previous, - drag: { - ...previous.drag, - impact, - }, - }; - - const result: MapProps = selector(current, ownProps); - - expect(result).toEqual({ - isDragging: false, - isDropAnimating: false, - // moving backwards - offset: negate(amount), - shouldAnimateDisplacement: false, - shouldAnimateDragMovement: false, - dimension: null, - direction: null, - draggingOver: null, - }); - }); - - it('should not break memoization on multiple calls if displaced and remain displaced', () => { - // looking at inHome4 - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const selector = makeMapStateToProps(); - const amount: Position = { y: preset.inHome1.client.marginBox.height, x: 0 }; - // moving inHome1 down beyond inHome2 - const impact1: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - // moving inHome1 down beyond inHome3 - // inHome2 is still displaced - const impact2: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 2, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - { - draggableId: preset.inHome3.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - const original: State = state.dragging(preset.inHome1.descriptor.id); - const first: State = { - ...original, - drag: { - ...original.drag, - impact: impact1, - }, - }; - const second: State = { - ...first, - drag: { - ...first.drag, - impact: impact2, - }, - }; - - const result1: MapProps = selector(first, ownProps); - const result2: MapProps = selector(second, ownProps); - - // checking memoization - expect(result1).toBe(result2); - expect(selector.recomputations()).toBe(1); - // validating result - expect(result1).toEqual({ - isDragging: false, - isDropAnimating: false, - // moving backwards - offset: negate(amount), - shouldAnimateDisplacement: true, - shouldAnimateDragMovement: false, - dimension: null, - direction: null, - draggingOver: null, - }); - }); - - describe('drop animating', () => { - it('should log an error when there is invalid drag state', () => { - const invalid: State = { - ...state.dropAnimating(), - // invalid - drop: null, - }; - const selector: Selector = makeMapStateToProps(); - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - - const result: MapProps = selector(invalid, ownProps); - - expect(result).toBe(defaultMapProps); - expect(console.error).toHaveBeenCalled(); - }); - - it('should not break memoization from the dragging phase', () => { - // looking at inHome2 - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const selector = makeMapStateToProps(); - const amount: Position = { y: preset.inHome1.client.marginBox.height, x: 0 }; - // moving inHome1 down beyond inHome2 - const impact: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - const dragging: State = (() => { - const previous: State = state.dragging(preset.inHome1.descriptor.id); - return { - ...previous, - drag: { - ...previous.drag, - impact, - }, - }; - })(); - const dropping: State = (() => { - const previous: State = state.dropAnimating(preset.inHome1.descriptor.id); - return { - ...previous, - drop: { - ...previous.drop, - pending: { - // $ExpectError - not checking for null - ...previous.drop.pending, - impact, - }, - }, - }; - })(); - - const duringDrag: MapProps = selector(dragging, ownProps); - const duringDrop: MapProps = selector(dropping, ownProps); - - // memoization check - expect(duringDrag).toBe(duringDrop); - expect(selector.recomputations()).toBe(1); - // validating result - expect(duringDrop).toEqual({ - isDragging: false, - isDropAnimating: false, - // moving backwards - offset: negate(amount), - shouldAnimateDisplacement: true, - shouldAnimateDragMovement: false, - dimension: null, - direction: null, - draggingOver: null, - }); - }); - }); - - describe('drop animating', () => { - it('should log an error when there is invalid drag state', () => { - const invalid: State = { - ...state.userCancel(), - // invalid - drop: null, - }; - const selector: Selector = makeMapStateToProps(); - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - - const result: MapProps = selector(invalid, ownProps); - - expect(result).toBe(defaultMapProps); - expect(console.error).toHaveBeenCalled(); - }); - - it('should not break memoization from the dragging phase', () => { - // looking at inHome2 - const ownProps: OwnProps = getOwnProps(preset.inHome2); - const selector = makeMapStateToProps(); - const amount: Position = { y: preset.inHome1.client.marginBox.height, x: 0 }; - // moving inHome1 down beyond inHome2 - const impact: DragImpact = { - direction: preset.home.axis.direction, - destination: { - index: 1, - droppableId: preset.home.descriptor.id, - }, - movement: { - amount, - isBeyondStartPosition: true, - displaced: [ - { - draggableId: preset.inHome2.descriptor.id, - isVisible: true, - shouldAnimate: true, - }, - ], - }, - }; - const dragging: State = (() => { - const previous: State = state.dragging(preset.inHome1.descriptor.id); - return { - ...previous, - drag: { - ...previous.drag, - impact, - }, - }; - })(); - const dropping: State = (() => { - const previous: State = state.userCancel(preset.inHome1.descriptor.id); - return { - ...previous, - drop: { - ...previous.drop, - pending: { - // $ExpectError - not checking for null - ...previous.drop.pending, - impact, - }, - }, - }; - })(); - - const duringDrag: MapProps = selector(dragging, ownProps); - const duringUserCancel: MapProps = selector(dropping, ownProps); - - // memoization check - expect(duringDrag).toBe(duringUserCancel); - expect(selector.recomputations()).toBe(1); - // validating result - expect(duringUserCancel).toEqual({ - isDragging: false, - isDropAnimating: false, - // moving backwards - offset: negate(amount), - shouldAnimateDisplacement: true, - shouldAnimateDragMovement: false, - dimension: null, - direction: null, - draggingOver: null, - }); - }); - }); - }); - }); - - describe('nothing is dragging', () => { - it('should return the default map props and not break memoization on multiple calls', () => { - const resting: State[] = [ - state.idle, - state.dropComplete(), - ]; - const ownProps: OwnProps = getOwnProps(preset.inHome1); - const selector: Selector = makeMapStateToProps(); - const defaultMapProps: MapProps = selector(state.idle, ownProps); - - [...resting, ...resting.reverse()].forEach((current: State) => { - Array.from({ length: 3 }).forEach(() => { - const result: MapProps = selector(current, ownProps); - expect(result).toBe(defaultMapProps); - }); - }); - }); - }); - - describe('selector isolation', () => { - it('should not break memoization across selectors', () => { - const inHome1Selector: Selector = makeMapStateToProps(); - const inHome1OwnProps: OwnProps = getOwnProps(preset.inHome1); - const inHome2Selector: Selector = makeMapStateToProps(); - const inHome2OwnProps: OwnProps = getOwnProps(preset.inHome2); - const defaultInHome2MapProps: MapProps = inHome2Selector(state.idle, inHome2OwnProps); - - state.allPhases(preset.inHome1.descriptor.id).forEach((current: State) => { - // independent selector - inHome1Selector(current, inHome1OwnProps); - // should not break memoization of inHome2 - expect(inHome2Selector(current, inHome2OwnProps)).toBe(defaultInHome2MapProps); - }); - }); - }); - - describe('child render behavior', () => { - // creating our own marshal so we can publish a droppable - // so that the draggable can publish itself - const marshal: DimensionMarshal = createDimensionMarshal({ - cancel: () => { }, - publishDraggable: () => { }, - publishDroppable: () => { }, - updateDroppableScroll: () => { }, - updateDroppableIsEnabled: () => { }, - bulkPublish: () => { }, - }); - const options: Object = combine( - withStore(), - withDroppableId(preset.home.descriptor.id), - withDimensionMarshal(marshal), - withStyleContext(), - withCanLift(), - ); - - // registering a fake droppable so that when a draggable - // registers itself the marshal can find its parent - marshal.registerDroppable(preset.home.descriptor, { - getDimension: () => preset.home, - watchScroll: () => { }, - unwatchScroll: () => { }, - scroll: () => { }, - }); - - class Person extends Component<{ name: string, provided: Provided}> { - render() { - const { provided, name } = this.props; - return ( -
provided.innerRef(ref)} - {...provided.draggableProps} - {...provided.dragHandleProps} - > - hello {name} -
- ); - } - } - - class App extends Component<{ currentUser: string }> { - render() { - return ( - - {(dragProvided: Provided) => ( - - )} - - ); - } - } - - beforeEach(() => { - jest.spyOn(Person.prototype, 'render'); - }); - - afterEach(() => { - Person.prototype.render.mockRestore(); - }); - - it('should render the child function when the parent renders', () => { - const wrapper = mount(, options); - - expect(Person.prototype.render).toHaveBeenCalledTimes(1); - expect(wrapper.find(Person).props().name).toBe('Jake'); - - wrapper.unmount(); - }); - - it('should render the child function when the parent re-renders', () => { - const wrapper = mount(, options); - - forceUpdate(wrapper); - - expect(Person.prototype.render).toHaveBeenCalledTimes(2); - expect(wrapper.find(Person).props().name).toBe('Jake'); - - wrapper.unmount(); - }); - - it('should render the child function when the parents props changes that cause a re-render', () => { - const wrapper = mount(, options); - - wrapper.setProps({ - currentUser: 'Finn', - }); - - expect(Person.prototype.render).toHaveBeenCalledTimes(2); - expect(wrapper.find(Person).props().name).toBe('Finn'); - - wrapper.unmount(); - }); - }); -}); diff --git a/test/unit/view/connected-draggable/child-render-behaviour.spec.js b/test/unit/view/connected-draggable/child-render-behaviour.spec.js index 21a65b4329..7c38762427 100644 --- a/test/unit/view/connected-draggable/child-render-behaviour.spec.js +++ b/test/unit/view/connected-draggable/child-render-behaviour.spec.js @@ -5,6 +5,7 @@ import { combine, withStore, withDroppableId, + withDroppableType, withDimensionMarshal, withStyleContext, withCanLift, @@ -12,6 +13,11 @@ import { import type { DimensionMarshal } from '../../../../src/state/dimension-marshal/dimension-marshal-types'; import { getMarshalStub, getDroppableCallbacks } from '../../../utils/dimension-marshal'; import { getPreset } from '../../../utils/dimension'; +import forceUpdate from '../../../utils/force-update'; +import Draggable from '../../../../src/view/draggable/connected-draggable'; +import type { + Provided, +} from '../../../../src/view/draggable/draggable-types'; const preset = getPreset(); // creating our own marshal so we can publish a droppable @@ -20,6 +26,7 @@ const marshal: DimensionMarshal = getMarshalStub(); const options: Object = combine( withStore(), withDroppableId(preset.home.descriptor.id), + withDroppableType(preset.home.descriptor.type), withDimensionMarshal(marshal), withStyleContext(), withCanLift(), diff --git a/test/unit/view/connected-draggable/dragging.spec.js b/test/unit/view/connected-draggable/dragging.spec.js index 39bd63240d..b4bd49ec77 100644 --- a/test/unit/view/connected-draggable/dragging.spec.js +++ b/test/unit/view/connected-draggable/dragging.spec.js @@ -60,6 +60,17 @@ draggingStates.forEach((current: IsDraggingState) => { expect(selector(withoutAnimation, ownProps).shouldAnimateDragMovement).toBe(false); }); + it('should indicate when over a droppable', () => { + const selector: Selector = makeMapStateToProps(); + + const inHome: IsDraggingState = + withImpact(current, getHomeImpact(state.critical, preset.dimensions)); + const noWhere: IsDraggingState = withImpact(current, noImpact); + + expect(selector(inHome, ownProps).draggingOver).toBe(state.critical.droppable.id); + expect(selector(noWhere, ownProps).draggingOver).toBe(null); + }); + it('should not break memoization on multiple calls to the same offset', () => { const selector: Selector = makeMapStateToProps(); @@ -84,7 +95,7 @@ draggingStates.forEach((current: IsDraggingState) => { expect(result1).toBe(result3); }); - it('should break memoization on multiple calls if moving to a new position', () => { + it('should break memoization on multiple calls if moving to a new offset', () => { const selector: Selector = makeMapStateToProps(); const result1: MapProps = selector( @@ -99,17 +110,6 @@ draggingStates.forEach((current: IsDraggingState) => { expect(result1).not.toBe(result2); expect(result1).not.toEqual(result2); }); - - it('should indicate when over a droppable', () => { - const selector: Selector = makeMapStateToProps(); - - const inHome: IsDraggingState = - withImpact(current, getHomeImpact(state.critical, preset.dimensions)); - const noWhere: IsDraggingState = withImpact(current, noImpact); - - expect(selector(inHome, ownProps).draggingOver).toBe(state.critical.droppable.id); - expect(selector(noWhere, ownProps).draggingOver).toBe(null); - }); }); }); diff --git a/test/utils/get-context-options.js b/test/utils/get-context-options.js index 8624f2f107..7c58e35908 100644 --- a/test/utils/get-context-options.js +++ b/test/utils/get-context-options.js @@ -1,9 +1,9 @@ // @flow import PropTypes from 'prop-types'; -import { storeKey, droppableIdKey, dimensionMarshalKey, styleContextKey, canLiftContextKey } from '../../src/view/context-keys'; +import { storeKey, droppableIdKey, dimensionMarshalKey, styleContextKey, canLiftContextKey, droppableTypeKey } from '../../src/view/context-keys'; import createStore from '../../src/state/create-store'; -import createDimensionMarshal from '../../src/state/dimension-marshal/dimension-marshal'; -import type { DroppableId } from '../../src/types'; +import { getMarshalStub } from './dimension-marshal'; +import type { DroppableId, TypeId } from '../../src/types'; import type { DimensionMarshal } from '../../src/state/dimension-marshal/dimension-marshal-types'; import type { StyleMarshal } from '../../src/view/style-marshal/style-marshal-types'; @@ -12,7 +12,22 @@ import type { StyleMarshal } from '../../src/view/style-marshal/style-marshal-ty export const withStore = () => ({ context: { // Each consumer will get their own store - [storeKey]: createStore(), + [storeKey]: createStore({ + getDimensionMarshal: () => getMarshalStub(), + styleMarshal: { + collecting: jest.fn(), + dragging: jest.fn(), + dropping: jest.fn(), + resting: jest.fn(), + styleContext: 'fake-style-context', + unmount: jest.fn(), + mount: jest.fn(), + }, + getHooks: () => ({ + onDragEnd: () => { }, + }), + announce: () => { }, + }), }, childContextTypes: { [storeKey]: PropTypes.shape({ @@ -32,6 +47,15 @@ export const withDroppableId = (droppableId: DroppableId): Object => ({ }, }); +export const withDroppableType = (type: TypeId): Object => ({ + context: { + [droppableTypeKey]: type, + }, + childContextTypes: { + [droppableTypeKey]: PropTypes.string.isRequired, + }, +}); + export const withStyleContext = (marshal?: StyleMarshal): Object => ({ context: { [styleContextKey]: marshal ? marshal.styleContext : 'fake-style-context', @@ -52,14 +76,7 @@ export const withCanLift = (): Object => ({ export const withDimensionMarshal = (marshal?: DimensionMarshal): Object => ({ context: { - [dimensionMarshalKey]: marshal || createDimensionMarshal({ - cancel: () => { }, - publishDraggable: () => { }, - publishDroppable: () => { }, - updateDroppableScroll: () => { }, - updateDroppableIsEnabled: () => { }, - bulkPublish: () => { }, - }), + [dimensionMarshalKey]: marshal || getMarshalStub(), }, childContextTypes: { [dimensionMarshalKey]: PropTypes.object.isRequired,