Skip to content

Instantly share code, notes, and snippets.

@cellog
Created March 15, 2017 21:13
Show Gist options
  • Save cellog/7c60befa8ec00063a29525ebc1d4920b to your computer and use it in GitHub Desktop.
Save cellog/7c60befa8ec00063a29525ebc1d4920b to your computer and use it in GitHub Desktop.
React-DnD testing example
import { DragSource } from 'react-dnd';
import Booked from '../components/Booked'
const source = {
beginDrag(props) {
return {
group: props.group,
slot: props.slot,
room: props.room
}
},
endDrag(props, monitor) {
if (!monitor.didDrop()) return
props.clear(props.group, props.room)
}
}
export default DragSource('booked', source, (connect, monitor) => ({
makeDraggable: connect.dragSource(),
dragging: monitor.isDragging()
}))(Booked)
import { DropTarget } from 'react-dnd'
import Slot from '../components/Slot'
export default DropTarget('booked', {
canDrop(props, monitor) {
return props.droppable(monitor.getItem().group)
},
drop(props, monitor, component) {
const item = monitor.getItem()
props.book(item.group, props.room)
}
}, (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}))(Slot)
import React, { Component, PropTypes } from 'react'
import styles from './Calendar.css'
import Booked from '../dragdrop/DragBooked'
class Slot extends Component {
static propTypes = {
room: PropTypes.object.isRequired,
slot: PropTypes.object.isRequired,
booked: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
book: PropTypes.func.isRequired,
clear: PropTypes.func.isRequired,
possibles: PropTypes.func.isRequired,
connectDropTarget: PropTypes.func.isRequired,
isOver: PropTypes.bool.isRequired,
}
static defaultProps = {
connectDropTarget: item => item,
isOver: false
}
constructor(props) {
super(props)
this.state = {
showing: false
}
}
render() {
const Possibles = this.props.possibles
if (!this.props.booked) {
const special = this.props.isOver ? { backgroundColor: this.props.canDrop ? 'lime' : 'red' } : {}
return this.props.connectDropTarget(
<div className={styles.slot} style={special}>
<div className={styles.room} onClick={() => this.setState({ showing: !this.state.showing })}>{this.props.room.name}</div>
<div className={styles.empty} onClick={() => this.setState({ showing: !this.state.showing })}>
{this.state.showing && <Possibles slot={this.props.slot} room={this.props.room} />}
</div>
</div>
)
}
return (
<div className={styles.slot}>
<div className={styles.room}>{this.props.room.name}</div>
<Booked slot={this.props.slot}
room={this.props.room}
group={this.props.booked}
clear={this.props.clear}
/>
</div>
)
}
}
export default Slot
import React from 'react'
import { renderComponent } from '../../test_helper'
import Slot from '../../../src/modules/schedule/dragdrop/Slot'
import Booked from '../../../src/modules/schedule/dragdrop/Booked'
import SlotComponent from '../../../src/modules/schedule/components/Slot'
describe('Slot', () => {
let state
let dropcallback = sinon.spy()
let droppable = true
let manager
let backend
let genericSlot = {
droppable: group => {
dropcallback(group)
return droppable
},
room: { name: 'room' },
slot: { name: 'slot' },
booked: false,
book: () => null,
clear: () => null,
possibles: () => null,
}
let bookedGeneric = {
slot: { name: 'slot'},
room: { name: 'room'},
group: false,
clear: () => null,
}
const Draggable = props => (
<div>
<Booked {...bookedGeneric} />
<Slot {...props} />
</div>
)
const source = component => component.find(Booked)[0].handler.monitor.sourceId
const target = component => component.find(Slot)[0].handler.monitor.targetId
function render(props = {}, bookedProps = {}) {
const info = renderComponent(Draggable, {
...genericSlot, ...props
}, {}, true)
const [ comp, store, log, m ] = info
manager = m.getManager()
backend = manager.getBackend()
return comp
}
describe('props', () => {
it('isOver', () => {
const component = render()
expect(component.find(SlotComponent).props('isOver')).eqls(false)
backend.simulateBeginDrag([source(component)])
backend.simulateHover([target(component)])
expect(component.find(SlotComponent).props('isOver')).eqls(true)
backend.simulateEndDrag([source(component)])
})
it('canDrop', () => {
const component = render()
backend.simulateBeginDrag([source(component)])
backend.simulateHover([target(component)])
expect(component.find(SlotComponent).props('canDrop')).eqls(true)
backend.simulateEndDrag([source(component)])
})
it('cannot drop', () => {
const component = render({
droppable: () => false
})
backend.simulateBeginDrag([source(component)])
backend.simulateHover([target(component)])
expect(component.find(SlotComponent).props('canDrop')).eqls(false)
backend.simulateEndDrag([source(component)])
})
})
describe('actions', () => {
let callback
function makeComponent(name, props = {}) {
callback = new sinon.spy()
return render({
[name]: callback,
...props
})
}
it('book', () => {
const component = makeComponent('book')
backend.simulateBeginDrag([source(component)])
backend.simulateHover([target(component)])
backend.simulateDrop()
backend.simulateEndDrag([source(component)])
expect(callback.called).is.true
expect(callback.args[0]).eqls([false, { name: 'room' }])
})
})
})
import { connect } from 'react-redux'
import { createSelector } from 'reselect'
import NormalPossibles from 'NormalPossibleGroups'
import DropSlot from '../dragdrop/DropSlot'
import * as actions from '../actions'
import * as selectors from '../selectors'
const schedule = state => state.schedule
const groups = state => state.groups
const campers = state => state.campers
const types = state => state.ensembleTypes
export default connect((state, props) => ({
booked: createSelector([schedule, groups, campers, types, () => props.room, () => props.slot], selectors.standardSlotBooked)(state),
droppable: group => selectors.canDrop(group, schedule(state), groups(state), props.slot, props.room),
possibles: NormalPossibles,
}), (dispatch, props) => ({
book: (id, room) => dispatch(actions.bookStandardCoaching(props.slot.days, props.slot.time, id, room)),
clear: (id, room) => dispatch(actions.clearStandardCoaching(props.slot.days, props.slot.time, id, room))
}))(DropSlot)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment