@@ -38,9 +38,9 @@ import java.util.logging.Logger; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import com.googlecode.gentyref.GenericTypeReflector; | |||
import org.jsoup.nodes.Element; | |||
import com.googlecode.gentyref.GenericTypeReflector; | |||
import com.vaadin.data.Result; | |||
import com.vaadin.data.ValidationResult; | |||
import com.vaadin.data.Validator; | |||
@@ -179,7 +179,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
}; | |||
/** | |||
* The default start year (inclusive) from which to calculate the | |||
* The default start year (inclusive) from which to calculate the | |||
* daylight-saving time zone transition dates. | |||
*/ | |||
private static final int DEFAULT_START_YEAR = 1980; | |||
@@ -323,8 +323,9 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
* <p> | |||
* Note: Negative, i.e. BC dates are not supported. | |||
* <p> | |||
* Note: It's usually recommended to use only one of the following at the same | |||
* time: Range validator with Binder or DateField's setRangeStart check. | |||
* Note: It's usually recommended to use only one of the following at the | |||
* same time: Range validator with Binder or DateField's setRangeStart | |||
* check. | |||
* | |||
* @param startDate | |||
* - the allowed range's start date | |||
@@ -377,8 +378,11 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
* the resolution to set, not {@code null} | |||
*/ | |||
public void setResolution(R resolution) { | |||
this.resolution = resolution; | |||
updateResolutions(); | |||
if (!resolution.equals(this.resolution)) { | |||
this.resolution = resolution; | |||
setValue(adjustToResolution(getValue(), resolution)); | |||
updateResolutions(); | |||
} | |||
} | |||
/** | |||
@@ -387,8 +391,8 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
* validate. If {@code endDate} is set to {@code null}, any value after | |||
* {@code startDate} will be accepted by the range. | |||
* <p> | |||
* Note: It's usually recommended to use only one of the following at the same | |||
* time: Range validator with Binder or DateField's setRangeEnd check. | |||
* Note: It's usually recommended to use only one of the following at the | |||
* same time: Range validator with Binder or DateField's setRangeEnd check. | |||
* | |||
* @param endDate | |||
* the allowed range's end date (inclusive, based on the current | |||
@@ -545,8 +549,8 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
* inclusive) between which to calculate the daylight-saving time zone | |||
* transition dates. Both parameters are used when '{@code z}' is included | |||
* inside the {@link #setDateFormat(String)}, they would have no effect | |||
* otherwise. Specifically, these parameters determine the range of years in | |||
* which zone names are are adjusted to show the daylight saving names. | |||
* otherwise. Specifically, these parameters determine the range of years in | |||
* which zone names are are adjusted to show the daylight saving names. | |||
* | |||
* If no values are provided, by default {@link startYear} is set to | |||
* {@value #DEFAULT_START_YEAR}, and {@link endYear} is set to | |||
@@ -704,12 +708,13 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
* @param value | |||
* the new value, may be {@code null} | |||
* @throws IllegalArgumentException | |||
* if the value is not within range bounds | |||
* if the value is not within range bounds | |||
*/ | |||
@Override | |||
public void setValue(T value) { | |||
T adjusted = adjustToResolution(value, getResolution()); | |||
RangeValidator<T> validator = getRangeValidator(); | |||
ValidationResult result = validator.apply(value, | |||
ValidationResult result = validator.apply(adjusted, | |||
new ValueContext(this, this)); | |||
if (result.isError()) { | |||
@@ -718,25 +723,40 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
} else { | |||
currentErrorMessage = null; | |||
/* | |||
* First handle special case when the client side component has a date | |||
* string but value is null (e.g. unparsable date string typed in by the | |||
* user). No value changes should happen, but we need to do some | |||
* internal housekeeping. | |||
* First handle special case when the client side component has a | |||
* date string but value is null (e.g. unparsable date string typed | |||
* in by the user). No value changes should happen, but we need to | |||
* do some internal housekeeping. | |||
*/ | |||
if (value == null && !getState(false).parsable) { | |||
if (adjusted == null && !getState(false).parsable) { | |||
/* | |||
* Side-effects of doSetValue clears possible previous strings and | |||
* flags about invalid input. | |||
* Side-effects of doSetValue clears possible previous strings | |||
* and flags about invalid input. | |||
*/ | |||
doSetValue(null); | |||
markAsDirty(); | |||
return; | |||
} | |||
super.setValue(value); | |||
super.setValue(adjusted); | |||
} | |||
} | |||
/** | |||
* Adjusts the given date to the given resolution. Any values that are more | |||
* specific than the given resolution are truncated to their default values. | |||
* | |||
* @param date | |||
* the date to adjust, can be {@code null} | |||
* @param resolution | |||
* the resolution to be used in the adjustment, can be | |||
* {@code null} | |||
* @return an adjusted date that matches the given resolution, or | |||
* {@code null} if the given date, resolution, or both were | |||
* {@code null} | |||
*/ | |||
protected abstract T adjustToResolution(T date, R resolution); | |||
/** | |||
* Checks whether ISO 8601 week numbers are shown in the date selector. | |||
* | |||
@@ -820,7 +840,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & | |||
.info("cannot parse " + design.attr("value") | |||
+ " as date"); | |||
} | |||
doSetValue(date); | |||
doSetValue(adjustToResolution(date, getResolution())); | |||
} else { | |||
throw new RuntimeException("Cannot detect resoluton type " | |||
+ Optional.ofNullable(dateType).map(Type::getTypeName) |
@@ -103,8 +103,8 @@ public abstract class AbstractLocalDateField | |||
@Override | |||
protected RangeValidator<LocalDate> getRangeValidator() { | |||
return new DateRangeValidator(getDateOutOfRangeMessage(), | |||
getDate(getRangeStart(), getResolution()), | |||
getDate(getRangeEnd(), getResolution())); | |||
adjustToResolution(getRangeStart(), getResolution()), | |||
adjustToResolution(getRangeEnd(), getResolution())); | |||
} | |||
@Override | |||
@@ -134,7 +134,9 @@ public abstract class AbstractLocalDateField | |||
return Date.from(date.atStartOfDay(ZoneOffset.UTC).toInstant()); | |||
} | |||
private LocalDate getDate(LocalDate date, DateResolution forResolution) { | |||
@Override | |||
protected LocalDate adjustToResolution(LocalDate date, | |||
DateResolution forResolution) { | |||
if (date == null) { | |||
return null; | |||
} | |||
@@ -171,19 +173,21 @@ public abstract class AbstractLocalDateField | |||
protected Result<LocalDate> handleUnparsableDateString(String dateString) { | |||
// Handle possible week number, which cannot be parsed client side due | |||
// limitations in GWT | |||
if (this.getDateFormat() != null && this.getDateFormat().contains("w")) { | |||
if (getDateFormat() != null && getDateFormat().contains("w")) { | |||
Date parsedDate; | |||
SimpleDateFormat df = new SimpleDateFormat(this.getDateFormat(),this.getLocale()); | |||
SimpleDateFormat df = new SimpleDateFormat(getDateFormat(), | |||
getLocale()); | |||
try { | |||
parsedDate = df.parse(dateString); | |||
} catch (ParseException e) { | |||
return super.handleUnparsableDateString(dateString); | |||
} | |||
ZoneId zi = this.getZoneId(); | |||
if (zi == null) { | |||
ZoneId zi = getZoneId(); | |||
if (zi == null) { | |||
zi = ZoneId.systemDefault(); | |||
} | |||
LocalDate date = Instant.ofEpochMilli(parsedDate.getTime()).atZone(zi).toLocalDate(); | |||
LocalDate date = Instant.ofEpochMilli(parsedDate.getTime()) | |||
.atZone(zi).toLocalDate(); | |||
return Result.ok(date); | |||
} else { | |||
return super.handleUnparsableDateString(dateString); |
@@ -111,8 +111,8 @@ public abstract class AbstractLocalDateTimeField | |||
@Override | |||
protected RangeValidator<LocalDateTime> getRangeValidator() { | |||
return new DateTimeRangeValidator(getDateOutOfRangeMessage(), | |||
getDate(getRangeStart(), getResolution()), | |||
getDate(getRangeEnd(), getResolution())); | |||
adjustToResolution(getRangeStart(), getResolution()), | |||
adjustToResolution(getRangeEnd(), getResolution())); | |||
} | |||
@Override | |||
@@ -143,7 +143,8 @@ public abstract class AbstractLocalDateTimeField | |||
return Date.from(date.toInstant(ZoneOffset.UTC)); | |||
} | |||
private LocalDateTime getDate(LocalDateTime date, | |||
@Override | |||
protected LocalDateTime adjustToResolution(LocalDateTime date, | |||
DateTimeResolution forResolution) { | |||
if (date == null) { | |||
return null; |
@@ -14,6 +14,7 @@ import com.vaadin.data.Binder; | |||
import com.vaadin.data.ValidationException; | |||
import com.vaadin.data.ValueContext; | |||
import com.vaadin.data.converter.LocalDateTimeToDateConverter; | |||
import com.vaadin.shared.ui.datefield.DateTimeResolution; | |||
import com.vaadin.ui.DateTimeField; | |||
public class LocalDateTimeToDateConverterTest extends AbstractConverterTest { | |||
@@ -59,7 +60,15 @@ public class LocalDateTimeToDateConverterTest extends AbstractConverterTest { | |||
BeanWithDate bean = new BeanWithDate(); | |||
binder.writeBean(bean); | |||
assertEquals(DATE, bean.getDate()); | |||
assertEquals(DateTimeResolution.MINUTE, dateField.getResolution()); | |||
// create a comparison date that matches the resolution | |||
Calendar calendar = Calendar | |||
.getInstance(TimeZone.getTimeZone(ZoneOffset.UTC)); | |||
calendar.clear(); | |||
calendar.set(2017, Calendar.JANUARY, 1, 1, 1, 0); | |||
Date date = calendar.getTime(); | |||
assertEquals(date, bean.getDate()); | |||
} | |||
public static class BeanWithDate { |
@@ -25,15 +25,19 @@ import com.vaadin.ui.AbstractLocalDateTimeField; | |||
public abstract class AbstractLocalDateTimeFieldDeclarativeTest<T extends AbstractLocalDateTimeField> | |||
extends AbstractFieldDeclarativeTest<T, LocalDateTime> { | |||
protected DateTimeFormatter DATE_FORMATTER = DateTimeFormatter | |||
.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH); | |||
// field initialised with DateTimeResolution.MINUTE, seconds get truncated | |||
protected DateTimeFormatter VALUE_DATE_FORMATTER = DateTimeFormatter | |||
.ofPattern("yyyy-MM-dd HH:mm:00", Locale.ROOT); | |||
// only field value conforms to resolution, range keeps the initial values | |||
protected DateTimeFormatter RANGE_DATE_FORMATTER = DateTimeFormatter | |||
.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ROOT); | |||
@Override | |||
public void valueDeserialization() | |||
throws InstantiationException, IllegalAccessException { | |||
LocalDateTime value = LocalDateTime.of(2003, 02, 27, 10, 37, 43); | |||
String design = String.format("<%s value='%s'/>", getComponentTag(), | |||
DATE_FORMATTER.format(value)); | |||
VALUE_DATE_FORMATTER.format(value)); | |||
T component = getComponentClass().newInstance(); | |||
component.setValue(value); | |||
@@ -57,8 +61,8 @@ public abstract class AbstractLocalDateTimeFieldDeclarativeTest<T extends Abstra | |||
"<%s show-iso-week-numbers range-end='%s' range-start='%s' " | |||
+ "date-out-of-range-message='%s' resolution='%s' " | |||
+ "date-format='%s' lenient parse-error-message='%s'/>", | |||
getComponentTag(), DATE_FORMATTER.format(end), | |||
DATE_FORMATTER.format(start), dateOutOfRange, | |||
getComponentTag(), RANGE_DATE_FORMATTER.format(end), | |||
RANGE_DATE_FORMATTER.format(start), dateOutOfRange, | |||
resolution.name().toLowerCase(Locale.ROOT), dateFormat, | |||
parseErrorMsg); | |||
@@ -82,7 +86,7 @@ public abstract class AbstractLocalDateTimeFieldDeclarativeTest<T extends Abstra | |||
throws InstantiationException, IllegalAccessException { | |||
LocalDateTime value = LocalDateTime.of(2003, 02, 27, 23, 12, 34); | |||
String design = String.format("<%s value='%s' readonly/>", | |||
getComponentTag(), DATE_FORMATTER.format(value)); | |||
getComponentTag(), VALUE_DATE_FORMATTER.format(value)); | |||
T component = getComponentClass().newInstance(); | |||
component.setValue(value); |
@@ -1,12 +1,14 @@ | |||
package com.vaadin.tests.server.component.datefield; | |||
import java.time.LocalDateTime; | |||
import java.time.temporal.ChronoUnit; | |||
import java.time.temporal.TemporalAccessor; | |||
import java.util.Date; | |||
import java.util.Map; | |||
import org.junit.Test; | |||
import com.vaadin.data.validator.DateTimeRangeValidator; | |||
import com.vaadin.data.validator.RangeValidator; | |||
import com.vaadin.event.FieldEvents.BlurEvent; | |||
import com.vaadin.event.FieldEvents.BlurListener; | |||
@@ -39,7 +41,9 @@ public class DateFieldListenersTest extends AbstractListenerMethodsTestBase { | |||
@Override | |||
protected RangeValidator<LocalDateTime> getRangeValidator() { | |||
return null; | |||
return new DateTimeRangeValidator(getDateOutOfRangeMessage(), | |||
adjustToResolution(getRangeStart(), getResolution()), | |||
adjustToResolution(getRangeEnd(), getResolution())); | |||
} | |||
@Override | |||
@@ -61,6 +65,32 @@ public class DateFieldListenersTest extends AbstractListenerMethodsTestBase { | |||
protected LocalDateTime toType(TemporalAccessor temporalAccessor) { | |||
return LocalDateTime.from(temporalAccessor); | |||
} | |||
@Override | |||
protected LocalDateTime adjustToResolution(LocalDateTime date, | |||
DateTimeResolution forResolution) { | |||
if (date == null) { | |||
return null; | |||
} | |||
switch (forResolution) { | |||
case YEAR: | |||
return date.withDayOfYear(1).toLocalDate().atStartOfDay(); | |||
case MONTH: | |||
return date.withDayOfMonth(1).toLocalDate().atStartOfDay(); | |||
case DAY: | |||
return date.toLocalDate().atStartOfDay(); | |||
case HOUR: | |||
return date.truncatedTo(ChronoUnit.HOURS); | |||
case MINUTE: | |||
return date.truncatedTo(ChronoUnit.MINUTES); | |||
case SECOND: | |||
return date.truncatedTo(ChronoUnit.SECONDS); | |||
default: | |||
assert false : "Unexpected resolution argument " | |||
+ forResolution; | |||
return null; | |||
} | |||
} | |||
} | |||
@Test |
@@ -0,0 +1,114 @@ | |||
package com.vaadin.tests.components.datefield; | |||
import java.time.LocalDate; | |||
import java.time.format.DateTimeFormatter; | |||
import java.util.Locale; | |||
import com.vaadin.data.Binder; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.shared.ui.datefield.DateResolution; | |||
import com.vaadin.tests.components.AbstractTestUIWithLog; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.DateField; | |||
import com.vaadin.ui.HorizontalLayout; | |||
public class DateFieldResolutionChange extends AbstractTestUIWithLog { | |||
protected DateTimeFormatter DATE_FORMATTER = DateTimeFormatter | |||
.ofPattern("yyyy-MM-dd", Locale.ROOT); | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
Binder<Pojo> binder = new Binder<>(Pojo.class); | |||
HorizontalLayout horizontalLayout = new HorizontalLayout(); | |||
final DateField monthField = new DateField() { | |||
@Override | |||
public void setValue(LocalDate value) { | |||
if (value != null) { | |||
log("MonthField set value " + DATE_FORMATTER.format(value)); | |||
} | |||
super.setValue(value); | |||
} | |||
}; | |||
monthField.setResolution(DateResolution.MONTH); | |||
monthField.setId("MonthField"); | |||
monthField.addValueChangeListener( | |||
event -> log("MonthField value change event: " | |||
+ DATE_FORMATTER.format(event.getValue()))); | |||
binder.bind(monthField, "value1"); | |||
final DateField dayField = new DateField() { | |||
@Override | |||
public void setValue(LocalDate value) { | |||
if (value != null) { | |||
log("DayField set value " + DATE_FORMATTER.format(value)); | |||
} | |||
super.setValue(value); | |||
} | |||
}; | |||
dayField.setResolution(DateResolution.DAY); | |||
dayField.setId("DayField"); | |||
dayField.addValueChangeListener( | |||
event -> log("DayField value change event: " | |||
+ DATE_FORMATTER.format(event.getValue()))); | |||
binder.bind(dayField, "value2"); | |||
Pojo pojo = new Pojo(); | |||
binder.setBean(pojo); | |||
Button monthButton = new Button("month", e -> { | |||
monthField.setResolution(DateResolution.MONTH); | |||
dayField.setResolution(DateResolution.MONTH); | |||
}); | |||
Button dayButton = new Button("day", e -> { | |||
monthField.setResolution(DateResolution.DAY); | |||
dayField.setResolution(DateResolution.DAY); | |||
}); | |||
Button logButton = new Button("log", e -> { | |||
log("MonthField current value: " | |||
+ DATE_FORMATTER.format(pojo.getValue1())); | |||
log("DayField current value: " | |||
+ DATE_FORMATTER.format(pojo.getValue2())); | |||
}); | |||
Button setButton = new Button("set", e -> { | |||
LocalDate newDate = LocalDate.of(2021, 2, 14); | |||
pojo.setValue1(newDate); | |||
pojo.setValue2(newDate); | |||
binder.setBean(pojo); | |||
}); | |||
horizontalLayout.addComponents(monthField, dayField, monthButton, | |||
dayButton, logButton, setButton); | |||
addComponent(horizontalLayout); | |||
} | |||
public class Pojo { | |||
private LocalDate value1, value2 = null; | |||
public LocalDate getValue1() { | |||
return value1; | |||
} | |||
public void setValue1(LocalDate value1) { | |||
this.value1 = value1; | |||
} | |||
public LocalDate getValue2() { | |||
return value2; | |||
} | |||
public void setValue2(LocalDate value2) { | |||
this.value2 = value2; | |||
} | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "Date field value should immediately update to match resolution."; | |||
} | |||
} |
@@ -0,0 +1,114 @@ | |||
package com.vaadin.tests.components.datefield; | |||
import java.time.LocalDateTime; | |||
import java.time.format.DateTimeFormatter; | |||
import java.util.Locale; | |||
import com.vaadin.data.Binder; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.shared.ui.datefield.DateTimeResolution; | |||
import com.vaadin.tests.components.AbstractTestUIWithLog; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.DateTimeField; | |||
import com.vaadin.ui.HorizontalLayout; | |||
public class DateTimeFieldResolutionChange extends AbstractTestUIWithLog { | |||
protected DateTimeFormatter DATE_FORMATTER = DateTimeFormatter | |||
.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ROOT); | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
Binder<Pojo> binder = new Binder<>(Pojo.class); | |||
HorizontalLayout horizontalLayout = new HorizontalLayout(); | |||
final DateTimeField monthField = new DateTimeField() { | |||
@Override | |||
public void setValue(LocalDateTime value) { | |||
if (value != null) { | |||
log("MonthField set value " + DATE_FORMATTER.format(value)); | |||
} | |||
super.setValue(value); | |||
} | |||
}; | |||
monthField.setResolution(DateTimeResolution.MONTH); | |||
monthField.setId("MonthField"); | |||
monthField.addValueChangeListener( | |||
event -> log("MonthField value change event: " | |||
+ DATE_FORMATTER.format(event.getValue()))); | |||
binder.bind(monthField, "value1"); | |||
final DateTimeField dayField = new DateTimeField() { | |||
@Override | |||
public void setValue(LocalDateTime value) { | |||
if (value != null) { | |||
log("DayField set value " + DATE_FORMATTER.format(value)); | |||
} | |||
super.setValue(value); | |||
} | |||
}; | |||
dayField.setResolution(DateTimeResolution.DAY); | |||
dayField.setId("DayField"); | |||
dayField.addValueChangeListener( | |||
event -> log("DayField value change event: " | |||
+ DATE_FORMATTER.format(event.getValue()))); | |||
binder.bind(dayField, "value2"); | |||
Pojo pojo = new Pojo(); | |||
binder.setBean(pojo); | |||
Button monthButton = new Button("month", e -> { | |||
monthField.setResolution(DateTimeResolution.MONTH); | |||
dayField.setResolution(DateTimeResolution.MONTH); | |||
}); | |||
Button dayButton = new Button("day", e -> { | |||
monthField.setResolution(DateTimeResolution.DAY); | |||
dayField.setResolution(DateTimeResolution.DAY); | |||
}); | |||
Button logButton = new Button("log", e -> { | |||
log("MonthField current value: " | |||
+ DATE_FORMATTER.format(pojo.getValue1())); | |||
log("DayField current value: " | |||
+ DATE_FORMATTER.format(pojo.getValue2())); | |||
}); | |||
Button setButton = new Button("set", e -> { | |||
LocalDateTime newDate = LocalDateTime.of(2021, 2, 14, 16, 17); | |||
pojo.setValue1(newDate); | |||
pojo.setValue2(newDate); | |||
binder.setBean(pojo); | |||
}); | |||
horizontalLayout.addComponents(monthField, dayField, monthButton, | |||
dayButton, logButton, setButton); | |||
addComponent(horizontalLayout); | |||
} | |||
public class Pojo { | |||
private LocalDateTime value1, value2 = null; | |||
public LocalDateTime getValue1() { | |||
return value1; | |||
} | |||
public void setValue1(LocalDateTime value1) { | |||
this.value1 = value1; | |||
} | |||
public LocalDateTime getValue2() { | |||
return value2; | |||
} | |||
public void setValue2(LocalDateTime value2) { | |||
this.value2 = value2; | |||
} | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "Date field value should immediately update to match resolution."; | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
package com.vaadin.tests.components.datefield; | |||
import static org.junit.Assert.assertEquals; | |||
import org.junit.Test; | |||
import com.vaadin.testbench.elements.ButtonElement; | |||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||
public class DateFieldResolutionChangeTest extends MultiBrowserTest { | |||
@Test | |||
public void testValueAndResolutionChange() { | |||
openTestURL(); | |||
// set a fixed date | |||
$(ButtonElement.class).caption("set").first().click(); | |||
// both fields should trigger a value change event but for MonthField | |||
// the day value should be truncated to default | |||
assertEquals("Unexpected log row", "1. MonthField set value 2021-02-14", | |||
getLogRow(3)); | |||
assertEquals("Unexpected log row", | |||
"2. MonthField value change event: 2021-02-01", getLogRow(2)); | |||
assertEquals("Unexpected log row", "3. DayField set value 2021-02-14", | |||
getLogRow(1)); | |||
assertEquals("Unexpected log row", | |||
"4. DayField value change event: 2021-02-14", getLogRow(0)); | |||
// change both to day resolution | |||
$(ButtonElement.class).caption("day").first().click(); | |||
// DayField shouldn't react, MonthField should check that the value | |||
// matches resolution but not trigger a ValueChangeEvent | |||
assertEquals("Unexpected log row", "5. MonthField set value 2021-02-01", | |||
getLogRow(0)); | |||
// change both to month resolution | |||
$(ButtonElement.class).caption("month").first().click(); | |||
// both fields should check that the value matches resolution but only | |||
// DayField should trigger a ValueChangeEvent | |||
assertEquals("Unexpected log row", "6. MonthField set value 2021-02-01", | |||
getLogRow(2)); | |||
assertEquals("Unexpected log row", "7. DayField set value 2021-02-01", | |||
getLogRow(1)); | |||
assertEquals("Unexpected log row", | |||
"8. DayField value change event: 2021-02-01", getLogRow(0)); | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
package com.vaadin.tests.components.datefield; | |||
import static org.junit.Assert.assertEquals; | |||
import org.junit.Test; | |||
import com.vaadin.testbench.elements.ButtonElement; | |||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||
public class DateTimeFieldResolutionChangeTest extends MultiBrowserTest { | |||
@Test | |||
public void testValueAndResolutionChange() { | |||
openTestURL(); | |||
// set a fixed date | |||
$(ButtonElement.class).caption("set").first().click(); | |||
// both fields should trigger a value change event but the value should | |||
// be truncated according to each field's resolution | |||
assertEquals("Unexpected log row", | |||
"1. MonthField set value 2021-02-14 16:17:00", getLogRow(3)); | |||
assertEquals("Unexpected log row", | |||
"2. MonthField value change event: 2021-02-01 00:00:00", | |||
getLogRow(2)); | |||
assertEquals("Unexpected log row", | |||
"3. DayField set value 2021-02-14 16:17:00", getLogRow(1)); | |||
assertEquals("Unexpected log row", | |||
"4. DayField value change event: 2021-02-14 00:00:00", | |||
getLogRow(0)); | |||
// change both to day resolution | |||
$(ButtonElement.class).caption("day").first().click(); | |||
// DayField shouldn't react, MonthField should check that the value | |||
// matches resolution but not trigger a ValueChangeEvent | |||
assertEquals("Unexpected log row", | |||
"5. MonthField set value 2021-02-01 00:00:00", getLogRow(0)); | |||
// change both to month resolution | |||
$(ButtonElement.class).caption("month").first().click(); | |||
// both fields should check that the value matches resolution but only | |||
// DayField should trigger a ValueChangeEvent | |||
assertEquals("Unexpected log row", | |||
"6. MonthField set value 2021-02-01 00:00:00", getLogRow(2)); | |||
assertEquals("Unexpected log row", | |||
"7. DayField set value 2021-02-01 00:00:00", getLogRow(1)); | |||
assertEquals("Unexpected log row", | |||
"8. DayField value change event: 2021-02-01 00:00:00", | |||
getLogRow(0)); | |||
} | |||
} |