From a51829aa28c89265aaf456d439ff0808465b20ce Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 16 Feb 2016 00:48:01 +0900 Subject: [PATCH] feat(errors): add validator-errors and validator-error component --- src/components/error.js | 37 +++++ src/components/errors.js | 80 ++++++++++ src/index.js | 2 + test/specs/components/errors.js | 249 ++++++++++++++++++++++++++++++++ test/specs/index.js | 1 + 5 files changed, 369 insertions(+) create mode 100644 src/components/error.js create mode 100644 src/components/errors.js create mode 100644 test/specs/components/errors.js diff --git a/src/components/error.js b/src/components/error.js new file mode 100644 index 0000000..d36ef81 --- /dev/null +++ b/src/components/error.js @@ -0,0 +1,37 @@ +export default function (Vue) { + + /** + * ValidatorError component + */ + + let error = { + name: 'validator-error', + + props: { + field: { + type: String, + required: true + }, + validator: { + type: String + }, + message: { + type: String, + required: true + }, + partial: { + type: String, + default: 'validator-error-default' + } + }, + + template: '', + + partials: {} + } + + // only use ValidatorError component + error.partials['validator-error-default'] = '

{{field}}: {{message}}

' + + return error +} diff --git a/src/components/errors.js b/src/components/errors.js new file mode 100644 index 0000000..e0429d2 --- /dev/null +++ b/src/components/errors.js @@ -0,0 +1,80 @@ +import ValidatorError from './error' + + +export default function (Vue) { + + // import ValidatorError component + const error = ValidatorError(Vue) + + + /** + * ValidatorErrors component + */ + + let errors = { + name: 'validator-errors', + + props: { + validation: { + type: Object, + required: true + }, + group: { + type: String, + default: null + }, + field: { + type: String, + default: null + }, + component: { + type: String, + default: 'validator-error' + } + }, + + computed: { + errors () { + let ret = [] + if (this.group !== null) { + for (let field in this.validation[this.group].errors) { + for (let validator in this.validation[this.group].errors[field]) { + let message = this.validation[this.group].errors[field][validator] + ret.push({ field: field, validator: validator, message: message }) + } + } + } else if (this.field === null) { + for (let field in this.validation.errors) { + for (let validator in this.validation.errors[field]) { + let message = this.validation.errors[field][validator] + ret.push({ field: field, validator: validator, message: message }) + } + } + } else { + for (let validator in this.validation.errors[this.field]) { + let message = this.validation.errors[this.field][validator] + ret.push({ field: this.field, validator: validator, message: message }) + } + } + return ret + } + }, + + template: '', + + components: {} + } + + // define 'partial' prop + errors.props['partial'] = error.props['partial'] + + // only use ValidatorErrors component + errors.components[error.name] = error + + // install ValidatorErrors component + Vue.component(errors.name, errors) + + return errors +} diff --git a/src/index.js b/src/index.js index 2365217..e7c441b 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ import Asset from './asset' import Override from './override' import Validate from './directives/validate' import Validator from './directives/validator' +import Errors from './components/errors' /** @@ -20,6 +21,7 @@ function plugin (Vue, options = {}) { util.Vue = Vue Asset(Vue) + Errors(Vue) Override(Vue) Validator(Vue) diff --git a/test/specs/components/errors.js b/test/specs/components/errors.js new file mode 100644 index 0000000..204abdd --- /dev/null +++ b/test/specs/components/errors.js @@ -0,0 +1,249 @@ +import assert from 'power-assert' +import Vue from 'vue' +import { each } from '../../../src/util' + + +describe('validator-errors', () => { + let el, vm + + beforeEach(() => { + el = document.createElement('div') + }) + + + describe('basic', () => { + beforeEach((done) => { + el.innerHTML = + '' + + '' + + '' + + '' + + '' + vm = new Vue({ + el: el, + data: { + field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } }, + field2: { + required: { rule: true, message: 'field2 required' }, + minlength: { rule: 2, message: 'field2 short too' } + } + } + }) + vm.$nextTick(done) + }) + + it('should be rendered error messages', () => { + let matchCount = 0 + + let errorElements = el.getElementsByTagName('p') + for (var i = 0, l = errorElements.length; i < l; i++) { + var element = errorElements[i] + each([ + 'field1: field1 pattern error', + 'field2: field2 required', + 'field2: field2 short too' + ], (msg) => { + if (msg === element.textContent) { + matchCount++ + } + }) + } + + assert(matchCount === errorElements.length) + }) + }) + + + describe('partial', () => { + beforeEach((done) => { + el.innerHTML = + '' + + '' + + '' + + '' + + '' + vm = new Vue({ + partials: { + 'custom-error': '{{field}}:{{validator}}:{{message}}' + }, + data: { + field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } }, + field2: { + required: { rule: true, message: 'field2 required' }, + minlength: { rule: 2, message: 'field2 short too' } + } + } + }).$mount() + vm.$nextTick(() => { + vm.$appendTo(el) + done() + }) + }) + + it('should be rendered error messages', () => { + let matchCount = 0 + + let errorElements = el.getElementsByTagName('span') + for (var i = 0, l = errorElements.length; i < l; i++) { + var element = errorElements[i] + each([ + 'field1:pattern:field1 pattern error', + 'field2:required:field2 required', + 'field2:minlength:field2 short too' + ], (msg) => { + if (msg === element.textContent) { + matchCount++ + } + }) + } + + assert(matchCount === errorElements.length) + }) + }) + + + describe('component', () => { + beforeEach((done) => { + el.innerHTML = + '' + + '' + + '' + + '' + + '' + Vue.component('custom-error', { + props: ['field', 'validator', 'message'], + template: '
{{field}}:{{validator}}:{{message}}
' + }) + vm = new Vue({ + el: el, + data: { + field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } }, + field2: { + required: { rule: true, message: 'field2 required' }, + minlength: { rule: 2, message: 'field2 short too' } + } + } + }) + vm.$nextTick(done) + }) + + it('should be rendered error messages', () => { + let matchCount = 0 + + let errorElements = el.getElementsByTagName('div') + for (var i = 0, l = errorElements.length; i < l; i++) { + var element = errorElements[i] + each([ + 'field1:pattern:field1 pattern error', + 'field2:required:field2 required', + 'field2:minlength:field2 short too' + ], (msg) => { + if (msg === element.textContent) { + matchCount++ + } + }) + } + + assert(matchCount === errorElements.length) + }) + }) + + + describe('group', () => { + beforeEach((done) => { + el.innerHTML = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + vm = new Vue({ + el: el, + data: { + field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } }, + field2: { required: { rule: true, message: 'field2 required' } }, + field3: { max: { rule: 3, message: 'field3 big too' } }, + field4: { maxlength: { rule: 3, message: 'field4 long too' } } + }, + computed: { + message1 () { + return 'field5 small too' + } + }, + methods: { + onMessage2 (field) { + return 'field6 short too ' + field + } + } + }) + vm.$nextTick(done) + }) + + it('should be rendered error messages', () => { + let matchCount = 0 + + let errorElements = el.getElementsByTagName('p') + for (var i = 0, l = errorElements.length; i < l; i++) { + var element = errorElements[i] + each([ + 'field1: field1 pattern error', + 'field2: field2 required', + 'field5: field5 small too' + ], (msg) => { + console.log(msg, element.textContent) + if (msg === element.textContent) { + matchCount++ + } + }) + } + + assert(matchCount === errorElements.length) + }) + }) + + + describe('field', () => { + beforeEach((done) => { + el.innerHTML = + '' + + '' + + '' + + '' + + '' + vm = new Vue({ + el: el, + data: { + field1: { pattern: { rule: '/foo/', message: 'field1 pattern error' } }, + field2: { + required: { rule: true, message: 'field2 required' }, + minlength: { rule: 2, message: 'field2 short too' } + } + } + }) + vm.$nextTick(done) + }) + + it('should be rendered error messages', () => { + let matchCount = 0 + + let errorElements = el.getElementsByTagName('p') + for (var i = 0, l = errorElements.length; i < l; i++) { + var element = errorElements[i] + each([ + 'field2: field2 required', + 'field2: field2 short too' + ], (msg) => { + if (msg === element.textContent) { + matchCount++ + } + }) + } + + assert(matchCount === errorElements.length) + }) + }) +}) diff --git a/test/specs/index.js b/test/specs/index.js index 02d61ba..a1d8a1e 100644 --- a/test/specs/index.js +++ b/test/specs/index.js @@ -22,6 +22,7 @@ require('./invalid') require('./event') require('./group') require('./multiple') +require('./components/errors') require('./messages') require('./lazy') require('./checkbox')