diff --git a/packages/vue-vanilla/src/complex/OneOfRenderer.vue b/packages/vue-vanilla/src/complex/OneOfRenderer.vue index b676662bb9..4a0379f2b4 100644 --- a/packages/vue-vanilla/src/complex/OneOfRenderer.vue +++ b/packages/vue-vanilla/src/complex/OneOfRenderer.vue @@ -88,7 +88,6 @@ import { RendererProps, useJsonFormsOneOfControl, } from '@jsonforms/vue'; -import isEmpty from 'lodash/isEmpty'; import { defineComponent, inject, nextTick, ref } from 'vue'; import { useVanillaControl } from '../util'; import { ControlWrapper } from '../controls'; @@ -158,7 +157,7 @@ const controlRenderer = defineComponent({ const target = event.target as any; this.selectIndex = target.value; - if (this.control.enabled && !isEmpty(this.control.data)) { + if (this.control.enabled && this.control.data !== undefined) { this.showDialog(); nextTick(() => { this.newSelectedIndex = this.selectIndex; diff --git a/packages/vue-vanilla/tests/unit/complex/OneOfRenderer.spec.ts b/packages/vue-vanilla/tests/unit/complex/OneOfRenderer.spec.ts index d1bb27878a..afb7878dce 100644 --- a/packages/vue-vanilla/tests/unit/complex/OneOfRenderer.spec.ts +++ b/packages/vue-vanilla/tests/unit/complex/OneOfRenderer.spec.ts @@ -1,6 +1,42 @@ import { expect } from 'chai'; import { mountJsonForms } from '../util'; +const schemaWithVariousTypes = { + type: 'object', + properties: { + oneOfProp: { + title: 'Boolean or Array', + oneOf: [ + { + title: 'Boolean', + type: 'boolean', + }, + { + title: 'Array', + type: 'array', + items: { + type: 'string', + }, + }, + { + title: 'Object', + type: 'object', + properties: { + name: { + type: 'string', + }, + }, + }, + ], + }, + }, +}; + +const uischemaWithVariousTypes = { + type: 'Control', + scope: '#/properties/oneOfProp', +}; + const schema = { title: 'My Object', oneOf: [ @@ -34,6 +70,95 @@ const uischema = { }; describe('OneOfRenderer.vue', () => { + it('shows confirmation dialog when switching from boolean true to array', async () => { + const wrapper = mountJsonForms( + { oneOfProp: true }, + schemaWithVariousTypes, + uischemaWithVariousTypes + ); + const oneOfSelect = wrapper.find('select'); + const dialog = wrapper.find('dialog'); + + expect(oneOfSelect.element.value).to.equal('0'); + expect(dialog.element.open).to.be.false; + + await oneOfSelect.setValue('1'); + + expect(dialog.element.open).to.be.true; + }); + + it('shows confirmation dialog when switching from boolean false to array', async () => { + const wrapper = mountJsonForms( + { oneOfProp: false }, + schemaWithVariousTypes, + uischemaWithVariousTypes + ); + const oneOfSelect = wrapper.find('select'); + const dialog = wrapper.find('dialog'); + + expect(oneOfSelect.element.value).to.equal('0'); + expect(dialog.element.open).to.be.false; + + await oneOfSelect.setValue('1'); + + expect(dialog.element.open).to.be.true; + }); + + it('allows adding items after switching from boolean to array', async () => { + const wrapper = mountJsonForms( + { oneOfProp: true }, + schemaWithVariousTypes, + uischemaWithVariousTypes + ); + const oneOfSelect = wrapper.find('select'); + + await oneOfSelect.setValue('1'); + + const confirmButton = wrapper.find('dialog button:last-child'); + await confirmButton.trigger('click'); + + const addButton = wrapper.find('.array-list-add'); + await addButton.trigger('click'); + + expect(wrapper.vm.data).to.deep.equal({ oneOfProp: [''] }); + }); + + it('does not show confirmation dialog when switching from undefined to array', async () => { + const wrapper = mountJsonForms( + {}, + schemaWithVariousTypes, + uischemaWithVariousTypes + ); + const oneOfSelect = wrapper.find('select'); + const dialog = wrapper.find('dialog'); + + await oneOfSelect.setValue('1'); + + expect(dialog.element.open).to.be.false; + expect(wrapper.vm.data).to.deep.equal({}); + }); + + it('allows adding items after switching from object to array', async () => { + const wrapper = mountJsonForms( + { oneOfProp: { name: 'test' } }, + schemaWithVariousTypes, + uischemaWithVariousTypes + ); + const oneOfSelect = wrapper.find('select'); + + expect(oneOfSelect.element.value).to.equal('2'); + + await oneOfSelect.setValue('1'); + + const confirmButton = wrapper.find('dialog button:last-child'); + await confirmButton.trigger('click'); + + const addButton = wrapper.find('.array-list-add'); + await addButton.trigger('click'); + + expect(wrapper.vm.data).to.deep.equal({ oneOfProp: [''] }); + }); + it('render has a class', () => { const wrapper = mountJsonForms({ variant: 'b', b: 'b' }, schema, uischema); expect(wrapper.find('div.one-of').exists()).to.be.true; diff --git a/packages/vue-vanilla/tests/unit/setup.ts b/packages/vue-vanilla/tests/unit/setup.ts new file mode 100644 index 0000000000..be8bced710 --- /dev/null +++ b/packages/vue-vanilla/tests/unit/setup.ts @@ -0,0 +1,14 @@ +// JSDOM doesn't support HTMLDialogElement.showModal() and close(), so we need to polyfill/mock them +// Also see https://github.com/jsdom/jsdom/issues/3294 +if (typeof HTMLDialogElement !== 'undefined') { + HTMLDialogElement.prototype.showModal = + HTMLDialogElement.prototype.showModal || + function (this: HTMLDialogElement) { + this.setAttribute('open', ''); + }; + HTMLDialogElement.prototype.close = + HTMLDialogElement.prototype.close || + function (this: HTMLDialogElement) { + this.removeAttribute('open'); + }; +} diff --git a/packages/vue-vanilla/tests/unit/util/index.ts b/packages/vue-vanilla/tests/unit/util/index.ts index bbebd88eb4..1eed8b4a5e 100644 --- a/packages/vue-vanilla/tests/unit/util/index.ts +++ b/packages/vue-vanilla/tests/unit/util/index.ts @@ -1 +1,2 @@ +import '../setup'; export * from './util';