/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kie.workbench.common.forms.editor.client.editor; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.gwtmockito.GwtMock; import com.google.gwtmockito.GwtMockitoTestRunner; import org.guvnor.common.services.shared.metadata.model.Overview; import org.jboss.errai.ioc.client.api.ManagedInstance; import org.jboss.errai.ioc.client.container.SyncBeanDef; import org.jboss.errai.ioc.client.container.SyncBeanManager; import org.jboss.errai.ui.client.local.spi.TranslationService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.kie.workbench.common.forms.dynamic.client.rendering.FieldLayoutComponent; import org.kie.workbench.common.forms.editor.client.editor.events.FormEditorContextResponse; import org.kie.workbench.common.forms.editor.client.editor.rendering.EditorFieldLayoutComponent; import org.kie.workbench.common.forms.editor.client.resources.images.FormEditorImageResources; import org.kie.workbench.common.forms.editor.client.type.FormDefinitionResourceType; import org.kie.workbench.common.forms.editor.model.FormModelerContent; import org.kie.workbench.common.forms.editor.service.shared.FormEditorService; import org.kie.workbench.common.forms.fields.shared.fieldTypes.basic.checkBox.definition.CheckBoxFieldDefinition; import org.kie.workbench.common.forms.fields.shared.fieldTypes.basic.datePicker.definition.DatePickerFieldDefinition; import org.kie.workbench.common.forms.fields.shared.fieldTypes.basic.textArea.definition.TextAreaFieldDefinition; import org.kie.workbench.common.forms.fields.shared.fieldTypes.basic.textBox.definition.TextBoxFieldDefinition; import org.kie.workbench.common.forms.fields.test.TestFieldManager; import org.kie.workbench.common.forms.model.FieldDefinition; import org.kie.workbench.common.forms.model.FormDefinition; import org.kie.workbench.common.forms.model.FormModel; import org.kie.workbench.common.widgets.metadata.client.KieEditorWrapperView; import org.kie.workbench.common.widgets.metadata.client.widget.OverviewWidgetPresenter; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.uberfire.backend.vfs.ObservablePath; import org.uberfire.ext.editor.commons.client.history.VersionRecordManager; import org.uberfire.ext.layout.editor.api.editor.LayoutComponent; import org.uberfire.ext.layout.editor.client.api.ComponentDropEvent; import org.uberfire.ext.layout.editor.client.api.ComponentRemovedEvent; import org.uberfire.ext.layout.editor.client.api.LayoutEditor; import org.uberfire.ext.plugin.client.perspective.editor.layout.editor.HTMLLayoutDragComponent; import org.uberfire.ext.widgets.common.client.common.BusyIndicatorView; import org.uberfire.mocks.CallerMock; import org.uberfire.mocks.EventSourceMock; import org.uberfire.mvp.PlaceRequest; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @RunWith(GwtMockitoTestRunner.class) public class FormEditorPresenterTest { private List<FieldDefinition> employeeFields; private FormEditorHelper editorContext; @GwtMock private FormEditorImageResources formEditorImageResources; @Mock VersionRecordManager versionRecordManager; @Mock private FormEditorPresenter.FormEditorView view; @Mock private TranslationService translationService; @GwtMock private KieEditorWrapperView kieView; @GwtMock private ObservablePath path; @GwtMock private FormDefinitionResourceType formDefinitionResourceType; @Mock private LayoutEditor layoutEditor; @Mock private HTMLLayoutDragComponent htmlLayoutDragComponent; @Mock private ManagedInstance<EditorFieldLayoutComponent> editorFieldLayoutComponents; @Mock protected EventSourceMock<FormEditorContextResponse> eventMock; @Mock protected FormEditorService formEditorService; private CallerMock<FormEditorService> editorServiceCallerMock; private FormEditorPresenter presenter; private FormModelerContent content; @Before public void setUp() throws Exception { initFields(); } protected void loadContent() { when(formDefinitionResourceType.getSuffix()).thenReturn("form.frm"); when(formDefinitionResourceType.accept(path)).thenReturn(true); when(editorFieldLayoutComponents.get()).thenAnswer(new Answer<EditorFieldLayoutComponent>() { @Override public EditorFieldLayoutComponent answer(InvocationOnMock invocationOnMock) throws Throwable { return mock(EditorFieldLayoutComponent.class); } }); when(formEditorService.loadContent(any())).then(new Answer<FormModelerContent>() { @Override public FormModelerContent answer(InvocationOnMock invocation) throws Throwable { FormDefinition form = new FormDefinition(); form.setName("EmployeeTestForm"); form.setId("_random_id"); content = new FormModelerContent(); FormModel model = () -> "employee"; form.setModel(model); Map<String, List<FieldDefinition>> availableFields = new HashMap<>(); availableFields.put("employee", employeeFields); content.setDefinition(form); content.setOverview(new Overview()); content.setPath(path); content.setAvailableFields(availableFields); employeeFields.forEach(fieldDefinition -> content.getModelProperties().add(fieldDefinition.getBinding())); return content; } }); editorServiceCallerMock = new CallerMock<>(formEditorService); editorContext = new FormEditorHelper(new TestFieldManager(), eventMock, editorFieldLayoutComponents); presenter = new FormEditorPresenter(view, formDefinitionResourceType, editorServiceCallerMock, translationService, editorFieldLayoutComponents) { { kieView = mock(KieEditorWrapperView.class); versionRecordManager = FormEditorPresenterTest.this.versionRecordManager; editorContext = FormEditorPresenterTest.this.editorContext; busyIndicatorView = mock(BusyIndicatorView.class); overviewWidget = mock(OverviewWidgetPresenter.class); layoutEditor = FormEditorPresenterTest.this.layoutEditor; htmlLayoutDragComponent = FormEditorPresenterTest.this.htmlLayoutDragComponent; } protected void makeMenuBar() { } protected void addSourcePage() { } }; presenter.onStartup(path, mock(PlaceRequest.class)); assertTrue("There should exist base field draggables", editorContext.getBaseFieldsDraggables().size() > 0); } @Test public void testLoad() { loadContent(); verify(layoutEditor).loadLayout(content.getDefinition().getLayoutTemplate()); verify(view).init(presenter); verify(view).setupLayoutEditor(layoutEditor); } @Test public void testLoadWithContent() { testLoad(); presenter.loadContent(); verify(layoutEditor).clear(); verify(layoutEditor, times(2)).loadLayout(content.getDefinition().getLayoutTemplate()); verify(view, times(2)).init(presenter); verify(view, times(2)).setupLayoutEditor(layoutEditor); } @Test public void testMayClose() { testLoad(); assertTrue(presenter.onMayClose()); verify(view, never()).confirmClose(); testAddAndMoveFields(); assertFalse(presenter.onMayClose()); verify(view).confirmClose(); } @Test public void testDataObjectsFields() { loadContent(); testAddRemoveDataTypeFields(); testDataTypeFieldProperties(); } @Test public void testUnbindedFields() { loadContent(); testUnbindedFieldProperties(); } @Test public void testMoveFormFields() { loadContent(); testAddAndMoveFields(); } protected void testAddAndMoveFields() { testAddFields(true); FormDefinition form = editorContext.getFormDefinition(); int formFields = form.getFields().size(); assertTrue("Form should have fields.", formFields > 0); assertEquals("Form should contain '" + employeeFields.size() + "' fields.", formFields, employeeFields.size()); int availableFields = editorContext.getAvailableFields().size(); assertTrue("There should not exist available fields.", availableFields == 0); List<FieldDefinition> formFieldsList = new ArrayList<>(form.getFields()); for (FieldDefinition field : formFieldsList) { presenter.onRemoveComponent(createComponentRemovedEvent(form, field)); checkExpectedFields(1, formFields - 1, true); presenter.onDropComponent(createComponentDropEvent(form, field)); checkExpectedFields(0, formFields, true); } } public void testAddRemoveDataTypeFields() { testAddFields(true); testRemoveFields(true); } protected void testAddFields(boolean checkAvailable) { int formFields = editorContext.getFormDefinition().getFields().size(); int availableFields = editorContext.getAvailableFields().size(); for (FieldDefinition field : employeeFields) { presenter.onDropComponent(createComponentDropEvent(editorContext.getFormDefinition(), field)); availableFields--; formFields++; checkExpectedFields(availableFields, formFields, checkAvailable); } } protected void testRemoveFields(boolean checkAvailable) { int formFields = editorContext.getFormDefinition().getFields().size(); assertTrue("Form should have fields.", formFields > 0); assertEquals("Form should contain '" + employeeFields.size() + "' fields.", formFields, employeeFields.size()); int availableFields = editorContext.getAvailableFields().size(); assertTrue("There should not exist available fields.", availableFields == 0); List<FieldDefinition> formFieldsList = new ArrayList<>(editorContext.getFormDefinition().getFields()); for (FieldDefinition field : formFieldsList) { presenter.onRemoveComponent(createComponentRemovedEvent(editorContext.getFormDefinition(), field)); availableFields++; formFields--; checkExpectedFields(availableFields, formFields, checkAvailable); } } public void testDataTypeFieldProperties() { testFieldProperties("name", true); } public void testUnbindedFieldProperties() { testFieldProperties(TextBoxFieldDefinition.FIELD_TYPE.getTypeName(), false); } protected void testFieldProperties(String fieldId, boolean binded) { FormDefinition form = editorContext.getFormDefinition(); presenter.onDropComponent(createComponentDropEvent(editorContext.getFormDefinition(), editorContext.getFormField(fieldId))); checkExpectedFields(editorContext.getAvailableFields().size(), 1, binded); FieldDefinition field = editorContext.getFormDefinition().getFields().get(0); checkFieldType(field, TextBoxFieldDefinition.class); Collection<String> compatibleTypes = editorContext.getCompatibleFieldTypes(field); assertNotNull("No compatibles types found!", compatibleTypes); assertTrue("There should exist more than one compatible types for TextBoxFieldDefinition!", compatibleTypes.size() > 1); assertTrue("Missing TextAreaFieldDefinition as a compatible type for TextBoxFieldDefinition", compatibleTypes.contains(TextAreaFieldDefinition.FIELD_TYPE.getTypeName())); field = editorContext.switchToFieldType(field, TextAreaFieldDefinition.FIELD_TYPE.getTypeName()); checkFieldType(field, TextAreaFieldDefinition.class); List<String> compatibleFields = editorContext.getCompatibleModelFields(field); assertNotNull("No compatibles fields found!", compatibleFields); assertEquals("There should exist 2 compatible fields for " + field.getName() + "!", compatibleFields.size(), 2); String expectedBindingExpression = "lastName"; field = editorContext.switchToField(field, expectedBindingExpression); assertEquals("Wrong binding expression after switch field!", field.getBinding(), expectedBindingExpression); presenter.onRemoveComponent(createComponentRemovedEvent(form, field)); } protected ComponentDropEvent createComponentDropEvent(FormDefinition form, FieldDefinition field) { return new ComponentDropEvent(createLayoutComponent(form, field)); } protected ComponentRemovedEvent createComponentRemovedEvent(FormDefinition form, FieldDefinition field) { return new ComponentRemovedEvent(createLayoutComponent(form, field)); } protected LayoutComponent createLayoutComponent(FormDefinition form, FieldDefinition field) { LayoutComponent component = new LayoutComponent(""); component.addProperty(FieldLayoutComponent.FORM_ID, form.getId()); component.addProperty(FieldLayoutComponent.FIELD_ID, field.getId()); return component; } protected void checkFieldType(FieldDefinition field, Class<? extends FieldDefinition> type) { assertTrue("Field " + field.getName() + " should be of type " + type.getClass().getName(), field.getClass() == type); } protected void checkExpectedFields(int expectedAvailable, int expectedFormFields, boolean checkAvailable) { if (checkAvailable) { assertEquals("There should be " + expectedAvailable + " available fields", editorContext.getAvailableFields().size(), expectedAvailable); } assertEquals("The form must contain " + expectedFormFields + " fields ", editorContext.getFormDefinition().getFields().size(), expectedFormFields); } protected void initFields() { TextBoxFieldDefinition name = new TextBoxFieldDefinition(); name.setId("name"); name.setName("employee_name"); name.setLabel("Name"); name.setPlaceHolder("Name"); name.setBinding("name"); name.setStandaloneClassName(String.class.getName()); TextBoxFieldDefinition lastName = new TextBoxFieldDefinition(); lastName.setId("lastName"); lastName.setName("employee_lastName"); lastName.setLabel("Last Name"); lastName.setPlaceHolder("Last Name"); lastName.setBinding("lastName"); lastName.setStandaloneClassName(String.class.getName()); DatePickerFieldDefinition birthday = new DatePickerFieldDefinition(); birthday.setId("birthday"); birthday.setName("employee_birthday"); birthday.setLabel("Birthday"); birthday.setBinding("birthday"); birthday.setStandaloneClassName(Date.class.getName()); CheckBoxFieldDefinition married = new CheckBoxFieldDefinition(); married.setId("married"); married.setName("employee_married"); married.setLabel("Married"); married.setBinding("married"); married.setStandaloneClassName(Boolean.class.getName()); employeeFields = new ArrayList<FieldDefinition>(); employeeFields.add(name); employeeFields.add(lastName); employeeFields.add(birthday); employeeFields.add(married); } }