From 966b2c6bedd4d575939550ff6048d8dbfc3c97c2 Mon Sep 17 00:00:00 2001 From: Alex Reardon Date: Thu, 24 May 2018 09:45:48 +1000 Subject: [PATCH] more dimension marshal tests --- .../dimension-marshal/dimension-marshal.js | 10 +- .../view/dimension-marshal/collection.spec.js | 19 +- .../droppable-passthrough.spec.js | 178 ++++++++++++++++++ .../dimension-marshal/registration.spec.js | 30 +-- test/unit/view/dimension-marshal/util.js | 29 ++- 5 files changed, 224 insertions(+), 42 deletions(-) diff --git a/src/state/dimension-marshal/dimension-marshal.js b/src/state/dimension-marshal/dimension-marshal.js index 9cd95633f5..515c2a4dde 100644 --- a/src/state/dimension-marshal/dimension-marshal.js +++ b/src/state/dimension-marshal/dimension-marshal.js @@ -223,13 +223,13 @@ export default (callbacks: Callbacks) => { }; const updateDroppableIsEnabled = (id: DroppableId, isEnabled: boolean) => { + invariant(entries.droppables[id], `Cannot update the scroll on Droppable ${id} as it is not registered`); + // no need to update the application state if a collection is not occurring if (!collection) { return; } - invariant(entries.droppables[id], `Cannot update the scroll on Droppable ${id} as it is not registered`); - // At this point a non primary droppable dimension might not yet be published // but may have its enabled state changed. For now we still publish this change // and let the reducer exit early if it cannot find the dimension in the state. @@ -243,13 +243,14 @@ export default (callbacks: Callbacks) => { if (!collection) { return; } + callbacks.updateDroppableScroll(id, newScroll); }; const scrollDroppable = (id: DroppableId, change: Position) => { const entry: ?DroppableEntry = entries.droppables[id]; - invariant(entry, 'Cannot scroll Droppable if not in entries'); + invariant(entry, `Cannot scroll Droppable ${id} as it is not registered`); if (!collection) { return; @@ -325,12 +326,15 @@ export default (callbacks: Callbacks) => { }; const marshal: DimensionMarshal = { + // dimension registration registerDraggable, updateDraggable, unregisterDraggable, registerDroppable, updateDroppable, unregisterDroppable, + + // droppable changes updateDroppableIsEnabled, scrollDroppable, updateDroppableScroll, diff --git a/test/unit/view/dimension-marshal/collection.spec.js b/test/unit/view/dimension-marshal/collection.spec.js index a9a6f83518..4195aefc66 100644 --- a/test/unit/view/dimension-marshal/collection.spec.js +++ b/test/unit/view/dimension-marshal/collection.spec.js @@ -21,18 +21,12 @@ import type { import { populateMarshal, resetWatcher, - type DimensionWatcher, + getCallbacksStub, + type DimensionWatcher, withExpectedAdvancedUsageWarning, } from './util'; const preset = getPreset(); -const getCallbacksStub = (): Callbacks => ({ - bulkReplace: jest.fn(), - updateDroppableScroll: jest.fn(), - updateDroppableIsEnabled: jest.fn(), - bulkCollectionStarting: jest.fn(), -}); - const critical: Critical = { droppable: preset.home.descriptor, draggable: preset.inHome1.descriptor, @@ -159,7 +153,6 @@ describe('collect', () => { }); it('should let the system know a bulk collection is starting', () => { - jest.spyOn(console, 'warn').mockImplementation(() => { }); const callbacks: Callbacks = getCallbacksStub(); const marshal: DimensionMarshal = createDimensionMarshal(callbacks); populateMarshal(marshal); @@ -221,7 +214,9 @@ describe('collect', () => { marshal.startPublishing(defaultRequest, preset.windowScroll); // watcher has been called with critical dimensions resetWatcher(watcher); - marshal.collect({ includeCritical: true }); + withExpectedAdvancedUsageWarning(() => { + marshal.collect({ includeCritical: true }); + }); // need to wait an animation frame expect(callbacks.bulkReplace).not.toHaveBeenCalled(); @@ -408,7 +403,9 @@ describe('collect', () => { expect(callbacks.bulkReplace).not.toHaveBeenCalled(); // another collection - returning to first phase - marshal.collect({ includeCritical: true }); + withExpectedAdvancedUsageWarning(() => { + marshal.collect({ includeCritical: true }); + }); expect(watcher.draggable.getDimension).not.toHaveBeenCalled(); expect(callbacks.bulkReplace).not.toHaveBeenCalled(); diff --git a/test/unit/view/dimension-marshal/droppable-passthrough.spec.js b/test/unit/view/dimension-marshal/droppable-passthrough.spec.js index 46e7f7c045..af33386c6d 100644 --- a/test/unit/view/dimension-marshal/droppable-passthrough.spec.js +++ b/test/unit/view/dimension-marshal/droppable-passthrough.spec.js @@ -1 +1,179 @@ // @flow +import createDimensionMarshal from '../../../../src/state/dimension-marshal/dimension-marshal'; +import { getPreset } from '../../../utils/dimension'; +import type { + Callbacks, + DimensionMarshal, + StartPublishingResult, +} from '../../../../src/state/dimension-marshal/dimension-marshal-types'; +import getViewport from '../../../../src/view/window/get-viewport'; +import type { + Critical, + LiftRequest, + DimensionMap, + DraggableId, + DroppableId, + DraggableDimension, + DroppableDimension, + DraggableDimensionMap, + DroppableDimensionMap, +} from '../../../../src/types'; +import { + populateMarshal, + resetWatcher, + getCallbacksStub, + type DimensionWatcher, +} from './util'; + +const preset = getPreset(); + +const critical: Critical = { + draggable: preset.inHome1.descriptor, + droppable: preset.home.descriptor, +}; + +const criticalDimensions: DimensionMap = { + draggables: { + [preset.inHome1.descriptor.id]: preset.inHome1, + }, + droppables: { + [preset.home.descriptor.id]: preset.home, + }, +}; + +const defaultRequest: LiftRequest = { + draggableId: critical.draggable.id, + scrollOptions: { + shouldPublishImmediately: false, + }, +}; + +describe('force scrolling a droppable', () => { + it('should scroll the droppable', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + const watcher: DimensionWatcher = populateMarshal(marshal); + + // initial lift + marshal.startPublishing(defaultRequest, preset.windowScroll); + marshal.collect({ includeCritical: false }); + requestAnimationFrame.flush(); + expect(watcher.droppable.scroll).not.toHaveBeenCalled(); + + // scroll + marshal.scrollDroppable(critical.droppable.id, { x: 10, y: 20 }); + expect(watcher.droppable.scroll) + .toHaveBeenCalledWith(critical.droppable.id, { x: 10, y: 20 }); + }); + + it('should throw if the droppable cannot be found', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + populateMarshal(marshal, criticalDimensions); + + // initial lift + marshal.startPublishing(defaultRequest, preset.windowScroll); + marshal.collect({ includeCritical: false }); + requestAnimationFrame.flush(); + + // scroll + expect(() => { + marshal.scrollDroppable(preset.foreign.descriptor.id, { x: 10, y: 20 }); + }).toThrow(`Cannot scroll Droppable ${preset.foreign.descriptor.id} as it is not registered`); + }); + + it('should not scroll the droppable if no collection is occurring', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + const watcher: DimensionWatcher = populateMarshal(marshal); + + marshal.scrollDroppable(critical.droppable.id, { x: 10, y: 20 }); + expect(watcher.droppable.scroll).not.toHaveBeenCalled(); + }); +}); + +describe('responding to scroll changes', () => { + it('should let consumers know', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + const watcher: DimensionWatcher = populateMarshal(marshal); + + // initial lift + marshal.startPublishing(defaultRequest, preset.windowScroll); + marshal.collect({ includeCritical: false }); + requestAnimationFrame.flush(); + expect(watcher.droppable.scroll).not.toHaveBeenCalled(); + + marshal.updateDroppableScroll(critical.droppable.id, { x: 10, y: 20 }); + expect(callbacks.updateDroppableScroll).toHaveBeenCalledWith( + critical.droppable.id, { x: 10, y: 20 } + ); + }); + + it('should throw if the droppable cannot be found', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + populateMarshal(marshal, criticalDimensions); + + // initial lift + marshal.startPublishing(defaultRequest, preset.windowScroll); + marshal.collect({ includeCritical: false }); + requestAnimationFrame.flush(); + expect(callbacks.updateDroppableScroll).not.toHaveBeenCalled(); + + expect(() => { + marshal.updateDroppableScroll(preset.foreign.descriptor.id, { x: 10, y: 20 }); + }).toThrow(`Cannot update the scroll on Droppable ${preset.foreign.descriptor.id} as it is not registered`); + }); + + it('should not let consumers know if know drag is occurring', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + populateMarshal(marshal, criticalDimensions); + + marshal.updateDroppableScroll(critical.droppable.id, { x: 10, y: 20 }); + expect(callbacks.updateDroppableScroll).not.toHaveBeenCalled(); + }); +}); + +describe('is enabled changes', () => { + it('should let consumers know', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + populateMarshal(marshal); + + // initial lift + marshal.startPublishing(defaultRequest, preset.windowScroll); + marshal.collect({ includeCritical: false }); + requestAnimationFrame.flush(); + expect(callbacks.updateDroppableIsEnabled).not.toHaveBeenCalled(); + + marshal.updateDroppableIsEnabled(critical.droppable.id, false); + expect(callbacks.updateDroppableIsEnabled) + .toHaveBeenCalledWith(critical.droppable.id, false); + }); + + it('should throw if the droppable cannot be found', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + populateMarshal(marshal, criticalDimensions); + + // initial lift + marshal.startPublishing(defaultRequest, preset.windowScroll); + marshal.collect({ includeCritical: false }); + requestAnimationFrame.flush(); + expect(callbacks.updateDroppableIsEnabled).not.toHaveBeenCalled(); + + expect(() => marshal.updateDroppableIsEnabled(preset.foreign.descriptor.id, false)) + .toThrow(`Cannot update the scroll on Droppable ${preset.foreign.descriptor.id} as it is not registered`); + }); + + it('should not let consumers know if no collection is occurring', () => { + const callbacks: Callbacks = getCallbacksStub(); + const marshal: DimensionMarshal = createDimensionMarshal(callbacks); + populateMarshal(marshal, criticalDimensions); + + marshal.updateDroppableIsEnabled(critical.droppable.id, false); + expect(callbacks.updateDroppableIsEnabled).not.toHaveBeenCalled(); + }); +}); diff --git a/test/unit/view/dimension-marshal/registration.spec.js b/test/unit/view/dimension-marshal/registration.spec.js index 70fdebb2a4..f065877dbd 100644 --- a/test/unit/view/dimension-marshal/registration.spec.js +++ b/test/unit/view/dimension-marshal/registration.spec.js @@ -17,34 +17,13 @@ import type { } from '../../../../src/types'; import { populateMarshal, - resetWatcher, - type DimensionWatcher, + getDroppableCallbacks, + withExpectedAdvancedUsageWarning, + getCallbacksStub, } from './util'; const preset = getPreset(); -const getCallbacksStub = (): Callbacks => ({ - bulkReplace: jest.fn(), - updateDroppableScroll: jest.fn(), - updateDroppableIsEnabled: jest.fn(), - bulkCollectionStarting: jest.fn(), -}); - -const getDroppableCallbacks = (dimension: DroppableDimension): DroppableCallbacks => ({ - getDimensionAndWatchScroll: jest.fn().mockReturnValue(dimension), - scroll: jest.fn(), - unwatchScroll: jest.fn(), - hidePlaceholder: jest.fn(), - showPlaceholder: jest.fn(), -}); - -const withExpectedAdvancedUsageWarning = (fn: Function) => { - jest.spyOn(console, 'warn').mockImplementation(() => { }); - fn(); - expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('Advanced usage warning')); - console.warn.mockRestore(); -}; - const critical: Critical = { draggable: preset.inHome1.descriptor, droppable: preset.home.descriptor, @@ -368,8 +347,7 @@ describe('draggable', () => { marshal.registerDraggable(preset.inHome3.descriptor, () => preset.inHome3); marshal.unregisterDraggable(preset.inHome3.descriptor); - const droppableCallbacks: DroppableCallbacks = getDroppableCallbacks(); - droppableCallbacks.getDimensionAndWatchScroll.mockReturnValue(preset.home); + const droppableCallbacks: DroppableCallbacks = getDroppableCallbacks(preset.home); marshal.registerDroppable(preset.home.descriptor, droppableCallbacks); const result: StartPublishingResult = diff --git a/test/unit/view/dimension-marshal/util.js b/test/unit/view/dimension-marshal/util.js index 5f57fbe7d2..5bd0e23dc7 100644 --- a/test/unit/view/dimension-marshal/util.js +++ b/test/unit/view/dimension-marshal/util.js @@ -1,8 +1,10 @@ // @flow +import { type Position } from 'css-box-model'; import { getPreset } from '../../../utils/dimension'; import type { DimensionMarshal, DroppableCallbacks, + Callbacks, } from '../../../../src/state/dimension-marshal/dimension-marshal-types'; import type { DimensionMap, @@ -59,8 +61,8 @@ export const populateMarshal = ( watcher.droppable.getDimensionAndWatchScroll(id); return droppable; }, - scroll: () => { - watcher.droppable.scroll(id); + scroll: (change: Position) => { + watcher.droppable.scroll(id, change); }, unwatchScroll: () => { watcher.droppable.unwatchScroll(id); @@ -87,3 +89,26 @@ export const populateMarshal = ( return watcher; }; + +export const getDroppableCallbacks = (dimension: DroppableDimension): DroppableCallbacks => ({ + getDimensionAndWatchScroll: jest.fn().mockReturnValue(dimension), + scroll: jest.fn(), + unwatchScroll: jest.fn(), + hidePlaceholder: jest.fn(), + showPlaceholder: jest.fn(), +}); + +export const withExpectedAdvancedUsageWarning = (fn: Function) => { + jest.spyOn(console, 'warn').mockImplementation(() => { }); + fn(); + expect(console.warn).toHaveBeenCalledWith(expect.stringContaining('Advanced usage warning')); + console.warn.mockRestore(); +}; + +export const getCallbacksStub = (): Callbacks => ({ + bulkReplace: jest.fn(), + updateDroppableScroll: jest.fn(), + updateDroppableIsEnabled: jest.fn(), + bulkCollectionStarting: jest.fn(), +}); +