From acd6b0b7a7b1e58185d6a912b0e9441838a1fbe5 Mon Sep 17 00:00:00 2001 From: TinySymphony Date: Thu, 18 May 2017 15:51:18 +0800 Subject: [PATCH] feat(CalendarSelect): add test & type check & doc fix --- .travis.yml | 13 ++ Calendar.js | 2 +- CalendarStyle.js | 2 +- Day/index.js | 5 +- Day/style.js | 2 +- Month/index.js | 4 +- __tests__/Calendar.test.js | 296 +++++++++++++++++++++++++++++++++++++ __tests__/index.android.js | 12 -- __tests__/index.ios.js | 12 -- index.ios.js | 15 +- package.json | 4 +- readme.md | 36 +++-- 12 files changed, 349 insertions(+), 54 deletions(-) create mode 100644 .travis.yml create mode 100644 __tests__/Calendar.test.js delete mode 100644 __tests__/index.android.js delete mode 100644 __tests__/index.ios.js diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..8fcd3ed --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: node_js +sudo: true +node_js: + - "4.4" +cache: + directories: + - node_modules +before_install: + - yarn install +script: + - npm test -- -u +after_script: + - npm run coverage diff --git a/Calendar.js b/Calendar.js index e2badcb..8eff679 100644 --- a/Calendar.js +++ b/Calendar.js @@ -232,7 +232,7 @@ export default class Calendar extends Component { let isClearVisible = startDate || endDate; return ( diff --git a/CalendarStyle.js b/CalendarStyle.js index 6205579..acba202 100644 --- a/CalendarStyle.js +++ b/CalendarStyle.js @@ -68,7 +68,7 @@ export default StyleSheet.create({ weekText: { flex: 1, fontSize: weekTextFontSize, - textAlign: 'center', + textAlign: 'center' }, scroll: { flex: 9, diff --git a/Day/index.js b/Day/index.js index 28949f8..74579df 100644 --- a/Day/index.js +++ b/Day/index.js @@ -13,6 +13,9 @@ import Moment from 'moment'; import styles from './style'; export default class Day extends Component { + static propTypes = { + onChoose: PropTypes.func + } constructor (props) { super(props); this._chooseDay = this._chooseDay.bind(this); @@ -20,7 +23,7 @@ export default class Day extends Component { this._statusCheck(); } _chooseDay () { - this.props.onChoose(this.props.date); + this.props.onChoose && this.props.onChoose(this.props.date); } _statusCheck (props) { const { diff --git a/Day/style.js b/Day/style.js index bbcdaca..0031325 100644 --- a/Day/style.js +++ b/Day/style.js @@ -4,7 +4,7 @@ import { } from 'react-native'; const {scale, width} = Dimensions.get('window'); let dayWidth = width / 7; -let mod = scale * width % 7 +let mod = scale * width % 7; if (mod) { dayWidth = ((7 - mod) / scale + width) / 7; } diff --git a/Month/index.js b/Month/index.js index b523663..141fc6f 100644 --- a/Month/index.js +++ b/Month/index.js @@ -44,7 +44,7 @@ export default class Month extends Component { let m = month.month(); let year = today.year(); if (year === y) { - return Month.I18N_MAP[i18n][m] + return Month.I18N_MAP[i18n][m]; } else { if (i18n === 'en') { return `${Month.I18N_MAP[i18n][m]}, ${y}`; @@ -63,7 +63,7 @@ export default class Month extends Component { empty: date.clone().subtract(1, 'h') }); } - while(date.month() === month) { + while (date.month() === month) { dayList.push({ date: date.clone() }); diff --git a/__tests__/Calendar.test.js b/__tests__/Calendar.test.js new file mode 100644 index 0000000..0abc63f --- /dev/null +++ b/__tests__/Calendar.test.js @@ -0,0 +1,296 @@ +/* eslint-disable */ + +import { + View, + Text, + Easing, + Dimensions +} from 'react-native'; +import React from 'react'; +import {shallow} from 'enzyme'; +import renderer from 'react-test-renderer'; +import Moment from 'moment'; + +import Calendar from '../Calendar'; +import Day from '../Day'; +import Month from '../Month'; +import MonthList from '../MonthList'; + +let start = {}; +let end = {}; +let color = { + mainColor: '#15aaaa', + subColor: '#fff', + borderColor: 'rgba(255, 255, 255, 0.50)' +}; + +let cal = shallow( + {start = startDate; end = endDate;}} + /> +); + +let invalidDateCalA = shallow( + +); + +let invalidDateCalB = shallow( + +); + +let invalidDateCalC = shallow( + +); + +test('It renders calendar correctly', done => { + let instance = cal.instance(); + expect(cal.state('isModalVisible')).toEqual(false); + instance.componentDidMount(); + expect(instance._minDate.isSame(Moment('20161210', 'YYYYMMDD'))).toEqual(true); + expect(instance._maxDate.isSame(Moment('20171104', 'YYYYMMDD'))).toEqual(true); + instance.open(); + expect(cal.state('isModalVisible')).toEqual(true); + expect(cal.state('startDate').isSame(Moment('20170512', 'YYYYMMDD'))).toEqual(true); + expect(cal.state('endDate').isSame(Moment('20170520', 'YYYYMMDD'))).toEqual(true); + expect(cal.state('startDateText')).toEqual('12 / 05'); + expect(cal.state('endDateText')).toEqual('20 / 05'); + expect(cal.state('startWeekdayText')).toEqual('Friday'); + expect(cal.state('endWeekdayText')).toEqual('Saturday'); + instance.clear(); + expect(cal.state('startDate')).toEqual(null); + expect(cal.state('endDate')).toEqual(null); + expect(cal.state('startDateText')).toEqual(''); + expect(cal.state('endDateText')).toEqual(''); + expect(cal.state('startWeekdayText')).toEqual(''); + expect(cal.state('endWeekdayText')).toEqual(''); + instance.confirm(); + expect(cal.state('isModalVisible')).toEqual(false); + expect(start).toEqual(null); + expect(end).toEqual(null); + instance.open(); + instance._onChoose(Moment('20170412', 'YYYYMMDD')); + expect(cal.state('startDate').isSame(Moment('20170412', 'YYYYMMDD'))).toEqual(true); + instance._onChoose(Moment('20170410', 'YYYYMMDD')); + expect(cal.state('startDate').isSame(Moment('20170410', 'YYYYMMDD'))).toEqual(true); + instance._onChoose(Moment('20170502', 'YYYYMMDD')); + expect(cal.state('endDate').isSame(Moment('20170502', 'YYYYMMDD'))).toEqual(true); + instance.cancel(); + done(); +}); + +test('It renders calendar correctly when min & max Date is incorrect.', done => { + let instanceA = invalidDateCalA.instance(); + let instanceB = invalidDateCalB.instance(); + let instanceC = invalidDateCalC.instance(); + done(); +}); + +let startDate = Moment('20170811', 'YYYYMMDD'); +let endDate = Moment('20170914', 'YYYYMMDD'); +let minDate = Moment('20170302', 'YYYYMMDD'); +let maxDate = Moment('20180122', 'YYYYMMDD'); +let today = Moment('20170801', 'YYYYMMDD'); + +let monthList = shallow( + {}} + color={color} + /> +); + +test('It renders MonthList correctly', done => { + let instance = monthList.instance(); + instance.componentDidMount(); + instance._shouldUpdate({date: Moment('20170519', 'YYYYMMDD')}, { + startDate, + endDate + }); + instance._shouldUpdate({date: Moment('20170819', 'YYYYMMDD')}, { + startDate, + endDate + }); + instance.componentWillReceiveProps({ + startDate, + endDate, + minDate, + maxDate + }); + instance.componentWillReceiveProps({ + startDate: startDate.clone().subtract(1, 'days'), + endDate: endDate.clone().add(1, 'days'), + minDate, + maxDate + }); + var month = instance._renderMonth({ + date: Moment('20170819', 'YYYYMMDD') + }); + done(); +}); + +let month = shallow( + +); + +let monthAnotherYear = shallow( + +); + +let jpMonth = shallow( + +); + +test('It renders Month correctly', done => { + let instance = month.instance(); + let anthorInstance = monthAnotherYear.instance(); + let jpInstance = jpMonth.instance(); + done(); +}); + +let dateOut = Moment('20170712', 'YYYYMMDD'); +let dateStart = Moment('20170811', 'YYYYMMDD'); +let dateEnd = Moment('20170914', 'YYYYMMDD'); +let dateMid = Moment('20170910', 'YYYYMMDD'); +let dateChoose = null; + +let dayOut = shallow( + {dateChoose = date;}} + /> +); + +let dayStart = shallow( + +); + +let dayEnd = shallow( + +); + +let dayMid = shallow( + +); + +let dayEmpty = shallow( + +); + +test('It renders Day correctly', done => { + let instanceOut = dayOut.instance(); + instanceOut._chooseDay(); + expect(dateChoose.isSame(dateOut)); + instanceOut.shouldComponentUpdate({ + startDate: startDate.clone().subtract(1, 'days'), + endDate, + minDate, + maxDate, + today, + date: dateOut + }); + let instanceStart = dayStart.instance(); + instanceStart.shouldComponentUpdate({ + startDate: startDate.clone().subtract(1, 'days'), + endDate, + minDate, + maxDate, + today, + date: dateStart + }); + let instanceEnd = dayEnd.instance(); + let instanceMid = dayMid.instance(); + let instanceEmpty = dayEmpty.instance(); + done(); +}); diff --git a/__tests__/index.android.js b/__tests__/index.android.js deleted file mode 100644 index b49b908..0000000 --- a/__tests__/index.android.js +++ /dev/null @@ -1,12 +0,0 @@ -import 'react-native'; -import React from 'react'; -import Index from '../index.android.js'; - -// Note: test renderer must be required after react-native. -import renderer from 'react-test-renderer'; - -it('renders correctly', () => { - const tree = renderer.create( - - ); -}); diff --git a/__tests__/index.ios.js b/__tests__/index.ios.js deleted file mode 100644 index ba7c5b5..0000000 --- a/__tests__/index.ios.js +++ /dev/null @@ -1,12 +0,0 @@ -import 'react-native'; -import React from 'react'; -import Index from '../index.ios.js'; - -// Note: test renderer must be required after react-native. -import renderer from 'react-test-renderer'; - -it('renders correctly', () => { - const tree = renderer.create( - - ); -}); diff --git a/index.ios.js b/index.ios.js index 4455713..353665e 100644 --- a/index.ios.js +++ b/index.ios.js @@ -17,8 +17,8 @@ export default class calendar extends Component { super(props); this.calendar = null; this.state = { - startDate: new Date(2017, 6, 12), - endDate: new Date(2017, 7, 23) + startDate: new Date(2017, 7, 12), + endDate: new Date(2017, 8, 23) }; this.openCalendar = this.openCalendar.bind(this); this.confirmDate = this.confirmDate.bind(this); @@ -53,8 +53,7 @@ export default class calendar extends Component { }; // optional property, too. let color = { - subColor: '#f4d329', - mainColor: '#47464b' + mainColor: '#138691' }; const { startDate, @@ -69,7 +68,7 @@ export default class calendar extends Component { title="press" onPress={this.openCalendar} > - 选 择 + Choose Dates {text} @@ -80,7 +79,7 @@ export default class calendar extends Component { ref={(calendar) => {this.calendar = calendar;}} format="YYYYMMDD" minDate="20170510" - maxDate="20180812" + maxDate="20180412" startDate={this.state.startDate} endDate={this.state.endDate} onConfirm={this.confirmDate} @@ -103,7 +102,7 @@ const styles = StyleSheet.create({ overflow: 'hidden', borderRadius: 6, marginBottom: 30, - backgroundColor: '#db9c0e' + backgroundColor: '#138691' }, btnFont: { color: '#fff', @@ -117,7 +116,7 @@ const styles = StyleSheet.create({ font: { fontSize: 24, fontWeight: '400', - color: '#11a4e3' + color: '#304853' }, instructions: { textAlign: 'center', diff --git a/package.json b/package.json index 4d3ae6b..b1c77f1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-native-calendar-select", - "version": "0.0.1", - "description": "Calendar component for react-native, like Airbnb.", + "version": "0.1.1", + "description": "Calendar select component for react-native, like Airbnb.", "main": "./Calendar.js", "repository": { "type": "git", diff --git a/readme.md b/readme.md index 416e20f..9fd6907 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -## react-native-calendar-select +## react-native-calendar-select [![Build Status](https://travis-ci.org/Tinysymphony/react-native-calendar-select.svg?branch=master)](https://travis-ci.org/Tinysymphony/react-native-calendar-select) [![Coverage Status](https://coveralls.io/repos/github/Tinysymphony/react-native-calendar-select/badge.svg?branch=master)](https://coveralls.io/github/Tinysymphony/react-native-calendar-select?branch=master) A date picker component like Airbnb. You can select a date period from the calendar modal. @@ -46,10 +46,11 @@ import Calendar from 'react-native-calendar-select'; constructor (props) { super(props); this.state = { - startDate: '20170712', - endDate: '20170820' + startDate: new Date(2017, 6, 12), + endDate: new Date(2017, 8, 2) }; this.confirmDate = this.confirmDate.bind(this); + this.openCalendar = this.openCalendar.bind(this); } // when confirm button is clicked, an object is conveyed to outer component // contains following property: @@ -61,6 +62,9 @@ confirmDate({startDate, endDate, startMoment, endMoment}) { endDate }); } +openCalendar() { + this.calendar && this.calendar.open(); +} // in render function render() { // It's an optional property, I use this to show the structure of customI18n object. @@ -81,17 +85,21 @@ render() { subColor: '#f0f0f0' }; return ( - + +