Created
March 15, 2017 21:13
-
-
Save cellog/7c60befa8ec00063a29525ebc1d4920b to your computer and use it in GitHub Desktop.
React-DnD testing example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' }]) | |
}) | |
}) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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