1
0
mirror of synced 2024-11-22 13:26:06 +03:00

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:
Justin Schroeder 2020-03-07 09:03:59 -05:00 committed by GitHub
parent adf8299a33
commit 34de4ba6dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1234 additions and 422 deletions

View File

@ -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: {
output: [
{
name: 'Formulate',
exports: 'default',
globals: {
'is-plain-object': 'isPlainObject',
'nanoid/non-secure': 'nanoid',
'is-url': 'isUrl'
'is-url': 'isUrl',
'@braid/vue-formulate-i18n': 'VueFormulateI18n'
}
},
}
],
external: ['nanoid/non-secure'],
plugins: [
commonjs(),

View File

@ -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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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 its 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"]}

File diff suppressed because one or more lines are too long

1011
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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"

View File

@ -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))) {

View File

@ -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>

View File

@ -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 => {

View File

@ -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
}

View File

@ -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
View 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).

View File

@ -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 isnt 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 doesnt end with a valid value.`
}
return `${value}” doesnt 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 doesnt start with a valid value.`
}
return `${value}” doesnt start with a valid value.`
},
/**
* Value is not a url.
*/
url: function ({ name }) {
return `Please include a valid url.`
}
}

View File

@ -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
View 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')
})
})

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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)

View File

@ -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';

View File

@ -1,5 +1,5 @@
import rules from '@/libs/rules'
import FileUpload from '../src/FileUpload'
import FileUpload from '../../src/FileUpload'
/**

View File

@ -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'])
})
})