Adds initial grouping tests and first functional, repeatable, modelable grouped fields
This commit is contained in:
parent
430f27f24c
commit
8e3ca76685
@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<div class="specimens specimens--group">
|
||||
<FormulateForm
|
||||
v-model="formResult"
|
||||
v-model="formData"
|
||||
@submit="save"
|
||||
>
|
||||
<FormulateInput
|
||||
v-model="users"
|
||||
name="users"
|
||||
label="Invite some new users"
|
||||
type="group"
|
||||
placeholder="users"
|
||||
help="Fields can be grouped"
|
||||
:repeatable="true"
|
||||
>
|
||||
<FormulateInput
|
||||
label="First and last name"
|
||||
@ -18,6 +20,7 @@
|
||||
placeholder="User’s name"
|
||||
/>
|
||||
<FormulateInput
|
||||
v-model="email"
|
||||
name="email"
|
||||
label="Email address"
|
||||
type="email"
|
||||
@ -30,9 +33,11 @@
|
||||
/>
|
||||
</FormulateForm>
|
||||
<span>Form Values</span>
|
||||
<pre>{{ formResult }}</pre>
|
||||
<pre>{{ formData }}</pre>
|
||||
<span>Save Values</span>
|
||||
<pre>{{ saveValues }}</pre>
|
||||
<pre>{{ email }}</pre>
|
||||
<pre>{{ users }}</pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -40,7 +45,13 @@
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
formResult: null,
|
||||
formData: {
|
||||
},
|
||||
users: [
|
||||
{ name: 'Justin' },
|
||||
{ name: 'Bob' }
|
||||
],
|
||||
email: 'justin@wearebraid.com',
|
||||
saveValues: null
|
||||
}
|
||||
},
|
||||
|
@ -26,11 +26,11 @@ export default class FormSubmission {
|
||||
values () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const pending = []
|
||||
const values = cloneDeep(this.form.internalFormModelProxy)
|
||||
const values = cloneDeep(this.form.proxy)
|
||||
for (const key in values) {
|
||||
if (typeof this.form.internalFormModelProxy[key] === 'object' && this.form.internalFormModelProxy[key] instanceof FileUpload) {
|
||||
if (typeof this.form.proxy[key] === 'object' && this.form.proxy[key] instanceof FileUpload) {
|
||||
pending.push(
|
||||
this.form.internalFormModelProxy[key].upload().then(data => Object.assign(values, { [key]: data }))
|
||||
this.form.proxy[key].upload().then(data => Object.assign(values, { [key]: data }))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -13,15 +13,13 @@
|
||||
|
||||
<script>
|
||||
import { shallowEqualObjects, arrayify, has } from './libs/utils'
|
||||
import Registry from './libs/registry'
|
||||
import useRegistry, { useRegistryComputed, useRegistryMethods, useRegistryProviders } from './libs/registry'
|
||||
import FormSubmission from './FormSubmission'
|
||||
|
||||
export default {
|
||||
provide () {
|
||||
return {
|
||||
formulateFormSetter: this.setFieldValue,
|
||||
formulateFormRegister: this.register,
|
||||
getFormValues: this.getFormValues,
|
||||
...useRegistryProviders(this),
|
||||
observeErrors: this.addErrorObserver,
|
||||
removeErrorObserver: this.removeErrorObserver,
|
||||
formulateFieldValidation: this.formulateFieldValidation
|
||||
@ -56,8 +54,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
registry: new Registry(),
|
||||
internalFormModelProxy: {},
|
||||
...useRegistry(this),
|
||||
formShouldShowErrors: false,
|
||||
errorObservers: [],
|
||||
namedErrors: [],
|
||||
@ -65,43 +62,12 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* @todo in 2.3.0 this will expand and be extracted to a separate module to
|
||||
* support better scoped slot interoperability.
|
||||
*/
|
||||
...useRegistryComputed(),
|
||||
formContext () {
|
||||
return {
|
||||
errors: this.mergedFormErrors
|
||||
}
|
||||
},
|
||||
hasInitialValue () {
|
||||
return (
|
||||
(this.formulateValue && typeof this.formulateValue === 'object') ||
|
||||
(this.values && typeof this.values === 'object')
|
||||
)
|
||||
},
|
||||
isVmodeled () {
|
||||
return !!(this.$options.propsData.hasOwnProperty('formulateValue') &&
|
||||
this._events &&
|
||||
Array.isArray(this._events.input) &&
|
||||
this._events.input.length)
|
||||
},
|
||||
initialValues () {
|
||||
if (
|
||||
has(this.$options.propsData, 'formulateValue') &&
|
||||
typeof this.formulateValue === 'object'
|
||||
) {
|
||||
// If there is a v-model on the form, use those values as first priority
|
||||
return Object.assign({}, this.formulateValue) // @todo - use a deep clone to detach reference types
|
||||
} else if (
|
||||
has(this.$options.propsData, 'values') &&
|
||||
typeof this.values === 'object'
|
||||
) {
|
||||
// If there are values, use them as secondary priority
|
||||
return Object.assign({}, this.values)
|
||||
}
|
||||
return {}
|
||||
},
|
||||
classes () {
|
||||
const classes = { 'formulate-form': true }
|
||||
if (this.name) {
|
||||
@ -137,11 +103,11 @@ export default {
|
||||
) {
|
||||
for (const field in newValue) {
|
||||
if (this.registry.has(field) &&
|
||||
!shallowEqualObjects(newValue[field], this.internalFormModelProxy[field]) &&
|
||||
!shallowEqualObjects(newValue[field], this.proxy[field]) &&
|
||||
!shallowEqualObjects(newValue[field], this.registry.get(field).internalModelProxy[field])
|
||||
) {
|
||||
this.setFieldValue(field, newValue[field])
|
||||
this.registry[field].context.model = newValue[field]
|
||||
this.registry.get(field).context.model = newValue[field]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,11 +136,7 @@ export default {
|
||||
this.$formulate.deregister(this)
|
||||
},
|
||||
methods: {
|
||||
applyInitialValues () {
|
||||
if (this.hasInitialValue) {
|
||||
this.internalFormModelProxy = this.initialValues
|
||||
}
|
||||
},
|
||||
...useRegistryMethods(),
|
||||
applyErrors ({ formErrors, inputErrors }) {
|
||||
// given an object of errors, apply them to this form
|
||||
this.namedErrors = formErrors
|
||||
@ -193,36 +155,6 @@ export default {
|
||||
removeErrorObserver (observer) {
|
||||
this.errorObservers = this.errorObservers.filter(obs => obs.callback !== observer)
|
||||
},
|
||||
setFieldValue (field, value) {
|
||||
Object.assign(this.internalFormModelProxy, { [field]: value })
|
||||
this.$emit('input', Object.assign({}, this.internalFormModelProxy))
|
||||
},
|
||||
register (field, component) {
|
||||
// Don't re-register fields... @todo come up with another way of handling this that doesn't break multi option
|
||||
if (this.registry.has(field)) {
|
||||
return false
|
||||
}
|
||||
this.registry.add(field, component)
|
||||
const hasVModelValue = has(component.$options.propsData, 'formulateValue')
|
||||
const hasValue = has(component.$options.propsData, 'value')
|
||||
if (
|
||||
!component.context.isSubField() &&
|
||||
!hasVModelValue &&
|
||||
this.hasInitialValue &&
|
||||
this.initialValues[field]
|
||||
) {
|
||||
// In the case that the form is carrying an initial value and the
|
||||
// element is not, set it directly.
|
||||
component.context.model = this.initialValues[field]
|
||||
} else if (
|
||||
(hasVModelValue || hasValue) &&
|
||||
!shallowEqualObjects(component.internalModelProxy, this.initialValues[field])
|
||||
) {
|
||||
// In this case, the field is v-modeled or has an initial value and the
|
||||
// form has no value or a different value, so use the field value
|
||||
this.setFieldValue(field, component.internalModelProxy)
|
||||
}
|
||||
},
|
||||
registerErrorComponent (component) {
|
||||
if (!this.errorComponents.includes(component)) {
|
||||
this.errorComponents.push(component)
|
||||
@ -248,9 +180,6 @@ export default {
|
||||
input.formShouldShowErrors = true
|
||||
})
|
||||
},
|
||||
getFormValues () {
|
||||
return this.internalFormModelProxy
|
||||
},
|
||||
formulateFieldValidation (errorObject) {
|
||||
this.$emit('validation', errorObject)
|
||||
},
|
||||
|
@ -26,7 +26,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'FormulateGrouping',
|
||||
props: {
|
||||
context: {
|
||||
type: Object,
|
||||
@ -35,8 +37,6 @@ export default {
|
||||
},
|
||||
provide () {
|
||||
return {
|
||||
formulateFormSetter: this.setFieldValue,
|
||||
formulateFormRegister: this.register,
|
||||
isSubField: () => true
|
||||
}
|
||||
},
|
||||
@ -64,9 +64,6 @@ export default {
|
||||
{ [field]: value }
|
||||
))
|
||||
this.context.model = values
|
||||
},
|
||||
register (field, component) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,9 +74,9 @@ export default {
|
||||
name: 'FormulateInput',
|
||||
inheritAttrs: false,
|
||||
inject: {
|
||||
formulateFormSetter: { default: undefined },
|
||||
formulateSetter: { default: undefined },
|
||||
formulateFieldValidation: { default: () => () => ({}) },
|
||||
formulateFormRegister: { default: undefined },
|
||||
formulateRegister: { default: undefined },
|
||||
getFormValues: { default: () => () => ({}) },
|
||||
observeErrors: { default: undefined },
|
||||
removeErrorObserver: { default: undefined },
|
||||
@ -141,7 +141,7 @@ export default {
|
||||
},
|
||||
repeatable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: false
|
||||
},
|
||||
validation: {
|
||||
type: [String, Boolean, Array],
|
||||
@ -270,8 +270,8 @@ export default {
|
||||
},
|
||||
created () {
|
||||
this.applyInitialValue()
|
||||
if (this.formulateFormRegister && typeof this.formulateFormRegister === 'function') {
|
||||
this.formulateFormRegister(this.nameOrFallback, this)
|
||||
if (this.formulateRegister && typeof this.formulateRegister === 'function') {
|
||||
this.formulateRegister(this.nameOrFallback, this)
|
||||
}
|
||||
if (!this.disableErrors && typeof this.observeErrors === 'function') {
|
||||
this.observeErrors({ callback: this.setErrors, type: 'input', field: this.nameOrFallback })
|
||||
|
@ -289,7 +289,7 @@ function modelSetter (value) {
|
||||
this.internalModelProxy = value
|
||||
}
|
||||
this.$emit('input', value)
|
||||
if (this.context.name && typeof this.formulateFormSetter === 'function') {
|
||||
this.formulateFormSetter(this.context.name, value)
|
||||
if (this.context.name && typeof this.formulateSetter === 'function') {
|
||||
this.formulateSetter(this.context.name, value)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { shallowEqualObjects, has } from './utils'
|
||||
|
||||
/**
|
||||
* Component registry with inherent depth to handle complex nesting. This is
|
||||
* important for features such as grouped fields.
|
||||
@ -5,9 +7,11 @@
|
||||
class Registry {
|
||||
/**
|
||||
* Create a new registry of components.
|
||||
* @param {vm} ctx The host vm context of the registry.
|
||||
*/
|
||||
constructor () {
|
||||
constructor (ctx) {
|
||||
this.registry = new Map()
|
||||
this.ctx = ctx
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,6 +41,14 @@ class Registry {
|
||||
return this.registry.has(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a particular registry value.
|
||||
* @param {string} key
|
||||
*/
|
||||
get (key) {
|
||||
return this.registry.get(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Map over the registry (recursively).
|
||||
* @param {function} callback
|
||||
@ -54,6 +66,36 @@ class Registry {
|
||||
return Array.from(this.registry.keys())
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully register a component.
|
||||
* @param {string} field name of the field.
|
||||
* @param {vm} component the actual component instance.
|
||||
*/
|
||||
register (field, component) {
|
||||
if (this.registry.has(field)) {
|
||||
return false
|
||||
}
|
||||
this.registry.set(field, component)
|
||||
const hasVModelValue = has(component.$options.propsData, 'formulateValue')
|
||||
const hasValue = has(component.$options.propsData, 'value')
|
||||
if (
|
||||
!hasVModelValue &&
|
||||
this.ctx.hasInitialValue &&
|
||||
this.ctx.initialValues[field]
|
||||
) {
|
||||
// In the case that the form is carrying an initial value and the
|
||||
// element is not, set it directly.
|
||||
component.context.model = this.ctx.initialValues[field]
|
||||
} else if (
|
||||
(hasVModelValue || hasValue) &&
|
||||
!shallowEqualObjects(component.internalModelProxy, this.ctx.initialValues[field])
|
||||
) {
|
||||
// In this case, the field is v-modeled or has an initial value and the
|
||||
// form has no value or a different value, so use the field value
|
||||
this.ctx.setFieldValue(field, component.internalModelProxy)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce the registry.
|
||||
* @param {function} callback
|
||||
@ -64,6 +106,99 @@ class Registry {
|
||||
})
|
||||
return accumulator
|
||||
}
|
||||
|
||||
/**
|
||||
* Data props to expose.
|
||||
*/
|
||||
dataProps () {
|
||||
return {
|
||||
proxy: {},
|
||||
registry: this,
|
||||
register: this.register.bind(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Registry
|
||||
/**
|
||||
* The context component.
|
||||
* @param {component} contextComponent
|
||||
*/
|
||||
export default function useRegistry (contextComponent) {
|
||||
const registry = new Registry(contextComponent)
|
||||
return registry.dataProps()
|
||||
}
|
||||
|
||||
/**
|
||||
* Computed properties related to the registry.
|
||||
*/
|
||||
export function useRegistryComputed () {
|
||||
return {
|
||||
hasInitialValue () {
|
||||
return (
|
||||
(this.formulateValue && typeof this.formulateValue === 'object') ||
|
||||
(this.values && typeof this.values === 'object') ||
|
||||
(this.isGrouping && typeof this.context.model[this.index] === 'object')
|
||||
)
|
||||
},
|
||||
isVmodeled () {
|
||||
return !!(this.$options.propsData.hasOwnProperty('formulateValue') &&
|
||||
this._events &&
|
||||
Array.isArray(this._events.input) &&
|
||||
this._events.input.length)
|
||||
},
|
||||
initialValues () {
|
||||
if (
|
||||
has(this.$options.propsData, 'formulateValue') &&
|
||||
typeof this.formulateValue === 'object'
|
||||
) {
|
||||
// If there is a v-model on the form/group, use those values as first priority
|
||||
return Object.assign({}, this.formulateValue) // @todo - use a deep clone to detach reference types
|
||||
} else if (
|
||||
has(this.$options.propsData, 'values') &&
|
||||
typeof this.values === 'object'
|
||||
) {
|
||||
// If there are values, use them as secondary priority
|
||||
return Object.assign({}, this.values)
|
||||
} else if (
|
||||
this.isGrouping && typeof this.context.model[this.index] === 'object'
|
||||
) {
|
||||
return this.context.model[this.index]
|
||||
}
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watchers used in the registry.
|
||||
*/
|
||||
export function useRegistryMethods (without = []) {
|
||||
const methods = {
|
||||
applyInitialValues () {
|
||||
if (this.hasInitialValue) {
|
||||
this.proxy = this.initialValues
|
||||
}
|
||||
},
|
||||
setFieldValue (field, value) {
|
||||
Object.assign(this.proxy, { [field]: value })
|
||||
this.$emit('input', Object.assign({}, this.proxy))
|
||||
},
|
||||
getFormValues () {
|
||||
return this.proxy
|
||||
}
|
||||
}
|
||||
return Object.keys(methods).reduce((withMethods, key) => {
|
||||
return without.includes(key) ? withMethods : { ...withMethods, [key]: methods[key] }
|
||||
}, {})
|
||||
}
|
||||
|
||||
/**
|
||||
* Providers related to the registry.
|
||||
*/
|
||||
export function useRegistryProviders (ctx) {
|
||||
return {
|
||||
formulateSetter: ctx.setFieldValue,
|
||||
formulateRegister: ctx.register,
|
||||
getFormValues: ctx.getFormValues
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import useRegistry, { useRegistryComputed, useRegistryMethods, useRegistryProviders } from '../libs/registry'
|
||||
|
||||
export default {
|
||||
provide () {
|
||||
return {
|
||||
formulateFormSetter: (field, value) => this.setFieldValue(this.index, field, value)
|
||||
...useRegistryProviders(this),
|
||||
formulateSetter: (field, value) => this.setFieldValue(this.index, field, value)
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@ -28,6 +31,18 @@ export default {
|
||||
type: Function,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
...useRegistry(this),
|
||||
isGrouping: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...useRegistryComputed()
|
||||
},
|
||||
methods: {
|
||||
...useRegistryMethods(['setFieldValue'])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -171,6 +171,26 @@ describe('FormulateForm', () => {
|
||||
expect(wrapper.emitted().input[wrapper.emitted().input.length - 1]).toEqual([{ testinput: 'override-data' }])
|
||||
})
|
||||
|
||||
it('updates an inputs value when the form v-model is modified', async () => {
|
||||
const wrapper = mount({
|
||||
data () {
|
||||
return {
|
||||
formValues: {
|
||||
testinput: 'abcd',
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<FormulateForm v-model="formValues">
|
||||
<FormulateInput type="text" name="testinput" />
|
||||
</FormulateForm>
|
||||
`
|
||||
})
|
||||
await flushPromises()
|
||||
wrapper.vm.formValues = { testinput: '1234' }
|
||||
await flushPromises()
|
||||
expect(wrapper.find('input[type="text"]').element.value).toBe('1234')
|
||||
})
|
||||
|
||||
it('emits an instance of FormSubmission', async () => {
|
||||
const wrapper = mount(FormulateForm, {
|
||||
@ -205,7 +225,6 @@ describe('FormulateForm', () => {
|
||||
slots: { default: `<FormulateInput type="text" name="name" validation="required" /><FormulateInput type="checkbox" name="candy" />` }
|
||||
})
|
||||
await flushPromises()
|
||||
// expect(wrapper.vm.internalFormModelProxy).toEqual({ name: 'Dave Barnett', candy: true })
|
||||
expect(wrapper.find('input[type="text"]').element.value).toBe('Dave Barnett')
|
||||
expect(wrapper.find('input[type="checkbox"]').element.checked).toBe(true)
|
||||
})
|
||||
|
@ -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 '@/Formulate.js'
|
||||
import FileUpload from '@/FileUpload.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputFile from '@/inputs/FormulateInputFile.vue'
|
||||
|
||||
|
101
test/unit/FormulateInputGroup.test.js
Normal file
101
test/unit/FormulateInputGroup.test.js
Normal file
@ -0,0 +1,101 @@
|
||||
import Vue from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import flushPromises from 'flush-promises'
|
||||
import Formulate from '@/Formulate.js'
|
||||
import FileUpload from '@/FileUpload.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
|
||||
Vue.use(Formulate)
|
||||
|
||||
describe('FormulateInputGroup', () => {
|
||||
it('allows nested fields to be sub-rendered', async () => {
|
||||
const wrapper = mount(FormulateInput, {
|
||||
propsData: { type: 'group' },
|
||||
slots: {
|
||||
default: '<FormulateInput type="text" />'
|
||||
}
|
||||
})
|
||||
expect(wrapper.findAll('.formulate-input-grouping input[type="text"]').length).toBe(1)
|
||||
})
|
||||
|
||||
it('registers sub-fields with grouping', async () => {
|
||||
const wrapper = mount(FormulateInput, {
|
||||
propsData: { type: 'group' },
|
||||
slots: {
|
||||
default: '<FormulateInput type="text" />'
|
||||
}
|
||||
})
|
||||
expect(wrapper.findAll('.formulate-input-grouping input[type="text"]').length).toBe(1)
|
||||
})
|
||||
|
||||
it('is not repeatable by default', async () => {
|
||||
const wrapper = mount(FormulateInput, {
|
||||
propsData: { type: 'group' },
|
||||
slots: {
|
||||
default: '<FormulateInput type="text" />'
|
||||
}
|
||||
})
|
||||
expect(wrapper.findAll('.formulate-input-group-add-more').length).toBe(0)
|
||||
})
|
||||
|
||||
it('adds an add more button when repeatable', async () => {
|
||||
const wrapper = mount(FormulateInput, {
|
||||
propsData: { type: 'group', repeatable: true },
|
||||
slots: {
|
||||
default: '<FormulateInput type="text" />'
|
||||
}
|
||||
})
|
||||
expect(wrapper.findAll('.formulate-input-group-add-more').length).toBe(1)
|
||||
})
|
||||
|
||||
it('repeats the default slot when adding more', async () => {
|
||||
const wrapper = mount(FormulateInput, {
|
||||
propsData: { type: 'group', repeatable: true },
|
||||
slots: {
|
||||
default: '<div class="wrap"><FormulateInput type="text" /></div>'
|
||||
}
|
||||
})
|
||||
wrapper.find('.formulate-input-group-add-more button').trigger('click')
|
||||
await flushPromises();
|
||||
expect(wrapper.findAll('.wrap').length).toBe(2)
|
||||
})
|
||||
|
||||
it('re-hydrates a repeatable field', async () => {
|
||||
const wrapper = mount(FormulateInput, {
|
||||
propsData: { type: 'group', repeatable: true, value: [{email: 'jon@example.com'}, {email:'jane@example.com'}] },
|
||||
slots: {
|
||||
default: '<div class="wrap"><FormulateInput type="text" name="email" /></div>'
|
||||
}
|
||||
})
|
||||
await flushPromises()
|
||||
const fields = wrapper.findAll('input[type="text"]')
|
||||
expect(fields.length).toBe(2)
|
||||
expect(fields.at(0).element.value).toBe('jon@example.com')
|
||||
expect(fields.at(1).element.value).toBe('jane@example.com')
|
||||
})
|
||||
|
||||
it('v-modeling a subfield changes all values', async () => {
|
||||
const wrapper = mount({
|
||||
template: `
|
||||
<FormulateInput
|
||||
v-model="users"
|
||||
type="group"
|
||||
>
|
||||
<FormulateInput type="text" v-model="email" name="email" />
|
||||
<FormulateInput type="text" name="name" />
|
||||
</FormulateInput>
|
||||
`,
|
||||
data () {
|
||||
return {
|
||||
users: [{email: 'jon@example.com'}, {email:'jane@example.com'}],
|
||||
email: 'jim@example.com'
|
||||
}
|
||||
}
|
||||
})
|
||||
await flushPromises()
|
||||
const fields = wrapper.findAll('input[type="text"]')
|
||||
expect(fields.length).toBe(4)
|
||||
expect(fields.at(0).element.value).toBe('jim@example.com')
|
||||
expect(fields.at(2).element.value).toBe('jim@example.com')
|
||||
})
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user