From d0534afef24c69558597161af7a2ce3406a3acd5 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Tue, 17 Oct 2023 13:51:06 +0300 Subject: [PATCH] fix: ensure client-side value property is initialized (#5590) --- .../component/textfield/TextFieldBase.java | 6 +-- .../textfield/tests/BigDecimalFieldTest.java | 46 +++++++++++++++++-- .../textfield/tests/EmailFieldTest.java | 42 ++++++++++++++++- .../textfield/tests/IntegerFieldTest.java | 45 ++++++++++++++++-- .../textfield/tests/NumberFieldTest.java | 43 +++++++++++++++-- .../textfield/tests/PasswordFieldTest.java | 45 +++++++++++++++++- .../textfield/tests/TextAreaTest.java | 43 +++++++++++++++-- .../textfield/tests/TextFieldTest.java | 44 +++++++++++++++++- 8 files changed, 292 insertions(+), 22 deletions(-) diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextFieldBase.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextFieldBase.java index ebb10341832..bfe9451f3dd 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextFieldBase.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/main/java/com/vaadin/flow/component/textfield/TextFieldBase.java @@ -309,7 +309,7 @@

TextFieldBase(TValue initialValue, TValue defaultValue, super("value", defaultValue, elementPropertyType, presentationToModel, modelToPresentation); if ((getElement().getProperty("value") == null - || !isInitialValueOptional) && initialValue != null) { + || !isInitialValueOptional)) { setPresentationValue(initialValue); } } @@ -349,7 +349,7 @@

TextFieldBase(TValue initialValue, TValue defaultValue, super("value", defaultValue, elementPropertyType, presentationToModel, modelToPresentation); if ((getElement().getProperty("value") == null - || !isInitialValueOptional) && initialValue != null) { + || !isInitialValueOptional)) { setPresentationValue(initialValue); } } @@ -377,7 +377,7 @@

TextFieldBase(TValue initialValue, TValue defaultValue, boolean acceptNullValues, boolean isInitialValueOptional) { super("value", defaultValue, acceptNullValues); if ((getElement().getProperty("value") == null - || !isInitialValueOptional) && initialValue != null) { + || !isInitialValueOptional)) { setPresentationValue(initialValue); } } diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/BigDecimalFieldTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/BigDecimalFieldTest.java index a0b301dfe9a..c4db7c535ab 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/BigDecimalFieldTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/BigDecimalFieldTest.java @@ -16,15 +16,23 @@ package com.vaadin.flow.component.textfield.tests; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasAriaLabel; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.shared.HasTooltip; import com.vaadin.flow.component.shared.InputField; import com.vaadin.flow.component.textfield.BigDecimalField; import com.vaadin.flow.component.textfield.TextFieldVariant; +import com.vaadin.flow.di.Instantiator; +import com.vaadin.flow.dom.Element; import com.vaadin.flow.dom.ThemeList; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import java.math.BigDecimal; import java.util.Locale; @@ -52,9 +60,41 @@ public void setValueNull() { @Override @Test - public void initialValuePropertyValue() { - assertEquals(field.getEmptyValue(), - field.getElement().getProperty("value")); + public void initialValueIsNotSpecified_valuePropertyHasEmptyString() { + BigDecimalField bigDecimalField = new BigDecimalField(); + Assert.assertNull(bigDecimalField.getValue()); + Assert.assertEquals("", + bigDecimalField.getElement().getProperty("value")); + } + + @Override + @Test + public void initialValueIsNull_valuePropertyHasEmptyString() { + } + + @Override + @Test + public void createElementWithValue_createComponentInstanceFromElement_valuePropertyMatchesValue() { + Element element = new Element("vaadin-big-decimal-field"); + element.setProperty("value", "1"); + UI ui = new UI(); + UI.setCurrent(ui); + VaadinSession session = Mockito.mock(VaadinSession.class); + ui.getInternals().setSession(session); + VaadinService service = Mockito.mock(VaadinService.class); + Mockito.when(session.getService()).thenReturn(service); + + Instantiator instantiator = Mockito.mock(Instantiator.class); + + Mockito.when(service.getInstantiator()).thenReturn(instantiator); + + Mockito.when(instantiator.createComponent(BigDecimalField.class)) + .thenAnswer(invocation -> new BigDecimalField()); + + BigDecimalField bigDecimalField = Component.from(element, + BigDecimalField.class); + Assert.assertEquals("1", + bigDecimalField.getElement().getProperty("value")); } @Test diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/EmailFieldTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/EmailFieldTest.java index 3916e1ed020..416bdee4f35 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/EmailFieldTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/EmailFieldTest.java @@ -16,17 +16,25 @@ package com.vaadin.flow.component.textfield.tests; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasAriaLabel; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.shared.HasAllowedCharPattern; import com.vaadin.flow.component.shared.HasTooltip; import com.vaadin.flow.component.shared.InputField; import com.vaadin.flow.component.textfield.EmailField; import com.vaadin.flow.component.textfield.TextFieldVariant; +import com.vaadin.flow.di.Instantiator; +import com.vaadin.flow.dom.Element; import com.vaadin.flow.dom.ThemeList; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; + import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.Mockito; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -52,9 +60,39 @@ public void setValueNull() { } @Test - public void initialValuePropertyValue() { + public void initialValueIsNotSpecified_valuePropertyHasEmptyString() { EmailField emailField = new EmailField(); - assertEquals(emailField.getEmptyValue(), + Assert.assertEquals("", emailField.getValue()); + Assert.assertEquals("", emailField.getElement().getProperty("value")); + } + + @Test + public void initialValueIsNull_valuePropertyHasEmptyString() { + EmailField emailField = new EmailField((String) null); + Assert.assertEquals("", emailField.getValue()); + Assert.assertEquals("", emailField.getElement().getProperty("value")); + } + + @Test + public void createElementWithValue_createComponentInstanceFromElement_valuePropertyMatchesValue() { + Element element = new Element("vaadin-email-field"); + element.setProperty("value", "foo@example.com"); + UI ui = new UI(); + UI.setCurrent(ui); + VaadinSession session = Mockito.mock(VaadinSession.class); + ui.getInternals().setSession(session); + VaadinService service = Mockito.mock(VaadinService.class); + Mockito.when(session.getService()).thenReturn(service); + + Instantiator instantiator = Mockito.mock(Instantiator.class); + + Mockito.when(service.getInstantiator()).thenReturn(instantiator); + + Mockito.when(instantiator.createComponent(EmailField.class)) + .thenAnswer(invocation -> new EmailField()); + + EmailField emailField = Component.from(element, EmailField.class); + Assert.assertEquals("foo@example.com", emailField.getElement().getProperty("value")); } diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/IntegerFieldTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/IntegerFieldTest.java index af756efdcbc..f678f5489f7 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/IntegerFieldTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/IntegerFieldTest.java @@ -16,19 +16,26 @@ package com.vaadin.flow.component.textfield.tests; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasAriaLabel; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.shared.HasTooltip; import com.vaadin.flow.component.shared.InputField; import com.vaadin.flow.component.textfield.IntegerField; import com.vaadin.flow.component.textfield.TextFieldVariant; +import com.vaadin.flow.di.Instantiator; +import com.vaadin.flow.dom.Element; import com.vaadin.flow.dom.ThemeList; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import java.util.Arrays; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; public class IntegerFieldTest extends TextFieldTest { @@ -59,9 +66,39 @@ public void assertStepGreaterThanZero() { @Override @Test - public void initialValuePropertyValue() { - assertEquals(field.getEmptyValue(), - field.getElement().getProperty("value")); + public void initialValueIsNotSpecified_valuePropertyHasEmptyString() { + IntegerField integerField = new IntegerField(); + Assert.assertNull(integerField.getValue()); + Assert.assertEquals("", integerField.getElement().getProperty("value")); + } + + @Override + @Test + public void initialValueIsNull_valuePropertyHasEmptyString() { + } + + @Override + @Test + public void createElementWithValue_createComponentInstanceFromElement_valuePropertyMatchesValue() { + Element element = new Element("vaadin-integer-field"); + element.setProperty("value", "1"); + UI ui = new UI(); + UI.setCurrent(ui); + VaadinSession session = Mockito.mock(VaadinSession.class); + ui.getInternals().setSession(session); + VaadinService service = Mockito.mock(VaadinService.class); + Mockito.when(session.getService()).thenReturn(service); + + Instantiator instantiator = Mockito.mock(Instantiator.class); + + Mockito.when(service.getInstantiator()).thenReturn(instantiator); + + Mockito.when(instantiator.createComponent(IntegerField.class)) + .thenAnswer(invocation -> new IntegerField()); + + IntegerField integerField = Component.from(element, IntegerField.class); + Assert.assertEquals("1", + integerField.getElement().getProperty("value")); } @Test diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/NumberFieldTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/NumberFieldTest.java index 39e5bf14ccb..c95cbd2a0be 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/NumberFieldTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/NumberFieldTest.java @@ -15,15 +15,23 @@ */ package com.vaadin.flow.component.textfield.tests; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasAriaLabel; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.shared.HasAllowedCharPattern; import com.vaadin.flow.component.shared.HasTooltip; import com.vaadin.flow.component.textfield.NumberField; import com.vaadin.flow.component.textfield.TextFieldVariant; +import com.vaadin.flow.di.Instantiator; +import com.vaadin.flow.dom.Element; import com.vaadin.flow.dom.ThemeList; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import java.util.Arrays; @@ -51,9 +59,38 @@ public void setValueNull() { @Override @Test - public void initialValuePropertyValue() { - assertEquals(field.getEmptyValue(), - field.getElement().getProperty("value")); + public void initialValueIsNotSpecified_valuePropertyHasEmptyString() { + NumberField numberField = new NumberField(); + Assert.assertNull(numberField.getValue()); + Assert.assertEquals("", numberField.getElement().getProperty("value")); + } + + @Override + @Test + public void initialValueIsNull_valuePropertyHasEmptyString() { + } + + @Override + @Test + public void createElementWithValue_createComponentInstanceFromElement_valuePropertyMatchesValue() { + Element element = new Element("vaadin-number-field"); + element.setProperty("value", "1"); + UI ui = new UI(); + UI.setCurrent(ui); + VaadinSession session = Mockito.mock(VaadinSession.class); + ui.getInternals().setSession(session); + VaadinService service = Mockito.mock(VaadinService.class); + Mockito.when(session.getService()).thenReturn(service); + + Instantiator instantiator = Mockito.mock(Instantiator.class); + + Mockito.when(service.getInstantiator()).thenReturn(instantiator); + + Mockito.when(instantiator.createComponent(NumberField.class)) + .thenAnswer(invocation -> new NumberField()); + + NumberField numberField = Component.from(element, NumberField.class); + Assert.assertEquals("1", numberField.getElement().getProperty("value")); } @Test(expected = IllegalArgumentException.class) diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/PasswordFieldTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/PasswordFieldTest.java index 8a1f2862ca8..4fdfbfb5f5e 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/PasswordFieldTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/PasswordFieldTest.java @@ -16,16 +16,24 @@ package com.vaadin.flow.component.textfield.tests; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasAriaLabel; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.shared.HasAllowedCharPattern; import com.vaadin.flow.component.shared.InputField; import com.vaadin.flow.component.textfield.PasswordField; import com.vaadin.flow.component.textfield.TextFieldVariant; +import com.vaadin.flow.di.Instantiator; +import com.vaadin.flow.dom.Element; import com.vaadin.flow.dom.ThemeList; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; + import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.Mockito; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -51,9 +59,42 @@ public void setValueNull() { } @Test - public void initialValuePropertyValue() { + public void initialValueIsNotSpecified_valuePropertyHasEmptyString() { PasswordField passwordField = new PasswordField(); - assertEquals(passwordField.getEmptyValue(), + Assert.assertEquals("", passwordField.getValue()); + Assert.assertEquals("", + passwordField.getElement().getProperty("value")); + } + + @Test + public void initialValueIsNull_valuePropertyHasEmptyString() { + PasswordField passwordField = new PasswordField((String) null); + Assert.assertEquals("", passwordField.getValue()); + Assert.assertEquals("", + passwordField.getElement().getProperty("value")); + } + + @Test + public void createElementWithValue_createComponentInstanceFromElement_valuePropertyMatchesValue() { + Element element = new Element("vaadin-password-field"); + element.setProperty("value", "test"); + UI ui = new UI(); + UI.setCurrent(ui); + VaadinSession session = Mockito.mock(VaadinSession.class); + ui.getInternals().setSession(session); + VaadinService service = Mockito.mock(VaadinService.class); + Mockito.when(session.getService()).thenReturn(service); + + Instantiator instantiator = Mockito.mock(Instantiator.class); + + Mockito.when(service.getInstantiator()).thenReturn(instantiator); + + Mockito.when(instantiator.createComponent(PasswordField.class)) + .thenAnswer(invocation -> new PasswordField()); + + PasswordField passwordField = Component.from(element, + PasswordField.class); + Assert.assertEquals("test", passwordField.getElement().getProperty("value")); } diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextAreaTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextAreaTest.java index a4e8d990d77..050362a1204 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextAreaTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextAreaTest.java @@ -16,17 +16,25 @@ package com.vaadin.flow.component.textfield.tests; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasAriaLabel; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.shared.HasAllowedCharPattern; import com.vaadin.flow.component.shared.HasTooltip; import com.vaadin.flow.component.shared.InputField; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.component.textfield.TextAreaVariant; +import com.vaadin.flow.di.Instantiator; +import com.vaadin.flow.dom.Element; import com.vaadin.flow.dom.ThemeList; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; + import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.Mockito; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -52,10 +60,39 @@ public void setValueNull() { } @Test - public void initialValuePropertyValue() { + public void initialValueIsNotSpecified_valuePropertyHasEmptyString() { TextArea textArea = new TextArea(); - assertEquals(textArea.getEmptyValue(), - textArea.getElement().getProperty("value")); + Assert.assertEquals("", textArea.getValue()); + Assert.assertEquals("", textArea.getElement().getProperty("value")); + } + + @Test + public void initialValueIsNull_valuePropertyHasEmptyString() { + TextArea textArea = new TextArea((String) null); + Assert.assertEquals("", textArea.getValue()); + Assert.assertEquals("", textArea.getElement().getProperty("value")); + } + + @Test + public void createElementWithValue_createComponentInstanceFromElement_valuePropertyMatchesValue() { + Element element = new Element("vaadin-text-area"); + element.setProperty("value", "test"); + UI ui = new UI(); + UI.setCurrent(ui); + VaadinSession session = Mockito.mock(VaadinSession.class); + ui.getInternals().setSession(session); + VaadinService service = Mockito.mock(VaadinService.class); + Mockito.when(session.getService()).thenReturn(service); + + Instantiator instantiator = Mockito.mock(Instantiator.class); + + Mockito.when(service.getInstantiator()).thenReturn(instantiator); + + Mockito.when(instantiator.createComponent(TextArea.class)) + .thenAnswer(invocation -> new TextArea()); + + TextArea textArea = Component.from(element, TextArea.class); + Assert.assertEquals("test", textArea.getElement().getProperty("value")); } @Test diff --git a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java index c9163e71941..e3a3c9496ca 100644 --- a/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java +++ b/vaadin-text-field-flow-parent/vaadin-text-field-flow/src/test/java/com/vaadin/flow/component/textfield/tests/TextFieldTest.java @@ -16,21 +16,31 @@ package com.vaadin.flow.component.textfield.tests; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.HasAriaLabel; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.shared.HasAllowedCharPattern; import com.vaadin.flow.component.shared.HasTooltip; import com.vaadin.flow.component.shared.InputField; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextFieldVariant; +import com.vaadin.flow.di.Instantiator; +import com.vaadin.flow.dom.Element; import com.vaadin.flow.dom.ThemeList; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; + import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.Mockito; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.time.LocalDate; + /** * Tests for the {@link TextField}. */ @@ -52,9 +62,39 @@ public void setValueNull() { } @Test - public void initialValuePropertyValue() { + public void initialValueIsNotSpecified_valuePropertyHasEmptyString() { TextField textField = new TextField(); - assertEquals(textField.getEmptyValue(), + Assert.assertEquals("", textField.getValue()); + Assert.assertEquals("", textField.getElement().getProperty("value")); + } + + @Test + public void initialValueIsNull_valuePropertyHasEmptyString() { + TextField textField = new TextField((String) null); + Assert.assertEquals("", textField.getValue()); + Assert.assertEquals("", textField.getElement().getProperty("value")); + } + + @Test + public void createElementWithValue_createComponentInstanceFromElement_valuePropertyMatchesValue() { + Element element = new Element("vaadin-text-field"); + element.setProperty("value", "test"); + UI ui = new UI(); + UI.setCurrent(ui); + VaadinSession session = Mockito.mock(VaadinSession.class); + ui.getInternals().setSession(session); + VaadinService service = Mockito.mock(VaadinService.class); + Mockito.when(session.getService()).thenReturn(service); + + Instantiator instantiator = Mockito.mock(Instantiator.class); + + Mockito.when(service.getInstantiator()).thenReturn(instantiator); + + Mockito.when(instantiator.createComponent(TextField.class)) + .thenAnswer(invocation -> new TextField()); + + TextField textField = Component.from(element, TextField.class); + Assert.assertEquals("test", textField.getElement().getProperty("value")); }