From b42ff67b07944178bd343e67a175c8c484f458a9 Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 25 Mar 2018 17:01:21 +0100 Subject: [PATCH 1/4] Add new component --- src/components/shared/forms/DateInput.vue | 76 +++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/components/shared/forms/DateInput.vue diff --git a/src/components/shared/forms/DateInput.vue b/src/components/shared/forms/DateInput.vue new file mode 100644 index 0000000..4a05ba3 --- /dev/null +++ b/src/components/shared/forms/DateInput.vue @@ -0,0 +1,76 @@ + + + From d87c29b0f24bf5f5e3ef233c7e1bd25633624ebb Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 25 Mar 2018 17:03:03 +0100 Subject: [PATCH 2/4] docs and tests --- .../shared/forms/croud-date-input.md | 14 ++++ test/unit/forms/DateInput.spec.js | 81 +++++++++++++++++++ .../__snapshots__/DateInput.spec.js.snap | 11 +++ 3 files changed, 106 insertions(+) create mode 100644 src/components/shared/forms/croud-date-input.md create mode 100644 test/unit/forms/DateInput.spec.js create mode 100644 test/unit/forms/__snapshots__/DateInput.spec.js.snap diff --git a/src/components/shared/forms/croud-date-input.md b/src/components/shared/forms/croud-date-input.md new file mode 100644 index 0000000..2a29995 --- /dev/null +++ b/src/components/shared/forms/croud-date-input.md @@ -0,0 +1,14 @@ +### Basic usage +Pass through a moment object or an iso string to set the initial value + + + +### Invalid date +This component will emit the **invalid-date** event if the date input is cleared down or if moment can't parse the date from the input + + + +### Validation +You can use the **min** and **max** props to set the limits of the date input. This is usually handled by the html5 input, but this component will emit a **validation-error** event if the date selected falls outside of the min and max values + + diff --git a/test/unit/forms/DateInput.spec.js b/test/unit/forms/DateInput.spec.js new file mode 100644 index 0000000..56bd62f --- /dev/null +++ b/test/unit/forms/DateInput.spec.js @@ -0,0 +1,81 @@ +import Vue from 'vue' +import moment from 'moment' +import DateInput from '../../../src/components/shared/forms/DateInput' + +const Constructor = Vue.extend(DateInput) + +const vm = new Constructor({ + propsData: { + value: moment(), + }, +}).$mount() + +const input = jest.fn() +const invalid = jest.fn() +const validation = jest.fn() +vm.$on('input', input) +vm.$on('invalid-date', invalid) +vm.$on('validation-error', validation) + +describe('Date Input', () => { + it('should match the snapshot', () => { + expect(vm.$el).toMatchSnapshot() + }) + + describe('events', () => { + beforeEach(() => { + input.mockReset() + invalid.mockReset() + validation.mockReset() + }) + it('should fire input event when date changes', (done) => { + vm.date = moment().add(1, 'd') + vm.$nextTick(() => { + expect(input).toBeCalled() + done() + }) + }) + + it('should fire invalid-date event when date is cleared', (done) => { + vm.date = '' + vm.$nextTick(() => { + expect(invalid).toBeCalled() + done() + }) + }) + + describe('validation', () => { + it('should fire validation-error event if sooner than min date', (done) => { + vm.min = moment().add(1, 'd') + vm.max = null + vm.date = moment() + vm.$nextTick(() => { + expect(validation).toBeCalled() + done() + }) + }) + + it('should fire validation-error event if later than max date', (done) => { + vm.min = null + vm.max = moment().subtract(1, 'd') + vm.date = moment() + + vm.$nextTick(() => { + expect(validation).toBeCalled() + done() + }) + }) + + it('should not fire validation-error if between min and max', (done) => { + vm.min = moment().subtract(1, 'd') + vm.max = moment().add(1, 'd') + vm.date = moment() + + vm.$nextTick(() => { + expect(validation).not.toBeCalled() + done() + }) + }) + }) + }) +}) diff --git a/test/unit/forms/__snapshots__/DateInput.spec.js.snap b/test/unit/forms/__snapshots__/DateInput.spec.js.snap new file mode 100644 index 0000000..2278c3e --- /dev/null +++ b/test/unit/forms/__snapshots__/DateInput.spec.js.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Date Input should match the snapshot 1`] = ` +
+ +
+`; From 70819321e5b5bebc833588b70619890a3d7a538d Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 26 Mar 2018 13:14:58 +0100 Subject: [PATCH 3/4] better error handling --- src/components/shared/forms/DateInput.vue | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/shared/forms/DateInput.vue b/src/components/shared/forms/DateInput.vue index 4a05ba3..aa2bb48 100644 --- a/src/components/shared/forms/DateInput.vue +++ b/src/components/shared/forms/DateInput.vue @@ -1,5 +1,5 @@ @@ -42,25 +42,31 @@ data() { return { format: 'YYYY-MM-DD', + error: false, } }, computed: { date: { get() { - return moment(this.value).format(this.format) + const date = moment(this.value) + return date.isValid() ? moment(this.value).format(this.format) : this.value }, set(val) { const date = moment(val, this.format, true) if (!date.isValid()) { this.$emit('invalid-date', date) + this.error = true } else if ((this.max && date.isAfter(moment(this.max), 'd')) || (this.min && date.isBefore(moment(this.min), 'd'))) { this.$emit('validation-error', date) + this.error = true + } else { + this.error = false } - this.$emit('input', date) + this.$emit('input', date.isValid() ? date : val) }, }, From e7f04b0bd29ead2e195acb592820500f209e2b8c Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 26 Mar 2018 13:15:14 +0100 Subject: [PATCH 4/4] More test coverage for error handling --- test/unit/forms/DateInput.spec.js | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/test/unit/forms/DateInput.spec.js b/test/unit/forms/DateInput.spec.js index 56bd62f..a0e85b1 100644 --- a/test/unit/forms/DateInput.spec.js +++ b/test/unit/forms/DateInput.spec.js @@ -28,6 +28,11 @@ describe('Date Input', () => { invalid.mockReset() validation.mockReset() }) + + it('shouldn\'t be in an error state by default', () => { + expect(vm.error).toBe(false) + }) + it('should fire input event when date changes', (done) => { vm.date = moment().add(1, 'd') vm.$nextTick(() => { @@ -36,11 +41,22 @@ describe('Date Input', () => { }) }) - it('should fire invalid-date event when date is cleared', (done) => { - vm.date = '' - vm.$nextTick(() => { - expect(invalid).toBeCalled() - done() + describe('invalid date', () => { + it('should fire invalid-date event when date is cleared', (done) => { + vm.date = '' + vm.$nextTick(() => { + expect(invalid).toBeCalled() + done() + }) + }) + + it('should notice an invalid date and add error class', (done) => { + vm.date = '2018-04-31' + vm.$nextTick(() => { + expect(invalid).toBeCalled() + expect(vm.error).toBe(true) + done() + }) }) }) @@ -51,6 +67,7 @@ describe('Date Input', () => { vm.date = moment() vm.$nextTick(() => { expect(validation).toBeCalled() + expect(vm.error).toBe(true) done() }) }) @@ -62,6 +79,7 @@ describe('Date Input', () => { vm.$nextTick(() => { expect(validation).toBeCalled() + expect(vm.error).toBe(true) done() }) }) @@ -73,6 +91,7 @@ describe('Date Input', () => { vm.$nextTick(() => { expect(validation).not.toBeCalled() + expect(vm.error).toBe(false) done() }) })