Skip to content

Commit

Permalink
Add switch prop for activating/de-activating Idea 'drop' functionalit…
Browse files Browse the repository at this point in the history
…y on IdeaDropTarget
  • Loading branch information
vanderhoop committed Feb 11, 2019
1 parent 458f839 commit 75e949f
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 103 deletions.
234 changes: 135 additions & 99 deletions test/components/idea_drop_target_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,142 +10,178 @@ describe("IdeaDropTarget", () => {

const defaultProps = {
onDropOfIdea: () => {},
}

context("when an item is dragged over it", () => {
let mockEvent
dragAndDropHandlersActive: true,

before(() => {
mockEvent = { preventDefault: spy(), dataTransfer: { dropEffect: null } }
}

context("when dragAndDropHandlersActive is true", () => {
it("applies drag and drop handlers", () => {
wrapper = shallow(
<IdeaDropTarget
{...defaultProps}
dragAndDropHandlersActive
/>
)

wrapper.simulate("dragOver", mockEvent)
const dragEventTypes = ["onDragOver", "onDragLeave", "onDrop"]
dragEventTypes.forEach(dragEventType => {
expect(wrapper.prop(dragEventType)).to.be.truthy
expect(typeof wrapper.prop(dragEventType)).to.eql("function")
})
})

it("prevents the default event behavior", () => {
expect(mockEvent.preventDefault).called
})
context("when an item is dragged over it", () => {
let mockEvent

it("adds a 'dragged-over' class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(1)
})
before(() => {
mockEvent = { preventDefault: spy(), dataTransfer: { dropEffect: null } }

context("when a dragLeave event follows", () => {
const relatedTarget = {}
wrapper = shallow(
<IdeaDropTarget
{...defaultProps}
/>
)

context("and the event's target element *does* contain the related (dragged) elemant", () => {
beforeEach(() => {
mockEvent = {
relatedTarget,
currentTarget: {
contains: stub().withArgs(relatedTarget).returns(true),
},
}
wrapper.simulate("dragOver", mockEvent)
})

wrapper.simulate("dragLeave", mockEvent)
it("prevents the default event behavior", () => {
expect(mockEvent.preventDefault).called
})

it("adds a 'dragged-over' class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(1)
})

context("when a dragLeave event follows", () => {
const relatedTarget = {}

context("and the event's target element *does* contain the related (dragged) elemant", () => {
beforeEach(() => {
mockEvent = {
relatedTarget,
currentTarget: {
contains: stub().withArgs(relatedTarget).returns(true),
},
}

wrapper.simulate("dragLeave", mockEvent)
})

it("doesn't remove the dragged-over class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(1)
})
})

it("doesn't remove the dragged-over class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(1)
context("and the event's target element *doesn't* contain the related (dragged) element", () => {
beforeEach(() => {
mockEvent = {
relatedTarget,
currentTarget: {
contains: stub().withArgs(relatedTarget).returns(false),
},
}
wrapper.simulate("dragLeave", mockEvent)
})

it("removes the dragged-over class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(0)
})
})
})

context("and the event's target element *doesn't* contain the related (dragged) element", () => {
context("and an item is dropped on it", () => {
let actions

beforeEach(() => {
mockEvent = {
relatedTarget,
currentTarget: {
contains: stub().withArgs(relatedTarget).returns(false),
},
actions = {
submitIdeaEditAsync: spy(),
}
wrapper.simulate("dragLeave", mockEvent)
})

it("removes the dragged-over class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(0)
})
})
})
context("and the data is a serialized idea", () => {
let onDropOfIdeaSpy

context("and an item is dropped on it", () => {
let actions
const idea = {
id: 100,
body: "sup",
category: "sad",
assignee_id: null,
}

beforeEach(() => {
actions = {
submitIdeaEditAsync: spy(),
}
})
const mockEvent = buildIdeaDragEvent(idea)

context("and the data is a serialized idea", () => {
let onDropOfIdeaSpy
beforeEach(() => {
onDropOfIdeaSpy = spy()

const idea = {
id: 100,
body: "sup",
category: "sad",
assignee_id: null,
}
wrapper = mountWithConnectedSubcomponents(
<IdeaDropTarget
{...defaultProps}
actions={actions}
onDropOfIdea={onDropOfIdeaSpy}
dragAndDropHandlersActive
/>
)

const mockEvent = buildIdeaDragEvent(idea)
wrapper.simulate("dragEnter")
wrapper.simulate("drop", mockEvent)
})

beforeEach(() => {
onDropOfIdeaSpy = spy()

wrapper = mountWithConnectedSubcomponents(
<IdeaDropTarget
{...defaultProps}
actions={actions}
onDropOfIdea={onDropOfIdeaSpy}
/>
)

wrapper.simulate("dragEnter")
wrapper.simulate("drop", mockEvent)
})
it("prevents the default event behavior", () => {
expect(mockEvent.preventDefault).called
})

it("prevents the default event behavior", () => {
expect(mockEvent.preventDefault).called
})
it("removes the dragged-over class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(0)
})

it("removes the dragged-over class", () => {
expect(wrapper.find(".dragged-over").length).to.equal(0)
it("invokes the onDropOfIdea callback, passing the idea", () => {
expect(onDropOfIdeaSpy).calledWith(idea)
})
})

it("invokes the onDropOfIdea callback, passing the idea", () => {
expect(onDropOfIdeaSpy).calledWith(idea)
context("and there is not serialized idea data associated with the event", () => {
const mockEvent = {
preventDefault: () => {},
dataTransfer: {
getData: stub(),
},
}

mockEvent.dataTransfer.getData
.withArgs("idea").returns("")

before(() => {
wrapper = shallow(
<IdeaDropTarget
{...defaultProps}
actions={actions}
/>
)

wrapper.simulate("drop", mockEvent)
})

it("does not invoke the submitIdeaEditAsync action", () => {
expect(actions.submitIdeaEditAsync).not.called
})
})
})
})
})

context("and there is not serialized idea data associated with the event", () => {
const mockEvent = {
preventDefault: () => {},
dataTransfer: {
getData: stub(),
},
}

mockEvent.dataTransfer.getData
.withArgs("idea").returns("")

before(() => {
wrapper = shallow(
<IdeaDropTarget
{...defaultProps}
actions={actions}
/>
)

wrapper.simulate("drop", mockEvent)
})
context("when dragAndDropHandlersActive is false", () => {
it("does *not* add drag and drop handlers", () => {
wrapper = shallow(
<IdeaDropTarget
{...defaultProps}
dragAndDropHandlersActive={false}
/>
)

it("does not invoke the submitIdeaEditAsync action", () => {
expect(actions.submitIdeaEditAsync).not.called
})
const dragEventTypes = ["onDragOver", "onDragLeave", "onDrop"]
dragEventTypes.forEach(dragEventType => {
expect(typeof wrapper.prop(dragEventType)).to.eql("undefined")
})
})
})
Expand Down
14 changes: 10 additions & 4 deletions web/static/js/components/idea_drop_target.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,22 @@ export class IdeaDropTarget extends Component {

render() {
const { handleDragOver, handleDrop, handleDragLeave, props, state } = this
const { children, wrapperClassName } = props
const { children, wrapperClassName, dragAndDropHandlersActive } = props

const className = classNames(wrapperClassName, {
"dragged-over": state.draggedOver,
})

const dragAndDropHandlers = dragAndDropHandlersActive ? {
onDragOver: handleDragOver,
onDragLeave: handleDragLeave,
onDrop: handleDrop,
} : {}

return (
<div
className={className}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
{...dragAndDropHandlers}
>
{children}
<span className="overlay" />
Expand All @@ -58,10 +62,12 @@ export class IdeaDropTarget extends Component {

IdeaDropTarget.propTypes = {
onDropOfIdea: PropTypes.func.isRequired,
dragAndDropHandlersActive: PropTypes.bool,
wrapperClassName: PropTypes.string,
}

IdeaDropTarget.defaultProps = {
dragAndDropHandlersActive: true,
wrapperClassName: "",
}

Expand Down

0 comments on commit 75e949f

Please sign in to comment.