Adds support for @braid/vue-formulate-i18n
* Adds support form FormulateError form errors * Adds support for form-errors prop Also includes tests for both named-form-errors as well, form-errors prop, positioning form errors with the <FormulateErrors /> component, and allowing multiple <FormulateErrors /> * Adds form error support, error handling, and supporting tests * Remove unused util functions * Adds german localization locales/de.js (#14) * Create de.js * Added startsWith and endsWith * adds build process for localization support, removes dist * Adds danish localization * fixes bug that resulted in validation failing if run more than once Credit to @luan-nk-nguyen for discovering the bug * Moves locales to vue-formulate-i18n * Adds dist files for locales * Adds vue-formulate-i18n 1.0.1 * Uses i18n 1.0.3 * Build files * Fixes #19 * Update src/locales/README.md Co-Authored-By: Andrew Boyd <andrew@wearebraid.com> * changes v-html to v-text for error message output credit to @skix123 for the bug report! Co-authored-by: Andrew Boyd <andrew@wearebraid.com>
This commit is contained in:
parent
adf8299a33
commit
34de4ba6dc
@ -1,20 +1,23 @@
|
||||
import commonjs from '@rollup/plugin-commonjs' // Convert CommonJS modules to ES6
|
||||
import buble from '@rollup/plugin-buble' // Transpile/polyfill with reasonable browser support
|
||||
import autoExternal from 'rollup-plugin-auto-external'
|
||||
import commonjs from 'rollup-plugin-commonjs' // Convert CommonJS modules to ES6
|
||||
import vue from 'rollup-plugin-vue' // Handle .vue SFC files
|
||||
import buble from 'rollup-plugin-buble' // Transpile/polyfill with reasonable browser support
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
|
||||
export default {
|
||||
input: 'src/Formulate.js', // Path relative to package.json
|
||||
output: {
|
||||
name: 'Formulate',
|
||||
exports: 'default',
|
||||
globals: {
|
||||
'is-plain-object': 'isPlainObject',
|
||||
'nanoid/non-secure': 'nanoid',
|
||||
'is-url': 'isUrl'
|
||||
output: [
|
||||
{
|
||||
name: 'Formulate',
|
||||
exports: 'default',
|
||||
globals: {
|
||||
'is-plain-object': 'isPlainObject',
|
||||
'nanoid/non-secure': 'nanoid',
|
||||
'is-url': 'isUrl',
|
||||
'@braid/vue-formulate-i18n': 'VueFormulateI18n'
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
external: ['nanoid/non-secure'],
|
||||
plugins: [
|
||||
commonjs(),
|
||||
|
@ -1,7 +1,7 @@
|
||||
import resolve from '@rollup/plugin-node-resolve'
|
||||
import commonjs from 'rollup-plugin-commonjs' // Convert CommonJS modules to ES6
|
||||
import commonjs from '@rollup/plugin-commonjs' // Convert CommonJS modules to ES6
|
||||
import buble from '@rollup/plugin-buble' // Transpile/polyfill with reasonable browser support
|
||||
import vue from 'rollup-plugin-vue' // Handle .vue SFC files
|
||||
import buble from 'rollup-plugin-buble' // Transpile/polyfill with reasonable browser support
|
||||
import internal from 'rollup-plugin-internal'
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
|
||||
@ -14,7 +14,8 @@ export default {
|
||||
globals: {
|
||||
'is-plain-object': 'isPlainObject',
|
||||
'nanoid/non-secure': 'nanoid',
|
||||
'is-url': 'isUrl'
|
||||
'is-url': 'isUrl',
|
||||
'@braid/vue-formulate-i18n': 'VueFormulateI18n'
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
@ -23,7 +24,7 @@ export default {
|
||||
preferBuiltins: false
|
||||
}),
|
||||
commonjs(),
|
||||
internal(['is-plain-object', 'nanoid/non-secure', 'is-url']),
|
||||
internal(['is-plain-object', 'nanoid/non-secure', 'is-url', '@braid/vue-formulate-i18n']),
|
||||
vue({
|
||||
css: true, // Dynamically inject css as a <style> tag
|
||||
compileTemplate: true // Explicitly convert template to render function
|
||||
|
2
dist/formulate.esm.js
vendored
2
dist/formulate.esm.js
vendored
File diff suppressed because one or more lines are too long
6
dist/formulate.min.js
vendored
6
dist/formulate.min.js
vendored
File diff suppressed because one or more lines are too long
1
dist/formulate.min.js.map
vendored
1
dist/formulate.min.js.map
vendored
@ -1 +0,0 @@
|
||||
{"version":3,"sources":["../node_modules/isobject/index.js","../node_modules/is-plain-object/index.js","Formulate.js"],"names":["isObject","val","Array","isArray","isObjectObject","o","Object","prototype","toString","call","isPlainObject","ctor","prot","constructor","hasOwnProperty","require","FormulateInput","Formulate","defaults","components","install","Vue","options","componentName","$formulate","extend","component","base","extendWith","merged","key","prop","module","exports"],"mappings":";AASC,aAFc,SAASA,EAASC,GACxBA,OAAO,MAAPA,GAA8B,iBAARA,IAA2C,IAAvBC,MAAMC,QAAQF,GAChE,OAAA,eAAA,QAAA,aAAA,CAAA,OAAA,IAAA,QAAA,QAAA;;ACyBA,aAAA,OAAA,eAAA,QAAA,aAAA,CAAA,OAAA,IAAA,QAAA,QAAA,EA3BD,IAAA,EAAA,EAAA,QAAA,aA2BC,SAAA,EAAA,GAAA,OAAA,GAAA,EAAA,WAAA,EAAA,CAAA,QAAA,GAzBD,SAASG,EAAeC,GACf,OAAgB,KAAhB,EAASA,EAAAA,SAAAA,IAC2B,oBAAtCC,OAAOC,UAAUC,SAASC,KAAKJ,GAGvB,SAASK,EAAcL,GAChCM,IAAAA,EAAKC,EAELR,OAAsB,IAAtBA,EAAeC,KAIC,mBADpBM,EAAON,EAAEQ,gBAKoB,IAAzBT,EADJQ,EAAOD,EAAKJ,aAIiC,IAAzCK,EAAKE,eAAe;;;;;AC5B1B,IAAIJ,EAAgBK,QAAQ,mBACxBC,EAAiBD,QAAQ,wBAKzBE,EAAY,WACTC,KAAAA,SAAW,CACdC,WAAY,CAEVH,eAAgBA,KAQtBC,EAAUV,UAAUa,QAAU,SAAUC,EAAKC,GAGtC,IAAA,IAAIC,KAFTF,EAAId,UAAUiB,WAAa,KACtBF,KAAAA,QAAU,KAAKG,OAAO,KAAKP,SAAUI,GAAW,IAC3B,KAAKA,QAAQH,WACrCE,EAAIK,UAAUH,EAAe,KAAKD,QAAQH,WAAWI,KASzDN,EAAUV,UAAUkB,OAAS,SAAUE,EAAMC,GACvCC,IAAAA,EAAS,GACR,IAAA,IAAIC,KAAOH,EACVC,EAAWd,eAAegB,GAC5BD,EAAOC,GAAOpB,EAAckB,EAAWE,KAASpB,EAAciB,EAAKG,IAC/D,KAAKL,OAAOE,EAAKG,GAAMF,EAAWE,IAClCF,EAAWE,GAEfD,EAAOC,GAAOH,EAAKG,GAGlB,IAAA,IAAIC,KAAQH,EACVC,EAAOf,eAAeiB,KACzBF,EAAOE,GAAQH,EAAWG,IAGvBF,OAAAA,GAGTG,OAAOC,QAAU,IAAIhB","file":"formulate.min.js","sourceRoot":"../src","sourcesContent":["/*!\n * isobject <https://github.com/jonschlinkert/isobject>\n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n\nexport default function isObject(val) {\n return val != null && typeof val === 'object' && Array.isArray(val) === false;\n};\n","/*!\n * is-plain-object <https://github.com/jonschlinkert/is-plain-object>\n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n\nimport isObject from 'isobject';\n\nfunction isObjectObject(o) {\n return isObject(o) === true\n && Object.prototype.toString.call(o) === '[object Object]';\n}\n\nexport default function isPlainObject(o) {\n var ctor,prot;\n\n if (isObjectObject(o) === false) return false;\n\n // If has modified constructor\n ctor = o.constructor;\n if (typeof ctor !== 'function') return false;\n\n // If has modified prototype\n prot = ctor.prototype;\n if (isObjectObject(prot) === false) return false;\n\n // If constructor does not have an Object-specific method\n if (prot.hasOwnProperty('isPrototypeOf') === false) {\n return false;\n }\n\n // Most likely a plain Object\n return true;\n};\n","var isPlainObject = require('is-plain-object')\nvar FormulateInput = require('./FormulateInput.vue')\n\n/**\n * The base formulate libary.\n */\nvar Formulate = function () {\n this.defaults = {\n components: {\n // FormulateForm: FormulateForm,\n FormulateInput: FormulateInput\n }\n }\n}\n\n/**\n * Install vue formulate, and register it’s components.\n */\nFormulate.prototype.install = function (Vue, options) {\n Vue.prototype.$formulate = this\n this.options = this.extend(this.defaults, options || {})\n for (var componentName in this.options.components) {\n Vue.component(componentName, this.options.components[componentName])\n }\n}\n\n/**\n * Create a new object by copying properties of base and extendWith.\n * @param {Object} base\n * @param {Object} extendWith\n */\nFormulate.prototype.extend = function (base, extendWith) {\n var merged = {}\n for (var key in base) {\n if (extendWith.hasOwnProperty(key)) {\n merged[key] = isPlainObject(extendWith[key]) && isPlainObject(base[key])\n ? this.extend(base[key], extendWith[key])\n : extendWith[key]\n } else {\n merged[key] = base[key]\n }\n }\n for (var prop in extendWith) {\n if (!merged.hasOwnProperty(prop)) {\n merged[prop] = extendWith[prop]\n }\n }\n return merged\n}\n\nmodule.exports = new Formulate()\n"]}
|
2
dist/formulate.umd.js
vendored
2
dist/formulate.umd.js
vendored
File diff suppressed because one or more lines are too long
1009
package-lock.json
generated
1009
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,8 @@
|
||||
"@babel/core": "^7.8.4",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"@rollup/plugin-buble": "^0.21.1",
|
||||
"@rollup/plugin-commonjs": "^11.0.2",
|
||||
"@rollup/plugin-node-resolve": "^7.1.1",
|
||||
"@vue/component-compiler-utils": "^3.1.1",
|
||||
"@vue/test-utils": "^1.0.0-beta.31",
|
||||
@ -55,6 +57,7 @@
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^24.9.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"cypress": "^4.1.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-plugin-import": "^2.20.1",
|
||||
@ -70,9 +73,8 @@
|
||||
"postcss-cli": "^6.1.3",
|
||||
"rollup": "^1.31.1",
|
||||
"rollup-plugin-auto-external": "^2.0.0",
|
||||
"rollup-plugin-buble": "^0.19.8",
|
||||
"rollup-plugin-commonjs": "^10.1.0",
|
||||
"rollup-plugin-internal": "^1.0.4",
|
||||
"rollup-plugin-multi-input": "^1.1.1",
|
||||
"rollup-plugin-terser": "^5.2.0",
|
||||
"rollup-plugin-vue": "^5.1.6",
|
||||
"typescript": "^3.8.2",
|
||||
@ -84,6 +86,7 @@
|
||||
"watch": "^1.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braid/vue-formulate-i18n": "^1.0.3",
|
||||
"is-plain-object": "^3.0.0",
|
||||
"is-url": "^1.2.4",
|
||||
"nanoid": "^2.1.11"
|
||||
|
@ -1,10 +1,10 @@
|
||||
import library from './libs/library'
|
||||
import rules from './libs/rules'
|
||||
import en from './locales/en'
|
||||
import mimes from './libs/mimes'
|
||||
import FileUpload from './FileUpload'
|
||||
import { arrayify } from './libs/utils'
|
||||
import { arrayify, parseLocale } from './libs/utils'
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import { en } from '@braid/vue-formulate-i18n'
|
||||
import fauxUploader from './libs/faux-uploader'
|
||||
import FormulateInput from './FormulateInput.vue'
|
||||
import FormulateForm from './FormulateForm.vue'
|
||||
@ -44,7 +44,7 @@ class Formulate {
|
||||
library,
|
||||
rules,
|
||||
mimes,
|
||||
locale: 'en',
|
||||
locale: false,
|
||||
uploader: fauxUploader,
|
||||
uploadUrl: false,
|
||||
fileUrlKey: 'url',
|
||||
@ -146,11 +146,47 @@ class Formulate {
|
||||
return { ...this.options.rules, ...rules }
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the vue-i18n configured locale.
|
||||
*/
|
||||
i18n (vm) {
|
||||
if (vm.$i18n && vm.$i18n.locale) {
|
||||
return vm.$i18n.locale
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the proper locale to use.
|
||||
*/
|
||||
getLocale (vm) {
|
||||
if (!this.selectedLocale) {
|
||||
this.selectedLocale = [
|
||||
this.options.locale,
|
||||
this.i18n(vm),
|
||||
'en'
|
||||
].reduce((selection, locale) => {
|
||||
if (selection) {
|
||||
return selection
|
||||
}
|
||||
if (locale) {
|
||||
const option = parseLocale(locale)
|
||||
.find(locale => Object.prototype.hasOwnProperty.call(this.options.locales, locale))
|
||||
if (option) {
|
||||
selection = option
|
||||
}
|
||||
}
|
||||
return selection
|
||||
}, false)
|
||||
}
|
||||
return this.selectedLocale
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation message for a particular error.
|
||||
*/
|
||||
validationMessage (rule, validationContext) {
|
||||
const generators = this.options.locales[this.options.locale]
|
||||
validationMessage (rule, validationContext, vm) {
|
||||
const generators = this.options.locales[this.getLocale(vm)]
|
||||
if (generators.hasOwnProperty(rule)) {
|
||||
return generators[rule](validationContext)
|
||||
} else if (rule[0] === '_' && generators.hasOwnProperty(rule.substr(1))) {
|
||||
|
@ -3,14 +3,12 @@
|
||||
v-if="visibleErrors.length"
|
||||
:class="`formulate-${type}-errors`"
|
||||
>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<li
|
||||
v-for="error in visibleErrors"
|
||||
:key="error"
|
||||
:class="`formulate-${type}-error`"
|
||||
v-html="error"
|
||||
v-text="error"
|
||||
/>
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
|
@ -316,7 +316,7 @@ export default {
|
||||
return () => this.messages[ruleName]
|
||||
}
|
||||
}
|
||||
return (context) => this.$formulate.validationMessage(rule.name, context)
|
||||
return (context) => this.$formulate.validationMessage(rule.name, context, this)
|
||||
},
|
||||
hasValidationErrors () {
|
||||
return new Promise(resolve => {
|
||||
|
@ -134,6 +134,9 @@ function showValidationErrors () {
|
||||
if (this.showErrors || this.formShouldShowErrors) {
|
||||
return true
|
||||
}
|
||||
if (this.classification === 'file' && this.uploadBehavior === 'live' && this.context.model) {
|
||||
return true
|
||||
}
|
||||
return this.behavioralErrorVisibility
|
||||
}
|
||||
|
||||
|
@ -79,17 +79,6 @@ export function arrayify (item) {
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* How to add an item.
|
||||
* @param {string} item
|
||||
*/
|
||||
export function sentence (item) {
|
||||
if (typeof item === 'string') {
|
||||
return item[0].toUpperCase() + item.substr(1)
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array or string return an array of callables.
|
||||
* @param {array|string} validation
|
||||
@ -199,3 +188,17 @@ export function cloneDeep (obj) {
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a locale string, parse the options.
|
||||
* @param {string} locale
|
||||
*/
|
||||
export function parseLocale (locale) {
|
||||
const segments = locale.split('-')
|
||||
return segments.reduce((options, segment) => {
|
||||
if (options.length) {
|
||||
options.unshift(`${options[0]}-${segment}`)
|
||||
}
|
||||
return options.length ? options : [segment]
|
||||
}, [])
|
||||
}
|
||||
|
9
src/locales/README.md
Normal file
9
src/locales/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# i18n moved
|
||||
|
||||
Locales have been removed from vue-formulate core to [vue-formulate-i18n](https://github.com/wearebraid/vue-formulate-i18n).
|
||||
This was done to allow for better tree-shaking by bundlers and allow
|
||||
for lots of additional language support without increasing the size of the core package.
|
||||
|
||||
## PRs welcome
|
||||
|
||||
[Please read the i18n contribution documentation](https://www.vueformulate.com/guide/contributing/#internationalization).
|
@ -1,191 +0,0 @@
|
||||
import { sentence as s } from '../libs/utils'
|
||||
/**
|
||||
* Validation error message generators.
|
||||
*/
|
||||
export default {
|
||||
|
||||
/**
|
||||
* Valid accepted value.
|
||||
*/
|
||||
accepted: function ({ name }) {
|
||||
return `Please accept the ${name}.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The date is not after.
|
||||
*/
|
||||
after: function ({ name, args }) {
|
||||
if (Array.isArray(args) && args.length) {
|
||||
return `${s(name)} must be after ${args[0]}.`
|
||||
}
|
||||
return `${s(name)} must be a later date.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The value is not a letter.
|
||||
*/
|
||||
alpha: function ({ name }) {
|
||||
return `${s(name)} can only contain alphabetical characters.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Rule: checks if the value is alpha numeric
|
||||
*/
|
||||
alphanumeric: function ({ name }) {
|
||||
return `${s(name)} can only contain letters and numbers.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The date is not before.
|
||||
*/
|
||||
before: function ({ name, args }) {
|
||||
if (Array.isArray(args) && args.length) {
|
||||
return `${s(name)} must be before ${args[0]}.`
|
||||
}
|
||||
return `${s(name)} must be an earlier date.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The value is not between two numbers or lengths
|
||||
*/
|
||||
between: function ({ name, value, args }) {
|
||||
if (!isNaN(value)) {
|
||||
return `${s(name)} must be between ${args[0]} and ${args[1]}.`
|
||||
}
|
||||
return `${s(name)} must be between ${args[0]} and ${args[1]} characters long.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The confirmation field does not match
|
||||
*/
|
||||
confirm: function ({ name, args }) {
|
||||
return `${s(name)} does not match.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Is not a valid date.
|
||||
*/
|
||||
date: function ({ name, args }) {
|
||||
if (Array.isArray(args) && args.length) {
|
||||
return `${s(name)} is not a valid, please use the format ${args[0]}`
|
||||
}
|
||||
return `${s(name)} is not a valid date.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The default render method for error messages.
|
||||
*/
|
||||
default: function ({ name }) {
|
||||
return `This field isn’t valid.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Is not a valid email address.
|
||||
*/
|
||||
email: function ({ name, value }) {
|
||||
if (!value) {
|
||||
return 'Please enter a valid email address.'
|
||||
}
|
||||
return `“${value}” is not a valid email address.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Ends with specified value
|
||||
*/
|
||||
endsWith: function ({ name, value }) {
|
||||
if (!value) {
|
||||
return `This field doesn’t end with a valid value.`
|
||||
}
|
||||
return `“${value}” doesn’t end with a valid value.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Value is an allowed value.
|
||||
*/
|
||||
in: function ({ name, value }) {
|
||||
if (typeof value === 'string' && value) {
|
||||
return `“${s(value)}” is not an allowed ${name}.`
|
||||
}
|
||||
return `This is not an allowed ${name}.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Value is not a match.
|
||||
*/
|
||||
matches: function ({ name }) {
|
||||
return `${s(name)} is not an allowed value.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The maximum value allowed.
|
||||
*/
|
||||
max: function ({ name, value, args }) {
|
||||
if (Array.isArray(value)) {
|
||||
return `You may only select ${args[0]} ${name}.`
|
||||
}
|
||||
const force = Array.isArray(args) && args[1] ? args[1] : false
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return `${s(name)} must be less than or equal to ${args[0]}.`
|
||||
}
|
||||
return `${s(name)} must be less than or equal to ${args[0]} characters long.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The (field-level) error message for mime errors.
|
||||
*/
|
||||
mime: function ({ name, args }) {
|
||||
return `${s(name)} must be of the the type: ${args[0] || 'No file formats allowed.'}`
|
||||
},
|
||||
|
||||
/**
|
||||
* The maximum value allowed.
|
||||
*/
|
||||
min: function ({ name, value, args }) {
|
||||
if (Array.isArray(value)) {
|
||||
return `You must select at least ${args[0]} ${name}.`
|
||||
}
|
||||
const force = Array.isArray(args) && args[1] ? args[1] : false
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return `${s(name)} must be more than ${args[0]}.`
|
||||
}
|
||||
return `${s(name)} must be more than ${args[0]} characters long.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The field is not an allowed value
|
||||
*/
|
||||
not: function ({ name, value }) {
|
||||
return `“${value}” is not an allowed ${name}.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The field is not a number
|
||||
*/
|
||||
number: function ({ name }) {
|
||||
return `${s(name)} must be a number.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Required field.
|
||||
*/
|
||||
required: function ({ name }) {
|
||||
return `${s(name)} is required.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts with specified value
|
||||
*/
|
||||
startsWith: function ({ name, value }) {
|
||||
if (!value) {
|
||||
return `This field doesn’t start with a valid value.`
|
||||
}
|
||||
return `“${value}” doesn’t start with a valid value.`
|
||||
},
|
||||
|
||||
/**
|
||||
* Value is not a url.
|
||||
*/
|
||||
url: function ({ name }) {
|
||||
return `Please include a valid url.`
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
import Formulate from '../src/Formulate.js'
|
||||
|
||||
test('can merge simple object', () => {
|
||||
let a = {
|
||||
optionA: true,
|
||||
optionB: '1234'
|
||||
}
|
||||
let b = {
|
||||
optionA: false
|
||||
}
|
||||
expect(Formulate.merge(a, b)).toEqual({
|
||||
optionA: false,
|
||||
optionB: '1234'
|
||||
})
|
||||
})
|
||||
|
||||
test('can add to simple array', () => {
|
||||
let a = {
|
||||
optionA: true,
|
||||
optionB: ['first', 'second']
|
||||
}
|
||||
let b = {
|
||||
optionB: ['third']
|
||||
}
|
||||
expect(Formulate.merge(a, b, true)).toEqual({
|
||||
optionA: true,
|
||||
optionB: ['first', 'second', 'third']
|
||||
})
|
||||
})
|
||||
|
||||
test('can merge recursively', () => {
|
||||
let a = {
|
||||
optionA: true,
|
||||
optionC: {
|
||||
first: '123',
|
||||
third: {
|
||||
a: 'b'
|
||||
}
|
||||
},
|
||||
optionB: '1234'
|
||||
}
|
||||
let b = {
|
||||
optionB: '567',
|
||||
optionC: {
|
||||
first: '1234',
|
||||
second: '789',
|
||||
}
|
||||
}
|
||||
expect(Formulate.merge(a, b)).toEqual({
|
||||
optionA: true,
|
||||
optionC: {
|
||||
first: '1234',
|
||||
third: {
|
||||
a: 'b'
|
||||
},
|
||||
second: '789'
|
||||
},
|
||||
optionB: '567'
|
||||
})
|
||||
})
|
||||
|
||||
test('installs on vue instance', () => {
|
||||
const components = [
|
||||
'FormulateForm',
|
||||
'FormulateInput',
|
||||
'FormulateErrors',
|
||||
'FormulateInputBox',
|
||||
'FormulateInputText',
|
||||
'FormulateInputFile',
|
||||
'FormulateInputGroup',
|
||||
'FormulateInputButton',
|
||||
'FormulateInputSelect',
|
||||
'FormulateInputSlider',
|
||||
'FormulateInputTextArea'
|
||||
]
|
||||
const registry = []
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {
|
||||
registry.push(name)
|
||||
}
|
||||
Formulate.install(Vue, { extended: true })
|
||||
expect(Vue.prototype.$formulate).toBe(Formulate)
|
||||
expect(registry).toEqual(components)
|
||||
})
|
||||
|
||||
test('can extend instance in a plugin', () => {
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {}
|
||||
const plugin = function (i) {
|
||||
i.extend({
|
||||
rules: {
|
||||
testRule: () => false
|
||||
}
|
||||
})
|
||||
}
|
||||
Formulate.install(Vue, {
|
||||
plugins: [ plugin ]
|
||||
})
|
||||
|
||||
expect(typeof Vue.prototype.$formulate.options.rules.testRule).toBe('function')
|
||||
})
|
169
test/unit/Formulate.test.js
Normal file
169
test/unit/Formulate.test.js
Normal file
@ -0,0 +1,169 @@
|
||||
import Formulate from '@/Formulate.js'
|
||||
|
||||
describe('Formulate', () => {
|
||||
it('can merge simple object', () => {
|
||||
let a = {
|
||||
optionA: true,
|
||||
optionB: '1234'
|
||||
}
|
||||
let b = {
|
||||
optionA: false
|
||||
}
|
||||
expect(Formulate.merge(a, b)).toEqual({
|
||||
optionA: false,
|
||||
optionB: '1234'
|
||||
})
|
||||
})
|
||||
|
||||
it('can add to simple array', () => {
|
||||
let a = {
|
||||
optionA: true,
|
||||
optionB: ['first', 'second']
|
||||
}
|
||||
let b = {
|
||||
optionB: ['third']
|
||||
}
|
||||
expect(Formulate.merge(a, b, true)).toEqual({
|
||||
optionA: true,
|
||||
optionB: ['first', 'second', 'third']
|
||||
})
|
||||
})
|
||||
|
||||
it('can merge recursively', () => {
|
||||
let a = {
|
||||
optionA: true,
|
||||
optionC: {
|
||||
first: '123',
|
||||
third: {
|
||||
a: 'b'
|
||||
}
|
||||
},
|
||||
optionB: '1234'
|
||||
}
|
||||
let b = {
|
||||
optionB: '567',
|
||||
optionC: {
|
||||
first: '1234',
|
||||
second: '789',
|
||||
}
|
||||
}
|
||||
expect(Formulate.merge(a, b)).toEqual({
|
||||
optionA: true,
|
||||
optionC: {
|
||||
first: '1234',
|
||||
third: {
|
||||
a: 'b'
|
||||
},
|
||||
second: '789'
|
||||
},
|
||||
optionB: '567'
|
||||
})
|
||||
})
|
||||
|
||||
it('installs on vue instance', () => {
|
||||
const components = [
|
||||
'FormulateForm',
|
||||
'FormulateInput',
|
||||
'FormulateErrors',
|
||||
'FormulateInputBox',
|
||||
'FormulateInputText',
|
||||
'FormulateInputFile',
|
||||
'FormulateInputGroup',
|
||||
'FormulateInputButton',
|
||||
'FormulateInputSelect',
|
||||
'FormulateInputSlider',
|
||||
'FormulateInputTextArea'
|
||||
]
|
||||
const registry = []
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {
|
||||
registry.push(name)
|
||||
}
|
||||
Formulate.install(Vue, { extended: true })
|
||||
expect(Vue.prototype.$formulate).toBe(Formulate)
|
||||
expect(registry).toEqual(components)
|
||||
})
|
||||
|
||||
it('can extend instance in a plugin', () => {
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {}
|
||||
const plugin = function (i) {
|
||||
i.extend({
|
||||
rules: {
|
||||
testRule: () => false
|
||||
}
|
||||
})
|
||||
}
|
||||
Formulate.install(Vue, {
|
||||
plugins: [ plugin ]
|
||||
})
|
||||
|
||||
expect(typeof Vue.prototype.$formulate.options.rules.testRule).toBe('function')
|
||||
})
|
||||
|
||||
it('locale default to en', () => {
|
||||
Formulate.selectedLocale = false // reset the memoization
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {}
|
||||
const vm = {}
|
||||
Formulate.install(Vue, {
|
||||
locales: {
|
||||
de: {},
|
||||
fr: {},
|
||||
cn: {},
|
||||
en: {}
|
||||
}
|
||||
})
|
||||
expect(Vue.prototype.$formulate.getLocale(vm)).toBe('en')
|
||||
})
|
||||
|
||||
it('explicitly selects language', () => {
|
||||
Formulate.selectedLocale = false // reset the memoization
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {}
|
||||
const vm = {}
|
||||
Formulate.install(Vue, {
|
||||
locale: 'fr-CH',
|
||||
locales: {
|
||||
de: {},
|
||||
fr: {},
|
||||
cn: {},
|
||||
en: {}
|
||||
}
|
||||
})
|
||||
expect(Vue.prototype.$formulate.getLocale(vm)).toBe('fr')
|
||||
})
|
||||
|
||||
it('can select a specific language tag', () => {
|
||||
Formulate.selectedLocale = false // reset the memoization
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {}
|
||||
const vm = {}
|
||||
Formulate.install(Vue, {
|
||||
locale: 'nl-BE',
|
||||
locales: {
|
||||
de: {},
|
||||
fr: {},
|
||||
'nl-BE': {},
|
||||
nl: {},
|
||||
cn: {},
|
||||
en: {}
|
||||
}
|
||||
})
|
||||
expect(Vue.prototype.$formulate.getLocale(vm)).toBe('nl-BE')
|
||||
})
|
||||
|
||||
it('can select a matching locale using i18n', () => {
|
||||
Formulate.selectedLocale = false // reset the memoization
|
||||
function Vue () {}
|
||||
Vue.component = function (name, instance) {}
|
||||
const vm = { $i18n: {locale: 'cn-ET' } }
|
||||
Formulate.install(Vue, {
|
||||
locales: {
|
||||
cn: {},
|
||||
em: {}
|
||||
}
|
||||
})
|
||||
expect(Vue.prototype.$formulate.getLocale(vm)).toBe('cn')
|
||||
})
|
||||
})
|
@ -1,8 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import { mount, shallowMount } from '@vue/test-utils'
|
||||
import flushPromises from 'flush-promises'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import FormSubmission from '../src/FormSubmission.js'
|
||||
import Formulate from '../../src/Formulate.js'
|
||||
import FormSubmission from '../../src/FormSubmission.js'
|
||||
import FormulateForm from '@/FormulateForm.vue'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import flushPromises from 'flush-promises'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import Formulate from '@/Formulate.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputBox from '@/inputs/FormulateInputBox.vue'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import flushPromises from 'flush-promises'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import Formulate from '../../src/Formulate.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputBox from '@/inputs/FormulateInputBox.vue'
|
||||
import FormulateInputGroup from '@/FormulateInputGroup.vue'
|
@ -1,6 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import Formulate from '../../src/Formulate.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputButton from '@/inputs/FormulateInputButton.vue'
|
||||
|
@ -1,8 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import flushPromises from 'flush-promises'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import FileUpload from '../src/FileUpload.js'
|
||||
import Formulate from '../../src/Formulate.js'
|
||||
import FileUpload from '../../src/FileUpload.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputFile from '@/inputs/FormulateInputFile.vue'
|
||||
|
||||
@ -20,6 +20,16 @@ describe('FormulateInputFile', () => {
|
||||
expect(wrapper.contains(FormulateInputFile)).toBe(true)
|
||||
})
|
||||
|
||||
it('forces an error-behavior live mode when upload-behavior is live and it has content', () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: { type: 'image', validation: 'mime:image/jpeg', value: [{ url: 'img.jpg' }] } })
|
||||
expect(wrapper.vm.showValidationErrors).toBe(true)
|
||||
})
|
||||
|
||||
it('wont show errors when upload-behavior is live and it is required but empty', () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: { type: 'image', validation: 'required|mime:image/jpeg' } })
|
||||
expect(wrapper.vm.showValidationErrors).toBe(false)
|
||||
})
|
||||
|
||||
/**
|
||||
* ===========================================================================
|
||||
* Currently there appears to be no way to properly mock upload data in
|
@ -1,8 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import FormulateInput from '../src/FormulateInput.vue'
|
||||
import FormulateInputSlider from '../src/inputs/FormulateInputSlider.vue'
|
||||
import Formulate from '@/Formulate.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputSlider from '@/inputs/FormulateInputSlider.vue'
|
||||
|
||||
Vue.use(Formulate)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import flushPromises from 'flush-promises'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import Formulate from '../../src/Formulate.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputText from '@/inputs/FormulateInputText.vue'
|
||||
import { doesNotReject } from 'assert';
|
@ -1,5 +1,5 @@
|
||||
import rules from '@/libs/rules'
|
||||
import FileUpload from '../src/FileUpload'
|
||||
import FileUpload from '../../src/FileUpload'
|
||||
|
||||
|
||||
/**
|
@ -1,4 +1,4 @@
|
||||
import { parseRules, regexForFormat, cloneDeep, isValueType, snakeToCamel } from '@/libs/utils'
|
||||
import { parseRules, parseLocale, regexForFormat, cloneDeep, isValueType, snakeToCamel } from '@/libs/utils'
|
||||
import rules from '@/libs/rules'
|
||||
import FileUpload from '@/FileUpload';
|
||||
|
||||
@ -143,3 +143,14 @@ describe('snakeToCamel', () => {
|
||||
expect(snakeToCamel('not-a-good-name')).toBe('not-a-good-name')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('parseLocale', () => {
|
||||
it('properly orders the options', () => {
|
||||
expect(parseLocale('en-US-VA')).toEqual(['en-US-VA', 'en-US', 'en'])
|
||||
})
|
||||
|
||||
it('properly parses a single option', () => {
|
||||
expect(parseLocale('en')).toEqual(['en'])
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue
Block a user