Skip to content

Commit

Permalink
tests for validation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Frizi committed Nov 23, 2016
1 parent aa3979c commit 7ef1d0d
Show file tree
Hide file tree
Showing 7 changed files with 379 additions and 31 deletions.
2 changes: 1 addition & 1 deletion docs/partials/api/_values.pug
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@
td.table__td: strong object
td.table__td
| Holds all validation models of collection validator. Always preserves
| the keys of original model, so it can be safely referenced in the <kdb>v-for</kdb>
| the keys of original model, so it can be safely referenced in the <kbd>v-for</kbd>
| loop iterating over your data using the same index.
9 changes: 7 additions & 2 deletions docs/partials/examples/ExampleEachArray.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
button.button(@click="people.push({name: ''})") Add
button.button(@click="people.pop()") Remove
.form-group(v-bind:class="{ 'form-group--error': $v.people.$error }")
span.form-group__message(v-if="$v.people.$error") List is invalid.
span.form-group__message(v-if="!$v.people.minLength") List must have at least 2 elements.
span.form-group__message(v-else-if="!$v.people.required") List must not be empty.
span.form-group__message(v-else-if="$v.people.$error") List is invalid.
button.button(@click="$v.people.$touch") $touch
button.button(@click="$v.people.$reset") $reset

pre
| people: {{ $v.people }}
Expand All @@ -32,7 +36,8 @@ export default {
validations: {
people: {
minLength: minLength(1),
required,
minLength: minLength(2),
$each: {
name: {
required
Expand Down
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,17 @@
"phantomjs-prebuilt": "^2.1.3",
"pug": "2.0.0-beta6",
"pug-loader": "^2.3.0",
"raw-loader": "^0.5.1",
"sass-loader": "^3.2.0",
"semver": "^5.3.0",
"shelljs": "^0.7.4",
"sinon": "^1.17.3",
"sinon-chai": "^2.8.0",
"url-loader": "^0.5.7",
"vue": "^2.0.4",
"vue-loader": "^9.4.0",
"vue": "^2.1.0",
"vue-loader": "^10.0.0",
"vue-style-loader": "^1.0.0",
"vue-template-compiler": "^2.1.0",
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.8.3",
"webpack-hot-middleware": "^2.12.2",
Expand All @@ -85,8 +87,5 @@
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"dependencies": {
"raw-loader": "^0.5.1"
}
}
34 changes: 14 additions & 20 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ function isObject (ruleset) {
return ruleset !== null && typeof ruleset === 'object'
}

const getPath = (obj, path, fallback) => {
const getPath = (ctx, obj, path, fallback) => {
if (typeof path === 'function') {
return path.call(obj, fallback)
return path.call(ctx, obj, fallback)
}

path = Array.isArray(path) ? path : path.split('.')
Expand Down Expand Up @@ -82,16 +82,11 @@ const defaultComputed = {
const defaultMethodKeys = Object.keys(defaultMethods)
const defaultComputedKeys = Object.keys(defaultComputed)
const mapDynamicKeyName = k => 'v$$' + k
const proxyValidationGuard = '__isProxyValidation'

function isSingleRule (ruleset) {
return typeof ruleset === 'function'
}

function isProxyVm (rule) {
return rule[proxyValidationGuard] === true
}

function makeValidationVm (validations, parentVm, rootVm = parentVm, parentProp = null) {
const validationKeys = Object.keys(validations).filter(key => !!validations[key])
const dynamicKeys = validationKeys.map(mapDynamicKeyName)
Expand All @@ -118,9 +113,7 @@ function makeValidationVm (validations, parentVm, rootVm = parentVm, parentProp
}

function mapValidator (rootVm, rule, ruleKey, vm, vmProp) {
if (isProxyVm(rule)) {
return rule
} else if (isSingleRule(rule)) {
if (isSingleRule(rule)) {
return mapRule(rootVm, rule, ruleKey, vm, vmProp)
} else if (Array.isArray(rule)) {
return mapGroup(rootVm, rule, ruleKey, vm, vmProp)
Expand All @@ -137,14 +130,14 @@ function mapRule (rootVm, rule, ruleKey, parentVm, prop) {

function mapChild (rootVm, rules, ruleKey, parentVm, prop) {
if (ruleKey === '$each') {
return trackArray(rootVm, rules, parentVm, prop)
return trackCollection(rootVm, rules, parentVm, prop)
}
const childVm = typeof prop === 'string' ? parentVm[prop] : parentVm
const vm = makeValidationVm(rules, childVm, rootVm, ruleKey)
return constant(vm)
}

function trackArray (rootVm, eachRule, parentVm, prop) {
function trackCollection (rootVm, eachRule, parentVm, prop) {
let vmList = {}
const strippedRule = {
...eachRule,
Expand All @@ -155,13 +148,13 @@ function trackArray (rootVm, eachRule, parentVm, prop) {
const childVm = typeof prop === 'string' ? parentVm[prop] : parentVm
const newKeys = Object.keys(childVm)
const keyToTrack = typeof eachRule.$trackBy !== 'undefined'
? buildFromKeys(newKeys, key => getPath(childVm[key], eachRule.$trackBy))
? buildFromKeys(newKeys, key => getPath(rootVm, childVm[key], eachRule.$trackBy))
: null

const vmByKey = {}
vmList = newKeys.reduce((newList, key) => {
const track = keyToTrack ? keyToTrack[key] : key
vmByKey[key] = newList[track] = vmList[track] || mapValidator(rootVm, strippedRule, key, childVm)
vmByKey[key] = newList[track] = newList[track] || vmList[track] || mapValidator(rootVm, strippedRule, key, childVm)
return newList
}, {})

Expand All @@ -172,7 +165,7 @@ function trackArray (rootVm, eachRule, parentVm, prop) {
function mapGroup (rootVm, group, prop, parentVm) {
const rules = buildFromKeys(
group,
path => function () { return getPath(this.$v, path) }
path => function () { return getPath(this, this.$v, path) }
)

const vm = makeValidationVm(rules, parentVm, rootVm, prop)
Expand All @@ -198,10 +191,7 @@ function proxyVm (vm, originalKeys) {
})),
...buildFromKeys(defaultMethodKeys, key => ({
value: vm[key].bind(vm)
})),
[proxyValidationGuard]: {
value: true
}
}))
}

return Object.defineProperties({}, redirectDef)
Expand All @@ -213,6 +203,7 @@ const validationMixin = {
if (!options.validations) return
const validations = options.validations

/* istanbul ignore if */
if (typeof options.computed === 'undefined') {
options.computed = {}
}
Expand All @@ -224,7 +215,10 @@ const validationMixin = {
const validateModel = (model, validations) => makeValidationVm(validations, model)

function Validation (Vue) {
if (Validation.installed) return
/* istanbul ignore if */
if (Validation.installed) {
return
}
Vue.mixin(validationMixin)
}

Expand Down
4 changes: 4 additions & 0 deletions test/unit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
/* eslint-disable no-extend-native */
Function.prototype.bind = require('function-bind')

import Vue from 'vue'
import Validation from '../../src/index'
Vue.use(Validation)

// require all test files (files that ends with .spec.js)
const testsContext = require.context('./specs', true, /\.spec$/)
testsContext.keys().forEach(testsContext)
Expand Down
Empty file removed test/unit/specs/groups.spec.js
Empty file.
Loading

0 comments on commit 7ef1d0d

Please sign in to comment.