Skip to content

Commit

Permalink
Get line coverage to 100%
Browse files Browse the repository at this point in the history
  • Loading branch information
bibekg committed Sep 3, 2018
1 parent 964c708 commit 2d3a23f
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 19 deletions.
30 changes: 13 additions & 17 deletions src/lib/DatePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export default class AvailabilitySelector extends React.Component<PropsType, Sta
// Performs a lookup into this.cellToDate to retrieve the Date that corresponds to
// the cell where this touch event is right now. Note that this method will only work
// if the event is a `touchmove` event since it's the only one that has a `touches` list.
getTimeFromTouchEvent = (event: SyntheticTouchEvent<*>): ?Date => {
getTimeFromTouchEvent(event: SyntheticTouchEvent<*>): ?Date {
const { touches } = event
if (!touches || touches.length === 0) return null
const { clientX, clientY } = touches[0]
Expand All @@ -203,7 +203,7 @@ export default class AvailabilitySelector extends React.Component<PropsType, Sta
}

// Given an ending Date, determines all the dates that should be selected in this draft
updateAvailabilityDraft = (selectionEnd: ?Date, callback?: () => void) => {
updateAvailabilityDraft(selectionEnd: ?Date, callback?: () => void) {
const { selection } = this.props
const { selectionType, selectionStart } = this.state

Expand All @@ -216,7 +216,7 @@ export default class AvailabilitySelector extends React.Component<PropsType, Sta
// where the user just clicks on a single cell, since in that case,
// In such a case, set the entire selection as just that
if (selectionStart) selected = [selectionStart]
} else {
} else if (selectionStart) {
const reverseSelection = isBefore(selectionEnd, selectionStart)
// Generate a list of Dates between the start of the selection and the end of the selection
// The Dates to choose from for this list are sourced from this.dates
Expand Down Expand Up @@ -257,15 +257,13 @@ export default class AvailabilitySelector extends React.Component<PropsType, Sta

// Isomorphic (mouse and touch) handler since starting a selection works the same way for both classes of user input
handleSelectionStartEvent(startTime: Date) {
if (startTime) {
// Check if the startTime cell is selected/unselected to determine if this drag-select should
// add values or remove values
const timeSelected = this.props.selection.find(a => isSameMinute(a, startTime))
this.setState({
selectionType: timeSelected ? 'remove' : 'add',
selectionStart: startTime
})
}
// Check if the startTime cell is selected/unselected to determine if this drag-select should
// add values or remove values
const timeSelected = this.props.selection.find(a => isSameMinute(a, startTime))
this.setState({
selectionType: timeSelected ? 'remove' : 'add',
selectionStart: startTime
})
}

handleMouseEnterEvent = (time: Date) => {
Expand All @@ -275,11 +273,9 @@ export default class AvailabilitySelector extends React.Component<PropsType, Sta
this.updateAvailabilityDraft(time)
}

handleMouseUpEvent = (time?: Date) => {
if (time) {
this.updateAvailabilityDraft(time)
// Don't call this.endSelection() here because the document mouseup handler will do it
}
handleMouseUpEvent = (time: Date) => {
this.updateAvailabilityDraft(time)
// Don't call this.endSelection() here because the document mouseup handler will do it
}

handleTouchMoveEvent(event: SyntheticTouchEvent<*>) {
Expand Down
100 changes: 98 additions & 2 deletions test/lib/DatePicker.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/* eslint-disable flowtype/* */

import React from 'react'
import renderer from 'react-test-renderer'
import { shallow } from 'enzyme'
import moment from 'moment'

import DatePicker from '../../src/lib/DatePicker'

const startDate = new Date('2018-01-01T00:00:00.000')
Expand All @@ -18,6 +21,7 @@ const getTestSchedule = () => [

beforeAll(() => {
document.elementFromPoint = jest.fn()
document.removeEventListener = jest.fn()
})

test('Component renders correctly', () => {
Expand Down Expand Up @@ -47,7 +51,7 @@ test('Date cell render prop is used if provided', () => {
expect(tree).toMatchSnapshot()
})

test('getTimeFromTouchEvent', () => {
test('getTimeFromTouchEvent returns the time for that cell', () => {
const component = shallow(<DatePicker />)
const mainSpy = jest.spyOn(component.instance(), 'getTimeFromTouchEvent')
const mockCellTime = new Date()
Expand All @@ -66,7 +70,7 @@ test('getTimeFromTouchEvent', () => {
cellToDateSpy.mockRestore()
})

test('endSelection', () => {
test('endSelection calls the onChange prop and resets selection state', () => {
const changeSpy = jest.fn()
const component = shallow(<DatePicker onChange={changeSpy} />)
const setStateSpy = jest.spyOn(component.instance(), 'setState')
Expand Down Expand Up @@ -135,3 +139,95 @@ test('touch handlers get called', () => {
spies[spyName].mockRestore()
})
})

test('handleTouchMoveEvent updates the availability draft', () => {
const mockCellTime = new Date()
const getTimeSpy = jest.spyOn(DatePicker.prototype, 'getTimeFromTouchEvent').mockReturnValue(mockCellTime)
const updateDraftSpy = jest.spyOn(DatePicker.prototype, 'updateAvailabilityDraft')

const component = shallow(<DatePicker />)
component.instance().handleTouchMoveEvent({})
expect(updateDraftSpy).toHaveBeenCalledWith(mockCellTime)

getTimeSpy.mockRestore()
updateDraftSpy.mockRestore()
})

test.each([['add', 1], ['remove', 1], ['add', -1], ['remove', -1]])(
'updateAvailabilityDraft handles addition and removals, for forward and reversed drags',
(type, amount, done) => {
const start = moment(startDate)
.add(5, 'hours')
.toDate()
const end = moment(start)
.add(amount, 'hours')
.toDate()
const outOfRangeOne = moment(start)
.add(amount + 5, 'hours')
.toDate()

const setStateSpy = jest.spyOn(DatePicker.prototype, 'setState')
const component = shallow(
<DatePicker
// Initialize the initial selection based on whether this test is adding or removing
selection={type === 'remove' ? [start, end, outOfRangeOne] : [outOfRangeOne]}
startDate={start}
numDays={5}
minTime={0}
maxTime={23}
/>
)
component.setState(
{
selectionType: type,
selectionStart: start
},
() => {
const expected = type === 'remove' ? [outOfRangeOne] : [start, end, outOfRangeOne]
component.instance().updateAvailabilityDraft(end, () => {
expect(setStateSpy).toHaveBeenLastCalledWith({ selectionDraft: expect.arrayContaining(expected) })
setStateSpy.mockRestore()
done()
})
}
)
}
)

test('updateAvailabilityDraft handles a single cell click correctly', done => {
const setStateSpy = jest.spyOn(DatePicker.prototype, 'setState')
const component = shallow(<DatePicker />)
const start = startDate
component.setState(
{
selectionType: 'add',
selectionStart: start
},
() => {
component.instance().updateAvailabilityDraft(null, () => {
expect(setStateSpy).toHaveBeenCalledWith({ selectionDraft: expect.arrayContaining([start]) })
setStateSpy.mockRestore()
done()
})
}
)
})

test('componentWillUnmount removes the mouseup event listener', () => {
const component = shallow(<DatePicker />)
const endSelectionMethod = component.instance().endSelection
component.unmount()
expect(document.removeEventListener).toHaveBeenCalledWith('mouseup', endSelectionMethod)
})

test('componentWillReceiveProps makes the selection prop override the existing selection draft', () => {
const setStateSpy = jest.spyOn(DatePicker.prototype, 'setState')
const component = shallow(<DatePicker />)
const mockNextProps = {
selection: ['foo', 'bar']
}
component.instance().componentWillReceiveProps(mockNextProps)
expect(setStateSpy).toHaveBeenCalledWith({
selectionDraft: expect.arrayContaining(mockNextProps.selection)
})
})

0 comments on commit 2d3a23f

Please sign in to comment.