1
0
mirror of synced 2024-11-22 05:16:05 +03:00

refactor: Merge utility moved to a separated file

This commit is contained in:
Zaytsev Kirill 2020-10-14 08:43:17 +03:00
parent c5bb8076e6
commit ec1035a9a0
6 changed files with 131 additions and 126 deletions

View File

@ -8,6 +8,7 @@ import FileUpload from '@/FileUpload'
import RuleValidationMessages from '@/RuleValidationMessages'
import { arrayify, has } from '@/libs/utils'
import fauxUploader from '@/libs/faux-uploader'
import merge from '@/utils/merge'
import FormularioForm from '@/FormularioForm.vue'
import FormularioInput from '@/FormularioInput.vue'
@ -113,46 +114,12 @@ export default class Formulario {
*/
extend (extendWith: FormularioOptions) {
if (typeof extendWith === 'object') {
this.options = this.merge(this.options as FormularioOptions, extendWith)
this.options = merge(this.options as FormularioOptions, extendWith)
return this
}
throw new Error(`VueFormulario extend() should be passed an object (was ${typeof extendWith})`)
}
/**
* Create a new object by copying properties of base and mergeWith.
* Note: arrays don't overwrite - they push
*
* @param {Object} base
* @param {Object} mergeWith
* @param {boolean} concatArrays
*/
merge (base: ObjectType, mergeWith: ObjectType, concatArrays: boolean = true) {
const merged: ObjectType = {}
for (const key in base) {
if (has(mergeWith, key)) {
if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) {
merged[key] = this.merge(base[key], mergeWith[key], concatArrays)
} else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) {
merged[key] = base[key].concat(mergeWith[key])
} else {
merged[key] = mergeWith[key]
}
} else {
merged[key] = base[key]
}
}
for (const prop in mergeWith) {
if (!has(merged, prop)) {
merged[prop] = mergeWith[prop]
}
}
return merged
}
/**
* Determine what "class" of input this element is given the "type".
*/

View File

@ -20,7 +20,7 @@ import { arrayify, getNested, has, setNested, shallowEqualObjects } from '@/libs
import { ObjectType } from '@/common.types'
import Registry from '@/libs/registry'
import FormSubmission from '@/FormSubmission'
import FormularioInput from '@/FormularioInput'
import FormularioInput from '@/FormularioInput.vue'
@Component
export default class FormularioForm extends Vue {

37
src/utils/merge.ts Normal file
View File

@ -0,0 +1,37 @@
import isPlainObject from 'is-plain-object'
import { ObjectType } from '@/common.types.ts'
import { has } from '@/libs/utils.ts'
/**
* Create a new object by copying properties of base and mergeWith.
* Note: arrays don't overwrite - they push
*
* @param {Object} base
* @param {Object} mergeWith
* @param {boolean} concatArrays
*/
export default function merge (base: ObjectType, mergeWith: ObjectType, concatArrays: boolean = true) {
const merged: ObjectType = {}
for (const key in base) {
if (has(mergeWith, key)) {
if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) {
merged[key] = merge(base[key], mergeWith[key], concatArrays)
} else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) {
merged[key] = base[key].concat(mergeWith[key])
} else {
merged[key] = mergeWith[key]
}
} else {
merged[key] = base[key]
}
}
for (const prop in mergeWith) {
if (!has(merged, prop)) {
merged[prop] = mergeWith[prop]
}
}
return merged
}

View File

@ -1,65 +1,6 @@
import Formulario from '@/index.ts'
describe('Formulario', () => {
it('can merge simple object', () => {
let a = {
optionA: true,
optionB: '1234'
}
let b = {
optionA: false
}
expect(Formulario.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(Formulario.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(Formulario.merge(a, b)).toEqual({
optionA: true,
optionC: {
first: '1234',
third: {
a: 'b'
},
second: '789'
},
optionB: '567'
})
})
it('installs on vue instance', () => {
const components = [
'FormularioForm',

View File

@ -8,12 +8,12 @@ import FormularioGrouping from '@/FormularioGrouping.vue'
Vue.use(Formulario)
describe('FormularioGrouping', () => {
it('grouped fields to be setted', async () => {
it('Grouped fields to be set', async () => {
const wrapper = mount(FormularioForm, {
propsData: { name: 'form', },
propsData: { name: 'form' },
slots: {
default: `
<FormularioGrouping name="sub">
<FormularioGrouping name="group">
<FormularioInput name="text" v-slot="{ context }">
<input type="text" v-model="context.model">
</FormularioInput>
@ -25,38 +25,40 @@ describe('FormularioGrouping', () => {
wrapper.find('input[type="text"]').setValue('test')
const submission = await wrapper.vm.formSubmitted()
expect(submission).toEqual({sub: {text: 'test'}})
expect(submission).toEqual({ group: { text: 'test' } })
})
it('grouped fields to be getted', async () => {
it('Grouped fields to be got', async () => {
const wrapper = mount(FormularioForm, {
propsData: { name: 'form', formularioValue: { sub: {text: 'initial value'}, text: 'simple text' } },
propsData: {
name: 'form',
formularioValue: {
group: { text: 'Group text' },
text: 'Text',
}
},
slots: {
default: `
<FormularioGrouping name="sub">
<FormularioInput name="text" v-slot="vSlot">
<input type="text" v-model="vSlot.context.model">
<FormularioGrouping name="group">
<FormularioInput name="text" v-slot="{ context }">
<input type="text" v-model="context.model">
</FormularioInput>
</FormularioGrouping>
`
}
})
expect(wrapper.find('input[type="text"]').element.value).toBe('initial value')
expect(wrapper.find('input[type="text"]').element.value).toBe('Group text')
})
it('data reactive with grouped fields', async () => {
it('Data reactive with grouped fields', async () => {
const wrapper = mount({
data () {
return {
formValues: {}
}
},
data: () => ({ values: {} }),
template: `
<FormularioForm name="form" v-model="formValues">
<FormularioGrouping name="sub">
<FormularioInput name="text" v-slot="vSlot">
<input type="text" v-model="vSlot.context.model">
<span>{{ formValues.sub.text }}</span>
<FormularioForm name="form" v-model="values">
<FormularioGrouping name="group">
<FormularioInput name="text" v-slot="{ context }">
<input type="text" v-model="context.model">
<span>{{ values.group.text }}</span>
</FormularioInput>
</FormularioGrouping>
</FormularioForm>
@ -68,18 +70,20 @@ describe('FormularioGrouping', () => {
expect(wrapper.find('span').text()).toBe('test')
})
it('errors are setted for grouped fields', async () => {
it('Errors are set for grouped fields', async () => {
const wrapper = mount({
data () {
return {
formValues: {}
}
},
data: () => ({ values: {} }),
template: `
<FormularioForm name="form" v-model="formValues" :errors="{'sub.text': 'Test error'}">
<FormularioGrouping name="sub">
<FormularioInput name="text" v-slot="vSlot">
<span v-for="error in vSlot.context.allErrors">{{ error }}</span>
<FormularioForm
v-model="values"
:errors="{'group.text': 'Test error'}"
name="form"
>
<FormularioGrouping name="group">
<FormularioInput name="text" v-slot="{ context }">
<span v-for="error in context.allErrors">
{{ error }}
</span>
</FormularioInput>
</FormularioGrouping>
</FormularioForm>

56
test/unit/merge.test.js Normal file
View File

@ -0,0 +1,56 @@
import merge from '@/utils/merge.ts'
describe('merge', () => {
it('Can merge simple object', () => {
expect(merge({
optionA: true,
optionB: '1234',
}, {
optionA: false,
})).toEqual({
optionA: false,
optionB: '1234',
})
})
it('Can add to simple array', () => {
expect(merge({
optionA: true,
optionB: ['first', 'second']
}, {
optionB: ['third']
}, true)).toEqual({
optionA: true,
optionB: ['first', 'second', 'third']
})
})
it('Can merge recursively', () => {
expect(merge({
optionA: true,
optionC: {
first: '123',
third: {
a: 'b',
},
},
optionB: '1234',
}, {
optionB: '567',
optionC: {
first: '1234',
second: '789',
}
})).toEqual({
optionA: true,
optionC: {
first: '1234',
third: {
a: 'b',
},
second: '789',
},
optionB: '567',
})
})
})