diff --git a/src/org/labkey/test/components/domain/DomainFieldRow.java b/src/org/labkey/test/components/domain/DomainFieldRow.java index 10f80dbe33..2dedc18a65 100644 --- a/src/org/labkey/test/components/domain/DomainFieldRow.java +++ b/src/org/labkey/test/components/domain/DomainFieldRow.java @@ -15,10 +15,11 @@ import org.labkey.test.components.html.SelectWrapper; import org.labkey.test.components.react.FilteringReactSelect; import org.labkey.test.components.ui.ontology.ConceptPickerDialog; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.labkey.test.pages.core.admin.BaseSettingsPage.TIME_FORMAT; import org.labkey.test.params.FieldDefinition; import org.labkey.test.util.LabKeyExpectedConditions; import org.openqa.selenium.ElementNotInteractableException; -import org.openqa.selenium.Keys; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.SearchContext; import org.openqa.selenium.WebDriver; @@ -146,12 +147,8 @@ public DomainFieldRow setType(FieldDefinition.ColumnType columnType, boolean con public ModalDialog setTypeWithDialog(FieldDefinition.ColumnType columnType) { elementCache().fieldTypeSelectInput.selectByVisibleText(columnType.getLabel()); - - ModalDialog confirmDialog = new ModalDialog.ModalDialogFinder(getDriver()) + return new ModalDialog.ModalDialogFinder(getDriver()) .withTitle("Confirm Data Type Change").timeout(1000).waitFor(); - - return confirmDialog; - } public boolean getRequiredField() @@ -412,29 +409,19 @@ public DomainFieldRow setFormat(String formatString, @Nullable String dataType) { expand(); - if (!StringUtils.isEmpty(dataType)) + + if (FieldDefinition.ColumnType.DateAndTime.getRangeURI().equals(dataType) || + FieldDefinition.ColumnType.Date.getRangeURI().equals(dataType) || + (FieldDefinition.ColumnType.Time.getRangeURI().equals(dataType))) { - if (FieldDefinition.ColumnType.DateAndTime.getRangeURI().equals(dataType)) - { - setDateTimeFormat(formatString); - return this; - } - if (FieldDefinition.ColumnType.Date.getRangeURI().equals(dataType)) - { - setDateFormat(formatString); - return this; - } - if (FieldDefinition.ColumnType.Time.getRangeURI().equals(dataType)) - { - setTimeFormat(formatString); - return this; - } + throw new UnsupportedOperationException("Setting the format for Date, Time or DateTime fields not supported in this method."); } - if(elementCache().formatInput.getComponentElement().isDisplayed()) + + if (elementCache().formatInput.getComponentElement().isDisplayed()) { elementCache().formatInput.setValue(formatString); } - else if(elementCache().charScaleInput.getComponentElement().isDisplayed()) + else if (elementCache().charScaleInput.getComponentElement().isDisplayed()) { // Formatting of Boolean types use the scale input. elementCache().charScaleInput.setValue(formatString); @@ -1303,67 +1290,93 @@ public boolean isDateTimeInherited() return elementCache().dateTimeInheritedCheckbox.get(); } - public String getDateTimeFormatDate() + public DomainFieldRow setDateTimeFormat(DATE_FORMAT date, TIME_FORMAT time) { - return getFormatWithoutExample(elementCache().dateTimeFormatDateSelect.getValue()); + setDateTimeFormat(date); + setDateTimeFormat(time); + return this; } - public DomainFieldRow setDateTimeFormatDate(String dateFormat) + public DomainFieldRow setDateTimeFormat(DATE_FORMAT dateFormat) { expand(); if (isDateTimeInherited()) setDateTimeInherited(false); - elementCache().dateTimeFormatDateSelect.typeAheadSelect(dateFormat + " ("); + + String txt; + + if (dateFormat.equals(DATE_FORMAT.DATETIME)) + { + txt = dateFormat.toString(); + } + else + { + txt = dateFormat + " ("; + } + + elementCache().dateTimeFormatDateSelect.typeAheadSelect(txt); return this; } - public DomainFieldRow setDateTimeFormatTime(String timeFormat) + public DomainFieldRow setDateTimeFormat(TIME_FORMAT timeFormat) { expand(); if (isDateTimeInherited()) setDateTimeInherited(false); - elementCache().dateTimeFormatTimeSelect.typeAheadSelect(timeFormat + " ("); + elementCache().dateTimeFormatTimeSelect.typeAheadSelect(TIME_FORMAT.none.equals(timeFormat) ? timeFormat.toString() : timeFormat + " ("); return this; } - public String getDateTimeFormatTime() + public String getDateTimeFormatDate() { - return getFormatWithoutExample(elementCache().dateTimeFormatTimeSelect.getValue()); + String formatValue; + + if(elementCache().dateTimeFormatDateSelect.isInteractive()) + { + formatValue = getFormatWithoutExample(elementCache().dateTimeFormatDateSelect.getValue()); + } + else + { + formatValue = getFormatWithoutExample(elementCache().disabledDateTimeDateFormat.getText()); + } + + return formatValue; } - public String getDateTimeFormat() + public boolean isDateTimeFormatDateEnabled() { - String date = getDateTimeFormatDate(); - String time = getDateTimeFormatTime(); - if ("".equals(time)) - time = null; - if (StringUtils.isEmpty(time)) - return date; - - return date + " " + time; + return elementCache().dateTimeFormatDateSelect.isInteractive(); } - public DomainFieldRow setDateTimeFormat(String dateTime) + public String getDateTimeFormatTime() { - expand(); - if (isDateTimeInherited()) - setDateTimeInherited(false); + String formatValue; + + if(elementCache().dateTimeFormatTimeSelect.isInteractive()) + { + formatValue = getFormatWithoutExample(elementCache().dateTimeFormatTimeSelect.getValue()); + } + else + { + formatValue = getFormatWithoutExample(elementCache().disabledDateTimeTimeFormat.getText()); + } - String[] parts = dateTime.split("\\s+", 2); - if (parts.length == 2) - return setDateTimeFormat(parts[0], parts[1]); - return setDateTimeFormat(parts[0], ""); + return formatValue; } - public DomainFieldRow setDateTimeFormat(String date, String time) + public boolean isDateTimeFormatTimeEnabled() { - expand(); - if (isDateTimeInherited()) - setDateTimeInherited(false); + return elementCache().dateTimeFormatTimeSelect.isInteractive(); + } - elementCache().dateTimeFormatDateSelect.typeAheadSelect(date + " ("); - elementCache().dateTimeFormatTimeSelect.typeAheadSelect("".equals(time) ? time : time + " ("); - return this; + public String getDateTimeFormat() + { + String date = getDateTimeFormatDate(); + String time = getDateTimeFormatTime(); + if (TIME_FORMAT.none.toString().equals(time) || StringUtils.isEmpty(time)) + return date; + + return date + " " + time; } public DomainFieldRow setDateInherited(boolean check) @@ -1380,15 +1393,42 @@ public boolean isDateInherited() public String getDateFormat() { - return getFormatWithoutExample(elementCache().dateFormatSelect.getValue()); + String formatValue; + + if(elementCache().dateFormatSelect.isInteractive()) + { + formatValue = getFormatWithoutExample(elementCache().dateFormatSelect.getValue()); + } + else + { + formatValue = getFormatWithoutExample(elementCache().disabledDateFormat.getText()); + } + + return formatValue; + } + + public boolean isDateFormatEnabled() + { + return elementCache().dateFormatSelect.isInteractive(); } - public DomainFieldRow setDateFormat(String dateFormat) + public DomainFieldRow setDateFormat(DATE_FORMAT dateFormat) { expand(); if (isDateInherited()) setDateInherited(false); - elementCache().dateFormatSelect.typeAheadSelect(dateFormat + " ("); + + String txt; + if (dateFormat.equals(DATE_FORMAT.DATE)) + { + txt = dateFormat.toString(); + } + else + { + txt = dateFormat + " ("; + } + elementCache().dateFormatSelect.typeAheadSelect(txt); + return this; } @@ -1406,18 +1446,56 @@ public boolean isTimeInherited() public String getTimeFormat() { - return getFormatWithoutExample(elementCache().timeFormatSelect.getValue()); + String formatValue; + + if(elementCache().timeFormatSelect.isInteractive()) + { + formatValue = getFormatWithoutExample(elementCache().timeFormatSelect.getValue()); + } + else + { + formatValue = getFormatWithoutExample(elementCache().disabledTimeFormat.getText()); + } + + return formatValue; } - public DomainFieldRow setTimeFormat(String timeFormat) + public boolean isTimeFormatEnabled() + { + return elementCache().timeFormatSelect.isInteractive(); + } + + public DomainFieldRow setTimeFormat(TIME_FORMAT timeFormat) { expand(); if (isTimeInherited()) setTimeInherited(false); - elementCache().timeFormatSelect.typeAheadSelect(timeFormat + " ("); + + String txt; + + if (timeFormat.equals(TIME_FORMAT.TIME)) + { + txt = timeFormat.toString(); + } + else + { + txt = timeFormat + " ("; + } + + elementCache().timeFormatSelect.typeAheadSelect(txt); return this; } + public boolean hasDomainWarningIcon() + { + return elementCache().domainWarningIcon.isDisplayed(); + } + + public WebElement getDomainWarningIcon() + { + return elementCache().domainWarningIcon; + } + public static class DomainFieldRowFinder extends WebDriverComponentFinder { private final Locator.XPathLocator _baseLocator = Locator.tagWithClassContaining("div", "domain-field-row").withoutClass("domain-floating-hdr"); @@ -1523,15 +1601,25 @@ protected class ElementCache extends WebDriverComponent.ElementCache public final FilteringReactSelect dateTimeFormatDateSelect = FilteringReactSelect.finder(getDriver()) .withNamedInput("domainpropertiesrow-format_datedateTime") .refindWhenNeeded(this); + public final WebElement disabledDateTimeDateFormat = Locator.tagWithAttributeContaining("div", "id", "domainpropertiesrow-format_datedateTime") + .descendant("div[contains(@class,'select-input__single-value--is-disabled')]").findWhenNeeded(this); public final FilteringReactSelect dateTimeFormatTimeSelect = FilteringReactSelect.finder(getDriver()) .withNamedInput("domainpropertiesrow-format_timedateTime") .refindWhenNeeded(this); + public final WebElement disabledDateTimeTimeFormat = Locator.tagWithAttributeContaining("div", "id", "domainpropertiesrow-format_timedateTime") + .descendant("div[contains(@class,'select-input__single-value--is-disabled')]").findWhenNeeded(this); public final FilteringReactSelect dateFormatSelect = FilteringReactSelect.finder(getDriver()) .withNamedInput("domainpropertiesrow-format_datedate") .refindWhenNeeded(this); + public final WebElement disabledDateFormat = Locator.tagWithAttributeContaining("div", "id", "domainpropertiesrow-format_datedate") + .descendant("div[contains(@class,'select-input__single-value--is-disabled')]").findWhenNeeded(this); public final FilteringReactSelect timeFormatSelect = FilteringReactSelect.finder(getDriver()) .withNamedInput("domainpropertiesrow-format_timetime") .refindWhenNeeded(this); + public final WebElement disabledTimeFormat = Locator.tagWithAttributeContaining("div", "id", "domainpropertiesrow-format_timetime") + .descendant("div[contains(@class,'select-input__single-value--is-disabled')]").findWhenNeeded(this); + public final WebElement domainWarningIcon = Locator.tagWithClass("span", "domain-warning-icon") + .findWhenNeeded(this); // lookup field options public final Select lookupContainerSelect = SelectWrapper.Select(Locator.name("domainpropertiesrow-lookupContainer")) diff --git a/src/org/labkey/test/components/domain/DomainFormPanel.java b/src/org/labkey/test/components/domain/DomainFormPanel.java index 49abcf1991..5510089b57 100644 --- a/src/org/labkey/test/components/domain/DomainFormPanel.java +++ b/src/org/labkey/test/components/domain/DomainFormPanel.java @@ -8,6 +8,8 @@ import org.labkey.test.components.html.Checkbox; import org.labkey.test.components.react.ToggleButton; import org.labkey.test.components.ui.grids.ResponsiveGrid; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.labkey.test.pages.core.admin.BaseSettingsPage.TIME_FORMAT; import org.labkey.test.params.FieldDefinition; import org.labkey.test.selenium.WebElementWrapper; import org.openqa.selenium.NoSuchElementException; @@ -125,7 +127,39 @@ private DomainFormPanel editField(DomainFieldRow fieldRow, FieldDefinition field if (fieldDefinition.getLabel() != null) fieldRow.setLabel(fieldDefinition.getLabel()); if (fieldDefinition.getFormat() != null) - fieldRow.setFormat(fieldDefinition.getFormat(), fieldDefinition.getRangeURI()); + { + if (fieldDefinition.getType().equals(FieldDefinition.ColumnType.Date)) + { + fieldRow.setDateFormat(DATE_FORMAT.get(fieldDefinition.getFormat())); + } + else if (fieldDefinition.getType().equals(FieldDefinition.ColumnType.Time)) + { + fieldRow.setTimeFormat(TIME_FORMAT.get(fieldDefinition.getFormat())); + } + else if (fieldDefinition.getType().equals(FieldDefinition.ColumnType.DateAndTime)) + { + + // Identify the part of the format that is the date and the part that is the time. Take into account + // a data format may include spaces (time does not). + String format = fieldDefinition.getFormat().trim(); + int index = format.lastIndexOf(" "); + + if (format.substring(index + 1).contains(":")) + { + fieldRow.setDateTimeFormat( + DATE_FORMAT.get(format.substring(0, index)), + TIME_FORMAT.get(format.substring(index + 1))); + } + else + { + fieldRow.setDateTimeFormat(DATE_FORMAT.get(format)); + } + } + else + { + fieldRow.setFormat(fieldDefinition.getFormat(), fieldDefinition.getRangeURI()); + } + } if (fieldDefinition.getScale() != null) fieldRow.setCharCount(fieldDefinition.getScale()); if (fieldDefinition.getURL() != null) diff --git a/src/org/labkey/test/pages/admin/FolderFormatsPage.java b/src/org/labkey/test/pages/admin/FolderFormatsPage.java new file mode 100644 index 0000000000..b312606638 --- /dev/null +++ b/src/org/labkey/test/pages/admin/FolderFormatsPage.java @@ -0,0 +1,299 @@ +package org.labkey.test.pages.admin; + +import org.labkey.test.Locator; +import org.labkey.test.WebDriverWrapper; +import org.labkey.test.WebTestHelper; +import org.labkey.test.pages.core.admin.BaseSettingsPage; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +public class FolderFormatsPage extends FolderManagementPage +{ + + public FolderFormatsPage(WebDriver driver) + { + super(driver); + } + + public static FolderFormatsPage beginAt(WebDriverWrapper wrapper) + { + return beginAt(wrapper, wrapper.getCurrentContainerPath()); + } + + public static FolderFormatsPage beginAt(WebDriverWrapper wrapper, String containerPath) + { + wrapper.beginAt(WebTestHelper.buildURL("admin", containerPath, "folderSettings")); + return new FolderFormatsPage(wrapper.getDriver()); + } + + private Boolean getInherited(String name) + { + return elementCache().inheritedChk(name).isSelected(); + } + + private void setInherited(String name, boolean enable) + { + if (enable) + checkCheckbox(elementCache().inheritedChk(name)); + else + uncheckCheckbox(elementCache().inheritedChk(name)); + } + + public boolean getDefaultDateDisplayInherited() + { + return getInherited("defaultDateFormatInherited"); + } + + public void setDefaultDateDisplayInherited(boolean enable) + { + setInherited("defaultDateFormatInherited", enable); + } + + public String getDefaultDateDisplay() + { + return getSelectedOptionValue(elementCache().defaultDateFormat); + } + + public void setDefaultDateDisplay(DATE_FORMAT dateFormat) + { + selectOptionByValue(elementCache().defaultDateFormat, dateFormat.toString()); + } + + public boolean defaultDateDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultDateFormat).isDisplayed(); + } + + public void setDefaultDateTimeDisplay(BaseSettingsPage.DATE_FORMAT dateFormat, BaseSettingsPage.TIME_FORMAT timeFormat) + { + setDefaultDateTimeDateDisplay(dateFormat); + setDefaultDateTimeTimeDisplay(timeFormat); + } + + public String getDefaultDateTimeDateDisplay() + { + return getSelectedOptionValue(elementCache().defaultDateTimeDateFormat); + } + + public void setDefaultDateTimeDateDisplay(BaseSettingsPage.DATE_FORMAT dateFormat) + { + selectOptionByValue(elementCache().defaultDateTimeDateFormat, dateFormat.toString()); + } + + public boolean defaultDateTimeDateDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultDateTimeDateFormat).isDisplayed(); + } + + public boolean getDefaultTimeDisplayInherited() + { + return getInherited("defaultTimeFormatInherited"); + } + + public void setDefaultTimeDisplayInherited(boolean enable) + { + setInherited("defaultTimeFormatInherited", enable); + } + + public String getDefaultDateTimeTimeDisplay() + { + return getSelectedOptionValue(elementCache().defaultDateTimeTimeFormat); + } + + public void setDefaultDateTimeTimeDisplay(BaseSettingsPage.TIME_FORMAT timeFormat) + { + selectOptionByValue(elementCache().defaultDateTimeTimeFormat, timeFormat.toString()); + } + + public boolean defaultDateTimeTimeDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultDateTimeTimeFormat).isDisplayed(); + } + + public boolean getDefaultDateTimeDisplayInherited() + { + return getInherited("defaultDateTimeFormatInherited"); + } + + public void setDefaultDateTimeDisplayInherited(boolean enable) + { + setInherited("defaultDateTimeFormatInherited", enable); + } + + public String getDefaultTimeDisplay() + { + return getSelectedOptionValue(elementCache().defaultTimeFormat); + } + + public void setDefaultTimeDisplay(BaseSettingsPage.TIME_FORMAT timeFormat) + { + selectOptionByValue(elementCache().defaultTimeFormat, timeFormat.toString()); + } + + public boolean defaultTimeDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultTimeFormat).isDisplayed(); + } + + public boolean getDefaultNumberDisplayInherited() + { + return getInherited("defaultNumberFormatInherited"); + } + + public void setDefaultNumberDisplayInherited(boolean enable) + { + setInherited("defaultNumberFormatInherited", enable); + } + + public String getDefaultNumberDisplay() + { + return getFormElement(elementCache().defaultNumberFormat); + } + + public void setDefaultNumberDisplay(String numberFormat) + { + setFormElement(elementCache().defaultNumberFormat, numberFormat); + } + + public boolean getAdditionalParsingPatternDatesInherited() + { + return getInherited("extraDateParsingPatternInherited"); + } + + public void setAdditionalParsingPatternDatesInherited(boolean enable) + { + setInherited("extraDateParsingPatternInherited", enable); + } + + public String getAdditionalParsingPatternDates() + { + return getFormElement(elementCache().additionalParsingPatternDates); + } + + public void setAdditionalParsingPatternDates(String pattern) + { + setFormElement(elementCache().additionalParsingPatternDates, pattern); + } + + public boolean getAdditionalParsingPatternDateAndTimeInherited() + { + return getInherited("extraDateTimeParsingPatternInherited"); + } + + public void setAdditionalParsingPatternDateAndTimeInherited(boolean enable) + { + setInherited("extraDateTimeParsingPatternInherited", enable); + } + + public String getAdditionalParsingPatternDateAndTime() + { + return getFormElement(elementCache().additionalParsingPatternDateAndTime); + } + + public void setAdditionalParsingPatternDateAndTime(String pattern) + { + setFormElement(elementCache().additionalParsingPatternDateAndTime, pattern); + } + + public boolean getAdditionalParsingPatternTimesInherited() + { + return getInherited("extraTimeParsingPatternInherited"); + } + + public void setAdditionalParsingPatternTimesInherited(boolean enable) + { + setInherited("extraTimeParsingPatternInherited", enable); + } + + public String getAdditionalParsingPatternTimes() + { + return getFormElement(elementCache().additionalParsingPatternTimes); + } + + public void setAdditionalParsingPatternTimes(String pattern) + { + setFormElement(elementCache().additionalParsingPatternTimes, pattern); + } + + public boolean getRestrictChartingColsInherited() + { + return getInherited("restrictedColumnsEnabledInherited"); + } + + public void setRestrictChartingColsInherited(boolean enable) + { + setInherited("restrictedColumnsEnabledInherited", enable); + } + + public void setRestrictChartingCols(boolean restrict) + { + if (restrict) + checkCheckbox(elementCache().restrictChartingColsChk); + else + uncheckCheckbox(elementCache().restrictChartingColsChk); + } + + public boolean getRestrictChartingCols() + { + return elementCache().restrictChartingColsChk.isSelected(); + } + + public FolderFormatsPage clickSave() + { + clickAndWait(elementCache().saveButton); + clearCache(); + return this; + } + + public FolderFormatsPage clickInheritAll() + { + clickAndWait(elementCache().inheritAll); + clearCache(); + return this; + } + + @Override + protected ElementCache newElementCache() + { + return new ElementCache(); + } + + @Override + protected ElementCache elementCache() + { + return (ElementCache) super.elementCache(); + } + + protected class ElementCache extends FolderManagementPage.ElementCache + { + WebElement inheritedChk(String name) + { + return Locator.checkboxByName(name).findWhenNeeded(this); + } + + WebElement defaultDateFormat = Locator.id("defaultDateFormat").findWhenNeeded(this); + WebElement defaultTimeFormat = Locator.id("defaultTimeFormat").findWhenNeeded(this); + WebElement defaultDateTimeDateFormat = Locator.id("dateSelect").findWhenNeeded(this); + WebElement defaultDateTimeTimeFormat = Locator.id("timeSelect").findWhenNeeded(this); + WebElement formatWarningBanner = Locator.tagWithId("div", "dateFormatWarning").findWhenNeeded(this); + + WebElement nonStandardWarning(WebElement field) + { + String id = field.getAttribute("id"); + String xpath = String.format("//select[@id='%s']/following-sibling::span[@class='has-warning']", id); + return Locator.xpath(xpath).findWhenNeeded(this); + } + + WebElement defaultNumberFormat = Locator.inputByNameContaining("defaultNumberFormat").findWhenNeeded(this); + WebElement additionalParsingPatternDates = Locator.inputByNameContaining("extraDateParsingPattern").findElement(this); + WebElement additionalParsingPatternTimes = Locator.inputByNameContaining("extraTimeParsingPattern").findElement(this); + WebElement additionalParsingPatternDateAndTime = Locator.inputByNameContaining("extraDateTimeParsingPattern").findElement(this); + WebElement restrictChartingColsChk = Locator.checkboxByName("restrictedColumnsEnabled").findWhenNeeded(this); + + WebElement saveButton = Locator.lkButton("Save").findWhenNeeded(this); + WebElement inheritAll = Locator.lkButton("Inherit All").findWhenNeeded(this); + + } + +} diff --git a/src/org/labkey/test/pages/admin/FolderManagementPage.java b/src/org/labkey/test/pages/admin/FolderManagementPage.java index 2b6ee0ff77..3f588c36ba 100644 --- a/src/org/labkey/test/pages/admin/FolderManagementPage.java +++ b/src/org/labkey/test/pages/admin/FolderManagementPage.java @@ -57,6 +57,12 @@ public FileRootsManagementPage goToFilesTab() return new FileRootsManagementPage(getDriver()); } + public FolderFormatsPage goToFormatsTab() + { + selectTab("settings"); + return new FolderFormatsPage(getDriver()); + } + public RConfigurationPage goToRConfigTab() { selectTab("rConfig"); diff --git a/src/org/labkey/test/pages/core/admin/BaseSettingsPage.java b/src/org/labkey/test/pages/core/admin/BaseSettingsPage.java index 043d7c0d45..4ab90f8604 100644 --- a/src/org/labkey/test/pages/core/admin/BaseSettingsPage.java +++ b/src/org/labkey/test/pages/core/admin/BaseSettingsPage.java @@ -11,6 +11,8 @@ import org.openqa.selenium.WebElement; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; public class BaseSettingsPage extends LabKeyPage { @@ -181,7 +183,12 @@ public String getDefaultDateDisplay() public void setDefaultDateDisplay(DATE_FORMAT dateFormat) { - selectOptionByValue(elementCache().defaultDateFormat, dateFormat.format); + selectOptionByValue(elementCache().defaultDateFormat, dateFormat.toString()); + } + + public boolean defaultDateDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultDateFormat).isDisplayed(); } public void setDefaultDateTimeDisplay(DATE_FORMAT dateFormat, TIME_FORMAT timeFormat) @@ -197,7 +204,12 @@ public String getDefaultDateTimeDateDisplay() public void setDefaultDateTimeDateDisplay(DATE_FORMAT dateFormat) { - selectOptionByValue(elementCache().defaultDateTimeDateFormat, dateFormat.format); + selectOptionByValue(elementCache().defaultDateTimeDateFormat, dateFormat.toString()); + } + + public boolean defaultDateTimeDateDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultDateTimeDateFormat).isDisplayed(); } public String getDefaultDateTimeTimeDisplay() @@ -207,7 +219,12 @@ public String getDefaultDateTimeTimeDisplay() public void setDefaultDateTimeTimeDisplay(TIME_FORMAT timeFormat) { - selectOptionByValue(elementCache().defaultDateTimeTimeFormat, timeFormat.format); + selectOptionByValue(elementCache().defaultDateTimeTimeFormat, timeFormat.toString()); + } + + public boolean defaultDateTimeTimeDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultDateTimeTimeFormat).isDisplayed(); } public String getDefaultTimeDisplay() @@ -217,7 +234,12 @@ public String getDefaultTimeDisplay() public void setDefaultTimeDisplay(TIME_FORMAT timeFormat) { - selectOptionByValue(elementCache().defaultTimeFormat, timeFormat.format); + selectOptionByValue(elementCache().defaultTimeFormat, timeFormat.toString()); + } + + public boolean defaultTimeDisplayWarning() + { + return elementCache().nonStandardWarning(elementCache().defaultTimeFormat).isDisplayed(); } public String getDefaultNumberDisplay() @@ -283,6 +305,23 @@ public void setAltLoginPage(String loginPage) setFormElement(elementCache().altLoginPageTxt,loginPage); } + /** + * If the warning banner is present return the text otherwise return an empty string. + * + * @return Text in warning banner, empty string if no banner is present. + */ + public String getFormatWarningMessage() + { + if (elementCache().formatWarningBanner.isDisplayed()) + { + return elementCache().formatWarningBanner.getText(); + } + else + { + return ""; + } + } + public void save() { clickAndWait(elementCache().saveBtn); @@ -325,6 +364,14 @@ protected class ElementCache extends LabKeyPage.ElementCache WebElement defaultTimeFormat = Locator.id("defaultTimeFormat").findWhenNeeded(this); WebElement defaultDateTimeDateFormat = Locator.id("dateSelect").findWhenNeeded(this); WebElement defaultDateTimeTimeFormat = Locator.id("timeSelect").findWhenNeeded(this); + WebElement formatWarningBanner = Locator.tagWithId("div", "dateFormatWarning").findWhenNeeded(this); + + WebElement nonStandardWarning(WebElement field) + { + String id = field.getAttribute("id"); + String xpath = String.format("//select[@id='%s']/following-sibling::span[@class='has-warning']", id); + return Locator.xpath(xpath).findWhenNeeded(this); + } WebElement defaultNumberFormat = Locator.inputByNameContaining("defaultNumberFormat").findWhenNeeded(this); WebElement additionalParsingPatternDates = Locator.inputByNameContaining("extraDateParsingPattern").findWhenNeeded(this); @@ -351,12 +398,19 @@ public enum DATE_FORMAT { yyyy_MM_dd("yyyy-MM-dd"), yyyy_MMM_dd("yyyy-MMM-dd"), + yyyy_MM("yyyy-MM"), dd_MMM_yyyy("dd-MMM-yyyy"), dd_MMM_yy("dd-MMM-yy"), + dd_MM_yyyy("dd-MM-yyyy"), ddMMMyyyy("ddMMMyyyy"), ddMMMyy("ddMMMyy"), + MMddyyyy("MM/dd/yyyy"), + MM_dd_yyyy("MM-dd-yyyy"), + MMMM_dd_yyyy("MMMM dd yyyy"), Default("yyyy-MM-dd"), - DTDefault("yyyy-MM-dd"); + DTDefault("yyyy-MM-dd"), + DATE("Date"), // Valid only in a domain designer. + DATETIME("DATETIME"); // Valid only in a domain designer and only for the date part of a DateTime field. private final String format; @@ -369,6 +423,19 @@ public enum DATE_FORMAT public String toString() { return this.format; } + + private static final Map lookup = new HashMap<>(); + + static { + for (DATE_FORMAT d : DATE_FORMAT.values()) { + lookup.put(d.toString(), d); + } + } + + public static DATE_FORMAT get(String format) { + return lookup.get(format); + } + } public enum TIME_FORMAT @@ -377,8 +444,10 @@ public enum TIME_FORMAT HH_mm("HH:mm"), HH_mm_ss_SSS("HH:mm:ss.SSS"), hh_mm_a("hh:mm a"), + none(""), // Valid only for a DateTime field. Default("HH:mm:ss"), - DTDefault("HH:mm"); + DTDefault("HH:mm"), + TIME("Time"); // Valid only in domain designer. private final String format; @@ -391,6 +460,19 @@ public enum TIME_FORMAT public String toString() { return this.format; } + + private static final Map lookup = new HashMap<>(); + + static { + for (TIME_FORMAT t : TIME_FORMAT.values()) { + lookup.put(t.toString(), t); + } + } + + public static TIME_FORMAT get(String format) { + return lookup.get(format); + } + } } diff --git a/src/org/labkey/test/tests/DataClassTest.java b/src/org/labkey/test/tests/DataClassTest.java index fd2c085cc8..d8adeeddd1 100644 --- a/src/org/labkey/test/tests/DataClassTest.java +++ b/src/org/labkey/test/tests/DataClassTest.java @@ -26,6 +26,8 @@ import org.labkey.test.categories.Daily; import org.labkey.test.components.domain.BaseDomainDesigner; import org.labkey.test.components.domain.DomainFormPanel; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.labkey.test.pages.core.admin.BaseSettingsPage.TIME_FORMAT; import org.labkey.test.pages.experiment.CreateDataClassPage; import org.labkey.test.pages.query.UpdateQueryRowPage; import org.labkey.test.params.FieldDefinition; @@ -304,29 +306,26 @@ public void testDateAndTimeFields() log("Add a date-time field."); String dateTimeField = "DateTime"; - String dateTimeFormat = "ddMMMyyyy hh:mm a"; DomainFormPanel domainFormPanel = createPage.getDomainEditor(); domainFormPanel.manuallyDefineFields(dateTimeField) .setType(FieldDefinition.ColumnType.DateAndTime) - .setDateTimeFormat(dateTimeFormat); + .setDateTimeFormat(DATE_FORMAT.ddMMMyyyy, TIME_FORMAT.hh_mm_a); log("Add a date-only field."); String dateField = "Date"; - String dateFormat = "ddMMMyyyy"; domainFormPanel = createPage.getDomainEditor(); domainFormPanel.addField(dateField) .setType(FieldDefinition.ColumnType.Date) - .setDateFormat(dateFormat); + .setDateFormat(DATE_FORMAT.ddMMMyyyy); log("Add a time-only field."); String timeField = "Time"; - String timeFormat = "hh:mm a"; domainFormPanel = createPage.getDomainEditor(); domainFormPanel.addField(timeField) .setType(FieldDefinition.ColumnType.Time) - .setTimeFormat(timeFormat); + .setTimeFormat(TIME_FORMAT.hh_mm_a); createPage.clickSave(); diff --git a/src/org/labkey/test/tests/DomainDesignerTest.java b/src/org/labkey/test/tests/DomainDesignerTest.java index ff87f6c18d..291c858d6d 100644 --- a/src/org/labkey/test/tests/DomainDesignerTest.java +++ b/src/org/labkey/test/tests/DomainDesignerTest.java @@ -35,6 +35,8 @@ import org.labkey.test.components.domain.RangeValidatorDialog; import org.labkey.test.components.domain.RegexValidatorDialog; import org.labkey.test.components.domain.RegexValidatorPanel; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.labkey.test.pages.core.admin.BaseSettingsPage.TIME_FORMAT; import org.labkey.test.pages.experiment.CreateSampleTypePage; import org.labkey.test.pages.list.EditListDefinitionPage; import org.labkey.test.params.FieldDefinition; @@ -311,7 +313,7 @@ public void testAddDomainField() throws Exception domainFormPanel.addField("addedField") .setType(FieldDefinition.ColumnType.DateAndTime) .expand() - .setDateTimeFormat("yyyy-MM-dd HH:mm") + .setDateTimeFormat(DATE_FORMAT.yyyy_MM_dd, TIME_FORMAT.HH_mm) .setExcludeFromDateShifting(false) .setDescription("simplest date format of all") .setLabel("DateTime"); diff --git a/src/org/labkey/test/tests/ExpTest.java b/src/org/labkey/test/tests/ExpTest.java index e3f706b714..4e6dc9febe 100644 --- a/src/org/labkey/test/tests/ExpTest.java +++ b/src/org/labkey/test/tests/ExpTest.java @@ -27,7 +27,7 @@ import org.labkey.test.categories.FileBrowser; import org.labkey.test.components.domain.DomainFieldRow; import org.labkey.test.components.ui.lineage.LineageGraph; -import org.labkey.test.pages.core.admin.BaseSettingsPage; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; import org.labkey.test.pages.query.QueryMetadataEditorPage; import org.labkey.test.params.FieldDefinition; import org.labkey.test.util.PortalHelper; @@ -140,7 +140,7 @@ public void testSteps() DomainFieldRow domainRow = designerPage.fieldsPanel().getField("Created"); domainRow.setLabel("editedCreated"); domainRow.setDateTimeInherited(false); - domainRow.setDateTimeFormatDate(BaseSettingsPage.DATE_FORMAT.ddMMMyyyy.toString()); + domainRow.setDateTimeFormat(DATE_FORMAT.ddMMMyyyy); designerPage.clickSave(); // Verify that it ended up in the XML version of the metadata diff --git a/src/org/labkey/test/tests/NonStandardDateAndTimeFormatTest.java b/src/org/labkey/test/tests/NonStandardDateAndTimeFormatTest.java new file mode 100644 index 0000000000..1167fb8078 --- /dev/null +++ b/src/org/labkey/test/tests/NonStandardDateAndTimeFormatTest.java @@ -0,0 +1,1343 @@ +package org.labkey.test.tests; + +import org.jetbrains.annotations.Nullable; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.labkey.remoteapi.CommandException; +import org.labkey.remoteapi.Connection; +import org.labkey.test.BaseWebDriverTest; +import org.labkey.test.Locator; +import org.labkey.test.TestTimeoutException; +import org.labkey.test.categories.Daily; +import org.labkey.test.components.domain.DomainFieldRow; +import org.labkey.test.components.domain.DomainFormPanel; +import org.labkey.test.pages.admin.FolderFormatsPage; +import org.labkey.test.pages.admin.FolderManagementPage; +import org.labkey.test.pages.core.admin.BaseSettingsPage; +import org.labkey.test.pages.core.admin.BaseSettingsPage.TIME_FORMAT; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.labkey.test.pages.core.admin.LookAndFeelSettingsPage; +import org.labkey.test.pages.core.admin.ProjectSettingsPage; +import org.labkey.test.pages.experiment.CreateDataClassPage; +import org.labkey.test.pages.list.EditListDefinitionPage; +import org.labkey.test.params.FieldDefinition; +import org.labkey.test.params.experiment.DataClassDefinition; +import org.labkey.test.params.list.IntListDefinition; +import org.labkey.test.params.list.ListDefinition; +import org.labkey.test.util.APIContainerHelper; +import org.labkey.test.util.DataRegionTable; +import org.labkey.test.util.PortalHelper; +import org.labkey.test.util.URLBuilder; +import org.openqa.selenium.WebElement; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@Category({Daily.class}) +public class NonStandardDateAndTimeFormatTest extends BaseWebDriverTest +{ + + private static final String PROJECT_NAME = "Non-Standard Date And Time Formats Test"; + + // No standard Date, Time and DateTime formats set at the project level. + private static final String PROJECT_DATE_FORMAT = "dd/MM/yy"; + private static final String PROJECT_TIME_FORMAT = "K:m:s a Z"; + private static final String PROJECT_DATETIME_FORMAT = "EEEE MMMM dd D yyyy k:mm:s X"; + + // Warning shown on the Validation page for project settings. + private static final List PROJECT_WARNINGS = List.of(String.format("Project default display format for Dates: %s", PROJECT_DATE_FORMAT), + String.format("Project default display format for DateTimes: %s", PROJECT_DATETIME_FORMAT), + String.format("Project default display format for Times: %s", PROJECT_TIME_FORMAT)); + + // Tooltips shown on the various designer pages for non-standard formats. + private static final String TT_NS_DATE = "Non-standard date format."; + private static final String TT_NS_TIME = "Non-standard time format."; + private static final String TT_NS_DATETIME = "Non-standard date-time format."; + + private final PortalHelper _portalHelper = new PortalHelper(this); + + @Override + public List getAssociatedModules() + { + return Arrays.asList("list"); + } + + @Override + protected String getProjectName() + { + return PROJECT_NAME; + } + + @BeforeClass + public static void setupProject() throws IOException, CommandException + { + NonStandardDateAndTimeFormatTest init = (NonStandardDateAndTimeFormatTest)getCurrentTest(); + init.doSetup(); + } + + private void doSetup() throws IOException, CommandException + { + resetSiteSettings(); + _containerHelper.createProject(PROJECT_NAME, null); + goToProjectHome(); + + // Use the API to set non-standard formats for the project. + new APIContainerHelper(this) + .setDateAndTimeFormats(createDefaultConnection(), PROJECT_NAME, + PROJECT_DATE_FORMAT, PROJECT_TIME_FORMAT, PROJECT_DATETIME_FORMAT); + + _portalHelper.addWebPart("Lists"); + _portalHelper.addWebPart("Data Classes"); + + } + + @AfterClass + public static void afterClass() throws IOException, CommandException + { + ((NonStandardDateAndTimeFormatTest) getCurrentTest()).resetSiteSettings(); + } + + @Override + public void doCleanup(boolean afterTest) throws TestTimeoutException + { + + super.doCleanup(afterTest); + + try + { + ((NonStandardDateAndTimeFormatTest) getCurrentTest()).resetSiteSettings(); + } + catch (IOException | CommandException rethrow) + { + throw new RuntimeException(rethrow); + } + } + + private void resetSiteSettings() throws IOException, CommandException + { + log("Reset site settings."); + BaseSettingsPage.resetSettings(createDefaultConnection(), "/"); + } + + @Before + public void preTest() + { + goToProjectHome(); + } + + @Override + protected BrowserType bestBrowser() + { + return BrowserType.CHROME; + } + + /** + *

+ * Test non-standard Date, Time and DateTime format settings at the project level. The non-standard formats are + * set during project creation. + *

+ *

+ * This test will: + *

    + *
  • Validate that the Date, Time and DateTime fields are not inherited.
  • + *
  • Validate the formats are as expected (non-standard)
  • + *
  • Validate the tooltip message.
  • + *
  • Validate the Site Validate report show the project settings.
  • + *
+ *

+ */ + @Test + public void testProjectSettingsPage() + { + + log("Check that the Date, Time and DateTime format fields in the Project Settings page."); + + goToProjectHome(); + ProjectSettingsPage.beginAt(this); + validateSettingsPage(false, PROJECT_DATE_FORMAT, true, + false, PROJECT_TIME_FORMAT, true, + false, PROJECT_DATETIME_FORMAT, "", + true, false); + + log("Check that Site Validation includes warnings from the project settings."); + String scope = String.format("Project: %s", getProjectName()); + validateSiteValidationReport(scope, PROJECT_WARNINGS, true); + + } + + /** + *

+ * Test non-standard Date, Time and DateTime formats with lists. + *

+ *

+ * This test will: + *

    + *
  • Create a list that has non-standard formats set for the fields.
  • + *
  • Create a second list that has fields that inherit from the project settings.
  • + *
  • Import data into the list to validate non-standard formats are used when display the data.
  • + *
  • Validate the designer for fields that do not inherit from the project.
  • + *
  • Validate the designer for fields that are inherited from the project (should see no warnings)
  • + *
  • Check Site Validation report calls out the fields not inherited, but not the inherited fields.
  • + *
+ *

+ * + * @throws IOException Can be thrown by the API creation calls. + * @throws CommandException Can be thrown by the API creation calls. + */ + @Test + public void testLists() throws IOException, CommandException + { + + String listFormat = "List Non-Standard Formats"; + String listInherit = "List Inherit Project Formats"; + String dateCol01 = "Date01"; + String dateCol02 = "Date02"; + String timeCol01 = "Time01"; + String timeCol02 = "Time02"; + String dateTimeCol01 = "DateTime01"; + String dateTimeCol02 = "DateTime02"; + + log(String.format("Create a list named '%s' with various Date, Time and DateTime columns.", listFormat)); + + String nsDateFormat01 = "MMMM dd, yyyy"; // Similar to a standard format, except this has a comma after the dd. + String nsDateFormat02 = "yyyy-w G"; + String nsTimeFormat01 = "hh:mm:ss.ss a"; + String nsTimeFormat02 = "K:mm a z"; + + List listFields = List.of( + new FieldDefinition(dateCol01, FieldDefinition.ColumnType.Date).setFormat(nsDateFormat01), + new FieldDefinition(dateCol02, FieldDefinition.ColumnType.Date).setFormat(nsDateFormat02), + new FieldDefinition(timeCol01, FieldDefinition.ColumnType.Time).setFormat(nsTimeFormat01), + new FieldDefinition(timeCol02, FieldDefinition.ColumnType.Time).setFormat(nsTimeFormat02), + new FieldDefinition(dateTimeCol01, FieldDefinition.ColumnType.DateAndTime).setFormat(String.format("%s %s", nsDateFormat01, nsTimeFormat01)), + new FieldDefinition(dateTimeCol02, FieldDefinition.ColumnType.DateAndTime).setFormat(String.format("%s %s", nsTimeFormat02, nsDateFormat02)) + ); + + createListByAPI(getProjectName(), listFormat, listFields); + + log(String.format("Create a second list named '%s' that inherits formats from the project.", listInherit)); + + listFields = List.of( + new FieldDefinition(dateCol01, FieldDefinition.ColumnType.Date), + new FieldDefinition(timeCol01, FieldDefinition.ColumnType.Time), + new FieldDefinition(dateTimeCol01, FieldDefinition.ColumnType.DateAndTime) + ); + + createListByAPI(getProjectName(), listInherit, listFields); + + log(String.format("Validate the design and data of list '%s' (does not inherit formats).", listFormat)); + goToProjectHome(); + _listHelper.goToList(listFormat); + _listHelper.insertNewRow(Map.of(dateCol01, "4/1/21", + dateCol02, "12/25/19", + timeCol01, "12:32 am", + timeCol02, "14:42", + dateTimeCol01, "May 1, 2005 6:32 pm", + dateTimeCol02, "6/1/24 10:00"), false); + + Map expectedRowValues = Map.of(dateCol01, "April 01, 2021", + dateCol02, "2019-52 AD", + timeCol01, "12:32:00.00 AM", + timeCol02, "2:42 PM PST", + dateTimeCol01, "May 01, 2005 06:32:00.00 PM", + dateTimeCol02, "10:00 AM PDT 2024-22 AD"); + + EditListDefinitionPage listDefinitionPage = _listHelper.goToEditDesign(listFormat); + DomainFormPanel domainEditor = listDefinitionPage.getFieldsPanel(); + + validateFieldsInDesigner(domainEditor, dateCol01, false, FieldDefinition.ColumnType.Date, + nsDateFormat01, TT_NS_DATE); + validateFieldsInDesigner(domainEditor, dateCol02, false, FieldDefinition.ColumnType.Date, + nsDateFormat02, TT_NS_DATE); + validateFieldsInDesigner(domainEditor, timeCol01, false, FieldDefinition.ColumnType.Time, + nsTimeFormat01, TT_NS_TIME); + validateFieldsInDesigner(domainEditor, timeCol02, false, FieldDefinition.ColumnType.Time, + nsTimeFormat02, TT_NS_TIME); + validateFieldsInDesigner(domainEditor, dateTimeCol01, false, FieldDefinition.ColumnType.DateAndTime, + String.format("%s %s", nsDateFormat01, nsTimeFormat01), TT_NS_DATETIME); + validateFieldsInDesigner(domainEditor, dateTimeCol02, false, FieldDefinition.ColumnType.DateAndTime, + String.format("%s %s", nsTimeFormat02, nsDateFormat02), TT_NS_DATETIME); + + validateDataIsFormatted(getProjectName(), listFormat, expectedRowValues); + + log(String.format("Validate the design and data of list '%s' (does inherit formats).", listInherit)); + goToProjectHome(); + _listHelper.goToList(listInherit); + _listHelper.insertNewRow(Map.of(dateCol01, "4/1/21", + timeCol01, "12:32 am", + dateTimeCol01, "May 1, 2005 6:32 pm"), false); + + expectedRowValues = Map.of(dateCol01, "01/04/21", + timeCol01, "0:32:0 AM -0800", + dateTimeCol01, "Sunday May 01 121 2005 18:32:0 -07"); + + listDefinitionPage = _listHelper.goToEditDesign(listInherit); + domainEditor = listDefinitionPage.getFieldsPanel(); + + validateFieldsInDesigner(domainEditor, dateCol01, true, FieldDefinition.ColumnType.Date, + PROJECT_DATE_FORMAT, TT_NS_DATE); + validateFieldsInDesigner(domainEditor, timeCol01, true, FieldDefinition.ColumnType.Time, + PROJECT_TIME_FORMAT, TT_NS_TIME); + validateFieldsInDesigner(domainEditor, dateTimeCol01, true, FieldDefinition.ColumnType.DateAndTime, + PROJECT_DATETIME_FORMAT, TT_NS_DATETIME); + + listDefinitionPage.clickCancel(); + + validateDataIsFormatted(getProjectName(), listInherit, expectedRowValues); + + log("Validate that the Site Validation contains the expected warnings."); + + List expectedWarnings = List.of(String.format("Date property \"lists.%s.%s\": %s", + listFormat, dateCol01, nsDateFormat01), + String.format("Date property \"lists.%s.%s\": %s", + listFormat, dateCol02, nsDateFormat02), + String.format("Time property \"lists.%s.%s\": %s", + listFormat, timeCol01, nsTimeFormat01), + String.format("Time property \"lists.%s.%s\": %s", + listFormat, timeCol02, nsTimeFormat02), + String.format("DateTime property \"lists.%s.%s\": %s %s", + listFormat, dateTimeCol01, nsDateFormat01, nsTimeFormat01), + String.format("DateTime property \"lists.%s.%s\": %s %s", + listFormat, dateTimeCol02, nsTimeFormat02, nsDateFormat02) + ); + + String scope = String.format("Project: %s", getProjectName()); + validateSiteValidationReport(scope, expectedWarnings, true); + + log("Validate that Site Validation does not contain warnings about inherited fields."); + + expectedWarnings = List.of(String.format("Date property \"lists.%s.%s\": %s", + listInherit, dateCol01, nsDateFormat01), + String.format("Time property \"lists.%s.%s\": %s", + listInherit, timeCol01, nsTimeFormat01), + String.format("DateTime property \"lists.%s.%s\": %s %s", + listInherit, dateTimeCol01, nsDateFormat01, nsTimeFormat01) + ); + + validateSiteValidationReport(scope, expectedWarnings, false); + + } + + /** + *

+ * Validate editing Date-Time fields with non-standard formats to standard formats. + *

+ *

+ * This test will: + *

    + *
  • Create a list with a non-standard format.
  • + *
  • Validate the list and fields are called out in the site validation.
  • + *
  • Edit the various fields and change the formats to a standard format.
  • + *
  • Cancel the edit and validate the at the non-standard format is retained.
  • + *
  • Edit again and change the fields to a standard format.
  • + *
  • Validate the list and fields are no longer called out in the Site Validation report.
  • + *
+ *

+ * + * @throws IOException Can be thrown by the API creation calls. + * @throws CommandException Can be thrown by the API creation calls. + */ + @Test + public void testEditDomain() throws IOException, CommandException + { + String listEdit = "List Edit Non-Standard Formats"; + String dateCol = "Date"; + String timeCol = "Time"; + String dateTimeCol = "DateTime"; + + log(String.format("Create a list named '%s' with various Date, Time and DateTime columns.", listEdit)); + + String nsDateFormat = "MMMM dd, yyyy"; + String nsTimeFormat = "hh:mm:ss.ss a"; + + List listFields = List.of( + new FieldDefinition(dateCol, FieldDefinition.ColumnType.Date).setFormat(nsDateFormat), + new FieldDefinition(timeCol, FieldDefinition.ColumnType.Time).setFormat(nsTimeFormat), + new FieldDefinition(dateTimeCol, FieldDefinition.ColumnType.DateAndTime).setFormat(String.format("%s %s", nsDateFormat, nsTimeFormat)) + ); + + createListByAPI(getProjectName(), listEdit, listFields); + + log("Check that Site Validation tags the fields in the list."); + + List expectedWarnings = List.of(String.format("Date property \"lists.%s.%s\": %s", + listEdit, dateCol, nsDateFormat), + String.format("Time property \"lists.%s.%s\": %s", + listEdit, timeCol, nsTimeFormat), + String.format("DateTime property \"lists.%s.%s\": %s %s", + listEdit, dateTimeCol, nsDateFormat, nsTimeFormat)); + + String scope = String.format("Project: %s", getProjectName()); + validateSiteValidationReport(scope, expectedWarnings, true); + + goToProjectHome(); + _listHelper.goToList(listEdit); + EditListDefinitionPage listDefinitionPage = _listHelper.goToEditDesign(listEdit); + + log("Edit the Date, Time and DateTime fields but then cancel out of the edit."); + + DomainFormPanel domainEditor = listDefinitionPage.getFieldsPanel(); + DomainFieldRow fieldRow = domainEditor.getField(dateCol); + fieldRow.expand(); + fieldRow.setDateFormat(DATE_FORMAT.yyyy_MM_dd); + checker().withScreenshot() + .verifyFalse(String.format("Changing '%s' to a standard format should remove the warning icon.", dateCol), + fieldRow.hasDomainWarningIcon()); + + fieldRow = domainEditor.getField(timeCol); + fieldRow.expand(); + fieldRow.setTimeFormat(TIME_FORMAT.HH_mm_ss); + checker().withScreenshot() + .verifyFalse(String.format("Changing '%s' to a standard format should remove the warning icon.", timeCol), + fieldRow.hasDomainWarningIcon()); + + fieldRow = domainEditor.getField(dateTimeCol); + fieldRow.expand(); + fieldRow.setDateTimeFormat(DATE_FORMAT.yyyy_MM_dd, TIME_FORMAT.hh_mm_a); + checker().withScreenshot() + .verifyFalse(String.format("Changing '%s' to a standard format should remove the warning icon.", dateTimeCol), + fieldRow.hasDomainWarningIcon()); + + log("Cancel out of the edit."); + listDefinitionPage.clickCancel(); + + log("Go back to the design page and validate that the non-standard formats are still there."); + listDefinitionPage = _listHelper.goToEditDesign(listEdit); + domainEditor = listDefinitionPage.getFieldsPanel(); + + validateFieldsInDesigner(domainEditor, dateCol, false, FieldDefinition.ColumnType.Date, + nsDateFormat, TT_NS_DATE); + validateFieldsInDesigner(domainEditor, timeCol, false, FieldDefinition.ColumnType.Time, + nsTimeFormat, TT_NS_TIME); + validateFieldsInDesigner(domainEditor, dateTimeCol, false, FieldDefinition.ColumnType.DateAndTime, + String.format("%s %s", nsDateFormat, nsTimeFormat), TT_NS_DATETIME); + + listDefinitionPage.clickCancel(); + + log("Now edit the field to a standard format."); + listDefinitionPage = _listHelper.goToEditDesign(listEdit); + + domainEditor = listDefinitionPage.getFieldsPanel(); + fieldRow = domainEditor.getField(dateCol); + fieldRow.expand(); + fieldRow.setDateFormat(DATE_FORMAT.yyyy_MM_dd); + fieldRow = domainEditor.getField(timeCol); + fieldRow.expand(); + fieldRow.setTimeFormat(TIME_FORMAT.HH_mm_ss); + fieldRow = domainEditor.getField(dateTimeCol); + fieldRow.expand(); + fieldRow.setDateTimeFormat(DATE_FORMAT.yyyy_MM_dd, TIME_FORMAT.hh_mm_a); + + listDefinitionPage.clickSave(); + + listDefinitionPage = _listHelper.goToEditDesign(listEdit); + domainEditor = listDefinitionPage.getFieldsPanel(); + + validateFieldsInDesigner(domainEditor, dateCol, false, FieldDefinition.ColumnType.Date, + DATE_FORMAT.yyyy_MM_dd.toString(), null); + validateFieldsInDesigner(domainEditor, timeCol, false, FieldDefinition.ColumnType.Time, + TIME_FORMAT.HH_mm_ss.toString(), null); + validateFieldsInDesigner(domainEditor, dateTimeCol, false, FieldDefinition.ColumnType.DateAndTime, + String.format("%s %s", DATE_FORMAT.yyyy_MM_dd, TIME_FORMAT.hh_mm_a), null); + + log("Check that Site Validation Does not tag the fields in the list after they have been edited."); + + validateSiteValidationReport(scope, expectedWarnings, false); + + } + + /** + *

+ * Validate non-standard Date, Time and DateTime formats in a DataClass + *

+ *

+ * This test will: + *

    + *
  • Create a DataClass with non-standard formats.
  • + *
  • Create a DataClass that inherits non-standard formats from the project settings.
  • + *
  • Add some data to both as a sanity validation that non-standard formats are used.
  • + *
  • Validate the designer scenarios for both DataClasses.
  • + *
+ *

+ * + * @throws IOException Can be thrown by the API creation calls. + * @throws CommandException Can be thrown by the API creation calls. + */ + @Test + public void testDataClass() throws IOException, CommandException + { + String dcFormat = "DC Non-Standard Formats"; + String dcInherit = "DC Inherit Project Formats"; + String dateCol = "Date"; + String timeCol = "Time"; + String dateTimeCol = "DateTime"; + + String nsDateFormat = "MMMM dd, yyyy"; + String nsTimeFormat = "hh:mm:ss.ss a"; + + List fields = List.of( + new FieldDefinition(dateCol, FieldDefinition.ColumnType.Date).setFormat(nsDateFormat), + new FieldDefinition(timeCol, FieldDefinition.ColumnType.Time).setFormat(nsTimeFormat), + new FieldDefinition(dateTimeCol, FieldDefinition.ColumnType.DateAndTime).setFormat(String.format("%s %s", nsDateFormat, nsTimeFormat)) + ); + + log(String.format("Create a Data Class named '%s' with non-standard format fields.", dcFormat)); + + createDataClass(getProjectName(), dcFormat, fields); + + fields = List.of( + new FieldDefinition(dateCol, FieldDefinition.ColumnType.Date), + new FieldDefinition(timeCol, FieldDefinition.ColumnType.Time), + new FieldDefinition(dateTimeCol, FieldDefinition.ColumnType.DateAndTime) + ); + + log(String.format("Create a Data Class named '%s' that inherits non-standard format fields from the project.", dcFormat)); + + createDataClass(getProjectName(), dcInherit, fields); + + log("Add some data to both data classes as a sanity validation of the formats."); + + String bulkData = String.format("%s\t%s\t%s\t%s\n", "Name", dateTimeCol, dateCol, timeCol) + + "A\t12/23/24 14:45\t12/23/24\t14:45\n"; + + Map expectedFormatData = Map.of("Name", "A", + dateTimeCol, "December 23, 2024 02:45:00.00 PM", + dateCol, "December 23, 2024", + timeCol, "02:45:00.00 PM", "Flag", ""); + + Map expectedInheritedData = Map.of("Name", "A", + dateTimeCol, "Monday December 23 358 2024 14:45:0 -08", + dateCol, "23/12/24", + timeCol, "2:45:0 PM -0800", "Flag", ""); + + populateDataClass(getProjectName(), dcFormat, bulkData); + populateDataClass(getProjectName(), dcInherit, bulkData); + + log(String.format("Validate domain designer feedback for '%s'.", dcFormat)); + + goToProjectHome(); + clickAndWait(Locator.linkWithText(dcFormat)); + clickAndWait(Locator.lkButton("Edit Data Class")); + CreateDataClassPage editPage = new CreateDataClassPage(getDriver()); + DomainFormPanel domainEditor = editPage.getDomainEditor(); + + validateFieldsInDesigner(domainEditor, dateCol, + false, FieldDefinition.ColumnType.Date, + nsDateFormat, TT_NS_DATE); + + validateFieldsInDesigner(domainEditor, timeCol, + false, FieldDefinition.ColumnType.Time, + nsTimeFormat, TT_NS_TIME); + + validateFieldsInDesigner(domainEditor, dateTimeCol, + false, FieldDefinition.ColumnType.DateAndTime, + String.format("%s %s", nsDateFormat, nsTimeFormat), TT_NS_DATETIME); + + editPage.clickCancel(); + + log("Validate the data (make sure we still respect non-standard formats)."); + validateDataIsFormatted(getProjectName(), dcFormat, expectedFormatData); + + log("Validate that data sets are reported in Site Validation."); + List expectedWarnings = List.of(String.format("Date property \"exp.data.%s.%s\": %s", + dcFormat, dateCol, nsDateFormat), + String.format("Time property \"exp.data.%s.%s\": %s", + dcFormat, timeCol, nsTimeFormat), + String.format("DateTime property \"exp.data.%s.%s\": %s %s", + dcFormat, dateTimeCol, nsDateFormat, nsTimeFormat)); + + String scope = String.format("Project: %s", getProjectName()); + validateSiteValidationReport(scope, expectedWarnings, true); + + log(String.format("Validate domain designer feedback for '%s'.", dcInherit)); + + goToProjectHome(); + clickAndWait(Locator.linkWithText(dcInherit)); + clickAndWait(Locator.lkButton("Edit Data Class")); + editPage = new CreateDataClassPage(getDriver()); + domainEditor = editPage.getDomainEditor(); + + validateFieldsInDesigner(domainEditor, dateCol, + false, FieldDefinition.ColumnType.Date, + PROJECT_DATE_FORMAT, TT_NS_DATE); + + validateFieldsInDesigner(domainEditor, timeCol, + false, FieldDefinition.ColumnType.Time, + PROJECT_TIME_FORMAT, TT_NS_TIME); + + validateFieldsInDesigner(domainEditor, dateTimeCol, + false, FieldDefinition.ColumnType.DateAndTime, + PROJECT_DATETIME_FORMAT, TT_NS_DATETIME); + + editPage.clickCancel(); + + log("Validate the data (make sure we still respect non-standard formats)."); + validateDataIsFormatted(getProjectName(), dcInherit, expectedInheritedData); + + } + + /** + *

+ * This test will check the scoping of non-standard formats when set at the site and subfolder levels. This test + * creates a separate project to avoid the project settings from changed for the default test project from + * interfering. This test also uses data classes for validation because a data class is visible in subfolders. + *

+ *

+ * This test will: + *

    + *
  • Create a separate project with a subfolder. Project has standard formats.
  • + *
  • Create and populate a data class in the project.
  • + *
  • Create and populate a data class in the subfolder.
  • + *
  • From the subfolder add a record to the data class in the parent folder.
  • + *
  • Change the Date-Time settings at the site level to be non-standard.
  • + *
  • Validate the 'Look and Feel' page for the site.
  • + *
  • Validate the Site Validation report calls out the site settings.
  • + *
  • Change the Date-Time format at the subfolder.
  • + *
  • Validate the 'Formats' page for the subfolder.
  • + *
  • Validate the Site Validation report.
  • + *
  • Validate the data in both data classes is formatted as expected in the subfolder.
  • + *
  • Reset the site settings.
  • + *
  • Validate the Site Validation does not call out the site settings but still calls out the subfolder.
  • + *
  • Validate the 'Look and Feel' page is reset with the default formats.
  • + *
  • Validate the subfolder formats are unchanged.
  • + *
+ * Note: there are periodic checks that the data is formatted as expected at the various levels. + *

+ * + * @throws IOException Can be thrown by the test APIs. + * @throws CommandException Can be thrown by the test APIs. + */ + @Test + public void testScopeFromSiteToSubFolder() throws IOException, CommandException + { + + String folderProject = "Non-Standard Sub-Folder Test"; + String subFolder = "SubFolder_01"; + String subFolderPath = folderProject + "/" + subFolder; + + String dcInProj = "DC In Project Folder"; + String dcInSub = "DC In Sub-Folder"; + String dateCol = "Date"; + String timeCol = "Time"; + String dateTimeCol = "DateTime"; + + log(String.format("Create a project '%s' with standard formatting.", folderProject)); + + _containerHelper.deleteProject(folderProject, false); + _containerHelper.createProject(folderProject, null); + + log(String.format("Create a sub-folder '%s'.", folderProject)); + _containerHelper.createSubfolder(folderProject, subFolder); + + log(String.format("In the parent folder create a DataClass named '%s' with various Date, Time and DateTime columns.", dcInProj)); + + goToProjectHome(folderProject); + _portalHelper.addWebPart("Data Classes"); + + List fields = List.of( + new FieldDefinition(dateCol, FieldDefinition.ColumnType.Date), + new FieldDefinition(timeCol, FieldDefinition.ColumnType.Time), + new FieldDefinition(dateTimeCol, FieldDefinition.ColumnType.DateAndTime) + ); + + createDataClass(folderProject, dcInProj, fields); + + log("Add data to use for format validation."); + String bulkData = String.format("%s\t%s\t%s\t%s\n", "Name", dateTimeCol, dateCol, timeCol) + + "P1\t12/23/24 14:45\t12/23/24\t14:45\n"; + + populateDataClass(folderProject, dcInProj, bulkData); + + log(String.format("In the sub-folder '%s' create a DataClass named '%s' with Date & Time columns.", subFolder, dcInSub)); + + navigateToFolder(folderProject, subFolder); + _portalHelper.addWebPart("Data Classes"); + + fields = List.of( + new FieldDefinition(dateCol, FieldDefinition.ColumnType.Date), + new FieldDefinition(timeCol, FieldDefinition.ColumnType.Time), + new FieldDefinition(dateTimeCol, FieldDefinition.ColumnType.DateAndTime) + ); + + createDataClass(subFolderPath, dcInSub, fields); + + log("Add data to DataClass created in the subfolder as validation."); + + bulkData = String.format("%s\t%s\t%s\t%s\n", "Name", dateTimeCol, dateCol, timeCol) + + "C1\t11/28/24 11:11\t11/28/24\t11:11\n"; + + populateDataClass(subFolderPath, dcInSub, bulkData); + + log("In the subfolder add data to DataClass from the parent folder as validation."); + + populateDataClass(subFolderPath, dcInProj, bulkData); + + log("Change the site setting to be non-standard."); + + String nsSiteDateFormat = "MMMM dd, yyyy"; + String nsSiteTimeFormat = "kk:mm z"; + + changeSiteDateAndTimeFormats(nsSiteDateFormat, nsSiteTimeFormat); + + goToProjectHome(folderProject); + + log("Validate the site 'Look and Feel' page has the correct values, feedback, etc..."); + LookAndFeelSettingsPage lookAndFeelSettingsPage = goToAdminConsole().clickLookAndFeelSettings(); + validateSettingsPage(null, nsSiteDateFormat, true, + null, nsSiteTimeFormat, true, + null, String.format("%s %s", nsSiteDateFormat, nsSiteTimeFormat), "", + true, false); + + if (checker().withScreenshot() + .verifyTrue("The warning banner at the top of the Site Setting page does not contain the expected comment.", + lookAndFeelSettingsPage.getFormatWarningMessage() + .startsWith("Warning: One or more date, time, or date-time display formats are using non-standard patterns."))) + { + WebElement link = Locator.linkWithText("Click here").findWhenNeeded(getDriver()); + if (checker().withScreenshot() + .verifyTrue("'Click here' link is not visible.", link.isDisplayed())) + { + link.click(); + switchToWindow(1); + WebElement banner = Locator.tagWithText("h3", "Date & Number Display Formats").refindWhenNeeded(getDriver()); + checker().withScreenshot() + .verifyTrue("'Click here' link did not navigate as expected.", + waitFor(banner::isDisplayed, 1_000)); + closeExtraWindows(); + } + } + + log("Check that the Site Validation report calls out the site settings."); + + List siteWarnings = List.of(String.format("Site default display format for Dates: %s", nsSiteDateFormat), + String.format("Site default display format for Times: %s", nsSiteTimeFormat), + String.format("Site default display format for DateTimes: %s %s", nsSiteDateFormat, nsSiteTimeFormat)); + + String scope = "Root: /"; + validateSiteValidationReport(scope, siteWarnings, true); + + log(String.format("Validate project settings for '%s' inherit the site settings.", folderProject)); + ProjectSettingsPage.beginAt(this, folderProject); + validateSettingsPage(true, nsSiteDateFormat, false, + true, nsSiteTimeFormat, false, + true, String.format("%s %s", nsSiteDateFormat, nsSiteTimeFormat), "", + false, false); + + log(String.format("Validate subfolder settings for '%s' inherit the site settings.", subFolderPath)); + FolderFormatsPage.beginAt(this, subFolderPath); + validateSettingsPage(true, nsSiteDateFormat, false, + true, nsSiteTimeFormat, false, + true, String.format("%s %s", nsSiteDateFormat, nsSiteTimeFormat), "", + false, false); + + log("Sanity check that the DataClass data is formatted in the project and subfolder."); + Map expectedFormatData = Map.of("Name", "P1", + dateTimeCol, "December 23, 2024 14:45 PST", + dateCol, "December 23, 2024", + timeCol, "14:45 PST", + "Flag", ""); + + validateDataIsFormatted(folderProject, dcInProj, expectedFormatData); + + expectedFormatData = Map.of("Name", "C1", + dateTimeCol, "November 28, 2024 11:11 PST", + dateCol, "November 28, 2024", + timeCol, "11:11 PST", + "Flag", ""); + validateDataIsFormatted(subFolderPath, dcInSub, expectedFormatData); + validateDataIsFormatted(subFolderPath, dcInProj, expectedFormatData); + + log("Change the formats in the subFolder."); + String nsSubDateFormat = "EEEE MMMM dd, yyyy"; + String nsSubTimeFormat = "kk:mm (z)"; + + new APIContainerHelper(this) + .setDateAndTimeFormats(createDefaultConnection(), subFolderPath, + nsSubDateFormat, nsSubTimeFormat, String.format("%s %s", nsSubDateFormat, nsSubTimeFormat)); + + log(String.format("Validate folder settings for '%s' no longer inherit the site settings.", subFolderPath)); + FolderFormatsPage.beginAt(this, subFolderPath); + validateSettingsPage(false, nsSubDateFormat, true, + false, nsSubTimeFormat, true, + false, String.format("%s %s", nsSubDateFormat, nsSubTimeFormat), "", + true, false); + + log("Check the format in the DataClasses"); + expectedFormatData = Map.of("Name", "C1", + dateTimeCol, "Thursday November 28, 2024 11:11 (PST)", + dateCol, "Thursday November 28, 2024", + timeCol, "11:11 (PST)", + "Flag", ""); + validateDataIsFormatted(subFolderPath, dcInSub, expectedFormatData); + validateDataIsFormatted(subFolderPath, dcInProj, expectedFormatData); + + log("Check that the 'Site Validation' report now includes the subfolder."); + List folderWarnings = List.of(String.format("Folder default display format for Dates: %s", nsSubDateFormat), + String.format("Folder default display format for Times: %s", nsSubTimeFormat), + String.format("Folder default display format for DateTimes: %s %s", nsSubDateFormat, nsSubTimeFormat)); + + scope = String.format("Folder: %s", subFolderPath); + validateSiteValidationReport(scope, folderWarnings, true); + + log("Reset the site settings."); + resetSiteSettings(); + + log("Validate 'Look and Feel' page after reset."); + goToAdminConsole().clickLookAndFeelSettings(); + validateSettingsPage(null, DATE_FORMAT.Default.toString(), false, + null, TIME_FORMAT.Default.toString(), false, + null, DATE_FORMAT.DTDefault.toString(), TIME_FORMAT.DTDefault.toString(), + false, false); + + log("Validate site is no longer listed in Site Validation report."); + scope = "Root: /"; + validateSiteValidationReport(scope, siteWarnings, false); + + log(String.format("Validate subfolder settings for '%s' still do not inherit the site settings.", subFolderPath)); + FolderFormatsPage.beginAt(this, subFolderPath); + validateSettingsPage(false, nsSubDateFormat, true, + false, nsSubTimeFormat, true, + false, String.format("%s %s", nsSubDateFormat, nsSubTimeFormat), "", + true, false); + + log("Validate the subfolder still appears in the Site Validation report."); + scope = String.format("Folder: %s", subFolderPath); + validateSiteValidationReport(scope, folderWarnings, true); + + } + + /** + *

+ * Use the text values 'Date', 'Time' and 'DateTime' as the format values in a domain designer. This will use a + * DataClass because its design will be visible in the sub-folder. + *

+ *

+ * This test will: + *

    + *
  • Create a new project and set the Date-Time formats to some standard format.
  • + *
  • Create a sub-folder and set the Date-Time formats to some other standard format.
  • + *
  • Create a DataClass in parent folder.
  • + *
  • Set the date field format to 'Date'.
  • + *
  • Set the time field format to 'Time'.
  • + *
  • Set the DateTime field format to 'DateTime' and 'none'.
  • + *
  • Validate data is formatted as expected in the project.
  • + *
  • In the sub-folder validate the data is formatted by the sub-folder settings.
  • + *
  • Validate that setting the date part of a DateTime field only allows 'none' for the time format part.
  • + *
+ *

+ * + * @throws IOException Can be thrown by helpers that create the folders, etc... + * @throws CommandException Can be thrown by helpers that create the folders, etc... + */ + @Test + public void testTextFormatValueOfDate() throws IOException, CommandException + { + + String folderProject = "Text_Format_Test"; + String subFolder = "SubFolder_01"; + String subFolderPath = folderProject + "/" + subFolder; + + log(String.format("Create a project '%s' with standard formatting.", folderProject)); + + _containerHelper.deleteProject(folderProject, false); + _containerHelper.createProject(folderProject, null); + + log(String.format("Create a sub-folder '%s'.", folderProject)); + _containerHelper.createSubfolder(folderProject, subFolder); + + goToProjectHome(folderProject); + _portalHelper.addWebPart("Data Classes"); + + goToProjectHome(subFolderPath); + _portalHelper.addWebPart("Data Classes"); + + String dcSetFormats = "DC Use Text Format"; + String dcCheckWarnings = "DC Check Warnings"; + + String dateCol = "Date01"; + String timeCol = "Time01"; + String dateTimeCol = "DateTime01"; + + log(String.format("Create a DataClass named '%s' with Date, Time and DateTime columns.", dcSetFormats)); + + List fields = List.of( + new FieldDefinition(dateCol, FieldDefinition.ColumnType.Date), + new FieldDefinition(timeCol, FieldDefinition.ColumnType.Time), + new FieldDefinition(dateTimeCol, FieldDefinition.ColumnType.DateAndTime) + ); + + createDataClass(folderProject, dcSetFormats, fields); + createDataClass(folderProject, dcCheckWarnings, fields); + + log("Add data in the parent folder."); + String bulkData = String.format("%s\t%s\t%s\t%s\n", "Name", dateTimeCol, dateCol, timeCol) + + "P1\t11/11/11 23:11\t11/11/11\t23:11\n"; + + populateDataClass(folderProject, dcSetFormats, bulkData); + + log("Add data to the DataClasses in the subfolder."); + + bulkData = String.format("%s\t%s\t%s\t%s\n", "Name", dateTimeCol, dateCol, timeCol) + + "C1\t11/11/11 23:11\t11/11/11\t23:11\n"; + + populateDataClass(subFolderPath, dcSetFormats, bulkData); + + log("At the project level set the formats to something other than the default values."); + ProjectSettingsPage projectSettingsPage = ProjectSettingsPage.beginAt(this, folderProject); + projectSettingsPage.setDefaultDateDisplayInherited(false); + projectSettingsPage.setDefaultDateDisplay(DATE_FORMAT.dd_MMM_yyyy); + projectSettingsPage.setDefaultTimeDisplayInherited(false); + projectSettingsPage.setDefaultTimeDisplay(TIME_FORMAT.hh_mm_a); + projectSettingsPage.setDefaultDateTimeDisplayInherited(false); + projectSettingsPage.setDefaultDateTimeDisplay(DATE_FORMAT.dd_MMM_yyyy, TIME_FORMAT.hh_mm_a); + projectSettingsPage.save(); + + log("At the sub-folder level set the formats to something different as well."); + FolderFormatsPage folderFormatsPage = FolderManagementPage.beginAt(this, subFolderPath).goToFormatsTab(); + folderFormatsPage.setDefaultDateDisplayInherited(false); + folderFormatsPage.setDefaultDateDisplay(DATE_FORMAT.ddMMMyy); + folderFormatsPage.setDefaultTimeDisplayInherited(false); + folderFormatsPage.setDefaultTimeDisplay(TIME_FORMAT.HH_mm_ss_SSS); + folderFormatsPage.setDefaultDateTimeDisplayInherited(false); + folderFormatsPage.setDefaultDateTimeDisplay(DATE_FORMAT.ddMMMyy, TIME_FORMAT.HH_mm_ss_SSS); + folderFormatsPage.clickSave(); + + log("Go to the project and change the formats in the DataClass."); + goToProjectHome(folderProject); + + log(String.format("For DataClass '%s' in the parent folder, change the formats to use 'Date', 'Time' and 'DateTime'.", dcSetFormats)); + clickAndWait(Locator.linkWithText(dcSetFormats)); + clickAndWait(Locator.lkButton("Edit Data Class")); + CreateDataClassPage editPage = new CreateDataClassPage(getDriver()); + DomainFormPanel domainEditor = editPage.getDomainEditor(); + DomainFieldRow fieldRow = domainEditor.getField(dateCol); + fieldRow.setDateInherited(false); + fieldRow.setDateFormat(DATE_FORMAT.DATE); + fieldRow = domainEditor.getField(timeCol); + fieldRow.setTimeInherited(false); + fieldRow.setTimeFormat(TIME_FORMAT.TIME); + fieldRow = domainEditor.getField(dateTimeCol); + fieldRow.setDateTimeInherited(false); + fieldRow.setDateTimeFormat(DATE_FORMAT.DATETIME, TIME_FORMAT.none); + editPage.clickSave(); + + log("Validate that the values are formatted with the settings in the parent folder."); + + Map expectedFormatData = Map.of("Name", "P1", + dateTimeCol, "11-Nov-2011 11:11 PM", + dateCol, "11-Nov-2011", + timeCol, "11:11 PM", "Flag", ""); + + validateDataIsFormatted(folderProject, dcSetFormats, expectedFormatData); + + log("Check that using the values DATE, TIME and DATETIME do not show up in the validation report."); + // Issue 51491 + List siteWarnings = List.of(String.format("Site default display format for Dates: %s", DATE_FORMAT.DATE), + String.format("Site default display format for Times: %s", TIME_FORMAT.TIME), + String.format("Site default display format for DateTimes: %s %s", DATE_FORMAT.DATETIME, TIME_FORMAT.none)); + + String scope = "Root: /"; + validateSiteValidationReport(scope, siteWarnings, false); + + log(String.format("Go to sub-folder '%s' and validate the data here is formatted according to sub-folder settings.", subFolder)); + + expectedFormatData = Map.of("Name", "C1", + dateTimeCol, "11Nov11 23:11:00.000", + dateCol, "11Nov11", + timeCol, "23:11:00.000", "Flag", ""); + + validateDataIsFormatted(subFolderPath, dcSetFormats, expectedFormatData); + + log("Go back to parent folder and validate warnings for DateTime fields."); + + goToProjectHome(folderProject); + + clickAndWait(Locator.linkWithText(dcCheckWarnings)); + clickAndWait(Locator.lkButton("Edit Data Class")); + editPage = new CreateDataClassPage(getDriver()); + domainEditor = editPage.getDomainEditor(); + fieldRow = domainEditor.getField(dateTimeCol); + fieldRow.setDateTimeInherited(false); + fieldRow.setDateTimeFormat(DATE_FORMAT.DATETIME, TIME_FORMAT.hh_mm_a); + + checker().verifyTrue(String.format("When setting the date part of a DateTime to '%s', '%s' to should be the only allowed value for the time part.", + DATE_FORMAT.DATETIME, TIME_FORMAT.none), + fieldRow.hasDomainWarningIcon()); + + List actualValues = editPage.clickSaveExpectingErrors(); + + List expectedValues = List.of( + String.format("Property %s: %s %s is an illegal format for type DateTime", + dateTimeCol, DATE_FORMAT.DATETIME, TIME_FORMAT.hh_mm_a), + String.format("Please correct errors in %s before saving.", + dcCheckWarnings)); + + checker().verifyEquals("Error messages are not as expected.", + expectedValues, actualValues); + + checker().screenShotIfNewError("Warning_Errors"); + + log("Cancel out of the editor."); + editPage.clickCancel(); + + } + + // Private helper that will create a list through the APIs. This allows the list to have non-standard formats. + private void createListByAPI(String path, String listName, List fields) throws IOException, CommandException + { + Connection connection = createDefaultConnection(); + ListDefinition listDef = new IntListDefinition(listName, "Key"); + for(FieldDefinition field : fields) + { + listDef.addField(field); + } + + listDef.create(connection, path); + } + + private void createDataClass(String path, String dcName, List fields) throws IOException, CommandException + { + log(String.format("Create a Data Class named '%s' in '%s'.", dcName, path)); + + DataClassDefinition dataClass = new DataClassDefinition(dcName); + for(FieldDefinition field : fields) + { + dataClass.addField(field); + } + + dataClass.create(createDefaultConnection(), path); + + } + + private void populateDataClass(String path, String dcName, String importData) + { + goToProjectHome(path); + clickAndWait(Locator.linkWithText(dcName)); + + DataRegionTable dataTable = new DataRegionTable("query", getDriver()); + dataTable.clickImportBulkData() + .setText(importData); + + clickButton("Submit"); + + } + + // Private helper to validate the data in the list or data class is formatted as expected. + private void validateDataIsFormatted(String projectPath, String domainName, Map expectedFormatData) + { + goToProjectHome(projectPath); + clickAndWait(Locator.linkWithText(domainName)); + DataRegionTable dataTable = new DataRegionTable("query", getDriver()); + Map actualData = dataTable.getRowDataAsMap(0); + checker().withScreenshot() + .verifyEquals(String.format("Data in '%s' is not formatted as expected.", domainName), + expectedFormatData, actualData); + + } + + // Private helper to change the Date-Time formats at the site level to non-standard formats. + // This modifies the html of the page to make an option in each field to be of a non-standard format. + private void changeSiteDateAndTimeFormats(String dateFormat, String timeFormat) + { + LookAndFeelSettingsPage lookAndFeelSettingsPage = goToAdminConsole().clickLookAndFeelSettings(); + + log(String.format("Chang date format '%s' to have a value of '%s'.", DATE_FORMAT.ddMMMyy, dateFormat)); + WebElement defaultDate = Locator.id("defaultDateFormat").findElement(getDriver()); + WebElement optionEl = Locator.tagWithAttribute("option", "value", DATE_FORMAT.ddMMMyy.toString()).findElement(defaultDate); + executeScript("arguments[0].value = arguments[1]", optionEl, dateFormat); + selectOptionByValue(defaultDate, dateFormat); + + log(String.format("Chang time format '%s' to have a value of '%s'.", TIME_FORMAT.hh_mm_a, timeFormat)); + WebElement defaultTime = Locator.id("defaultTimeFormat").findElement(getDriver()); + optionEl = Locator.tagWithAttribute("option", "value", TIME_FORMAT.hh_mm_a.toString()).findElement(defaultTime); + executeScript("arguments[0].value = arguments[1]", optionEl, timeFormat); + selectOptionByValue(defaultTime, timeFormat); + + log(String.format("Chang DateTime date format '%s' to have a value of '%s'.", DATE_FORMAT.ddMMMyy, dateFormat)); + WebElement defaultDTDate = Locator.id("dateSelect").findElement(getDriver()); + optionEl = Locator.tagWithAttribute("option", "value", DATE_FORMAT.ddMMMyy.toString()).findElement(defaultDTDate); + executeScript("arguments[0].value = arguments[1]", optionEl, dateFormat); + selectOptionByValue(defaultDTDate, dateFormat); + + log(String.format("Chang DateTime time format '%s' to have a value of '%s'.", TIME_FORMAT.hh_mm_a, timeFormat)); + WebElement defaultDTTime = Locator.id("timeSelect").findElement(getDriver()); + optionEl = Locator.tagWithAttribute("option", "value", TIME_FORMAT.hh_mm_a.toString()).findElement(defaultDTTime); + executeScript("arguments[0].value = arguments[1]", optionEl, timeFormat); + selectOptionByValue(defaultDTTime, timeFormat); + + lookAndFeelSettingsPage.save(); + } + + // Private helper that validates Date, Time and DateTime fields in a domain designer. + // isInherited: Used to check the enabled / editable state of the field. + // columnType: Used to identify the expected field options and messages. + // expectedToolTipText: Used as a check for the warning icon. If null no warning icon is expected. + private void validateFieldsInDesigner(DomainFormPanel domainEditor, String fieldName, + boolean isInherited, FieldDefinition.ColumnType columnType, + String expectedFormat, @Nullable String expectedToolTipText) + { + DomainFieldRow fieldRow = domainEditor.getField(fieldName); + fieldRow.expand(); + + if (FieldDefinition.ColumnType.Date.equals(columnType)) + { + if(isInherited) + { + checker().verifyTrue(String.format("Field '%s' should show as inherited, it does not.", fieldName), + fieldRow.isDateInherited()); + + checker().verifyFalse(String.format("Field '%s' should not be enabled.", fieldName), + fieldRow.isDateFormatEnabled()); + } + + checker().verifyEquals(String.format("Date format for field '%s' not as expected.", fieldName), + expectedFormat, fieldRow.getDateFormat()); + } + else if (FieldDefinition.ColumnType.Time.equals(columnType)) + { + + if(isInherited) + { + checker().verifyTrue(String.format("Field '%s' should show as inherited, it does not.", fieldName), + fieldRow.isTimeInherited()); + + checker().verifyFalse(String.format("Field '%s' should not be enabled.", fieldName), + fieldRow.isTimeFormatEnabled()); + } + + checker().verifyEquals(String.format("Time format for field '%s' not as expected.", fieldName), + expectedFormat, fieldRow.getTimeFormat()); + } + else + { + + if(isInherited) + { + checker().verifyTrue(String.format("Field '%s' should show as inherited, it does not.", fieldName), + fieldRow.isDateTimeInherited()); + + checker().verifyFalse(String.format("Date part of DateTime field '%s' should not be enabled.", fieldName), + fieldRow.isDateTimeFormatDateEnabled()); + + checker().verifyFalse(String.format("Time part of DateTime field '%s' should not be enabled.", fieldName), + fieldRow.isDateTimeFormatTimeEnabled()); + } + + String expectedDateFormat; + String expectedTimeFormat; + + // If expected tooltip text is not null treat the field as a non-standard format field. + if (null != expectedToolTipText) + { + expectedDateFormat = expectedFormat; + expectedTimeFormat = TIME_FORMAT.none.toString(); + } + else + { + // None of the standard dates have a space. The first space will be between the date format and the time format. + int index = expectedFormat.indexOf(" "); + + expectedDateFormat = expectedFormat.substring(0, index); + expectedTimeFormat = expectedFormat.substring(index+1); + } + + checker().verifyEquals(String.format("DateTime Date format for field '%s' not as expected.", fieldName), + expectedDateFormat, fieldRow.getDateTimeFormatDate()); + + checker().verifyEquals(String.format("DateTime Time format for field '%s' not as expected.", fieldName), + expectedTimeFormat, fieldRow.getDateTimeFormatTime()); + } + + // If expected tooltip text is not null treat the field as a non-standard format field. + if (null != expectedToolTipText) + { + if (checker().verifyTrue("No warning icon present for field with non-standard date-time format.", + fieldRow.hasDomainWarningIcon())) + { + WebElement icon = fieldRow.getDomainWarningIcon(); + mouseOver(icon); + WebElement toolTip = Locator.tagWithClass("div", "tooltip-inner") + .withText(expectedToolTipText) + .findWhenNeeded(getDriver()); + + checker().verifyTrue("Tooltip not present or text not as expected.", + waitFor(toolTip::isDisplayed, 1_000)); + } + } + else + { + checker().verifyFalse(String.format("Field '%s' should not have a warning icon present, but one is there.", fieldName), + fieldRow.hasDomainWarningIcon()); + } + + checker().screenShotIfNewError(String.format("Non_Standard_Field_%s_Error", fieldName)); + + } + + // These controls are shared across multiple setting pages. It is easier to find them here in the test than to use + // the page objects. + private String getFormatFromControl(String fieldId) + { + return getSelectedOptionValue(Locator.id(fieldId).findElement(getDriver())); + } + + private boolean getFieldInherited(String fieldName) + { + return Locator.checkboxByName(fieldName).findElement(getDriver()).isSelected(); + } + + private boolean getNonStandardWarning(String fieldId) + { + String xpath = String.format("//select[@id='%s']/following-sibling::span[@class='has-warning']", fieldId); + return Locator.xpath(xpath).findWhenNeeded(getDriver()).isDisplayed(); + } + + // Private helper to check the format settings at the site, project or folder. + // Site settings do not inherit, if the inherited parameter is null that check is skipped. + private void validateSettingsPage(@Nullable Boolean dateInherited, String dateFormat, boolean dateWarning, + @Nullable Boolean timeInherited, String timeFormat, boolean timeWarning, + @Nullable Boolean dateTimeInherited, String dtDateFormat, String dtTimeFormat, + boolean dtDateWarning, boolean dtTimeWarning) + { + + log("Check Date field settings."); + + checker().verifyEquals("Format of Default Date is not as expected.", + dateFormat, getFormatFromControl("defaultDateFormat")); + + if (null != dateInherited) + { + checker().verifyEquals("Inherited value for Date format not as expected.", + dateInherited, getFieldInherited("defaultDateFormatInherited")); + } + + checker().verifyEquals("Non-standard warning for Date field not as expected.", + dateWarning, getNonStandardWarning("defaultDateFormat")); + + + log("Check Time field settings."); + + checker().verifyEquals("Format of Default Time is not as expected.", + timeFormat, getFormatFromControl("defaultTimeFormat")); + + if (null != timeInherited) + { + checker().verifyEquals("Inherited value for Time format not as expected.", + timeInherited, getFieldInherited("defaultTimeFormatInherited")); + } + + checker().verifyEquals("Non-standard warning for Time field not as expected.", + timeWarning, getNonStandardWarning("defaultTimeFormat")); + + + log("Check DateTime field settings."); + + checker().verifyEquals("Format of Default DateTime (Date) is not as expected.", + dtDateFormat, getFormatFromControl("dateSelect")); + + checker().verifyEquals("Format of Default DateTime (Time) is not as expected.", + dtTimeFormat, getFormatFromControl("timeSelect")); + + if (null != dateTimeInherited) + { + checker().verifyEquals("Inherited value for DateTime format not as expected.", + dateTimeInherited, getFieldInherited("defaultDateTimeFormatInherited")); + } + + checker().verifyEquals("Non-standard warning for DateTime (Date) not as expected.", + dtDateWarning, getNonStandardWarning("dateSelect")); + + checker().verifyEquals("Non-standard warning for DateTime (Time) not as expected.", + dtTimeWarning, getNonStandardWarning("timeSelect")); + + checker().screenShotIfNewError("Settings_Page_Error"); + } + + // Private helper to check the Site Validation report. Checks to see if the report should, or should not, contain + // the list of warnings. + private void validateSiteValidationReport(String scope, List expectedWarnings, boolean shouldContain) + { + List actualWarnings = getProjectValidationWarnings(scope); + + log("Found Warnings: " + actualWarnings); + + if (shouldContain) + { + log("Should Contain Warnings: " + expectedWarnings); + + if (checker().withScreenshot() + .verifyFalse(String.format("Found no Site Validation warnings under '%s'.", scope), + actualWarnings.isEmpty())) + { + checker().verifyTrue("Did not find the expected warnings in the 'Site Validation' report.", + actualWarnings.containsAll(expectedWarnings)); + + } + } + else + { + log("Should Not Contain Warnings: " + expectedWarnings); + + boolean shouldBeFalse = actualWarnings.stream() + .anyMatch(expectedWarnings::contains); + + checker().withScreenshot() + .verifyFalse("Found Site Validation warning(s) that should not be there.", + shouldBeFalse); + } + + checker().screenShotIfNewError("Site_Validation_Error"); + } + + // Private helper that gets the data from the Site Validation page, narrowed to the scope provided, and cleans it up a bit. + private List getProjectValidationWarnings(String scope) + { + + URLBuilder urlBuilder = new URLBuilder("admin", "configureSiteValidation"); + String url = urlBuilder.buildRelativeURL(); + beginAt(url); + + waitForElementToBeVisible(Locator.lkButton("Validate")); + + // Disable all validators. + Locator.tagWithAttribute("input", "type", "checkbox") + .findElements(getDriver()).forEach(this::uncheckCheckbox); + + // Enable Display Format validator. + WebElement formatValidation = Locator.checkboxByNameAndValue("providers", "Display Format Validator").findWhenNeeded(getDriver()); + checkCheckbox(formatValidation); + + // Validate projects and sub-folders. + checkRadioButton(Locator.radioButtonByNameAndValue("includeSubfolders", "true")); + + // Don't run in the background. + uncheckCheckbox(Locator.id("background")); + + clickAndWait(Locator.lkButton("Validate")); + + waitForText("Folder Validation Results"); + + String xpath = String.format("//li[contains(text(),'%s')]//li[contains(text(),'Warnings:')]//ul", scope); + WebElement ul = Locator.xpath(xpath).findWhenNeeded(getDriver()); + + List warnings = new ArrayList<>(); + int linkTextLength = " more info".length(); + + if (ul.isDisplayed()) + { + // Get the text of the warnings and trim off the 'More Info' link. + warnings = ul.findElements(Locator.tag("li")) + .stream() + .map(el->el.getText().trim().substring(0, el.getText().length() - linkTextLength)).toList(); + } + + return warnings; + } + +} diff --git a/src/org/labkey/test/tests/ProjectSettingsTest.java b/src/org/labkey/test/tests/ProjectSettingsTest.java index 63b27805cf..1de201af03 100644 --- a/src/org/labkey/test/tests/ProjectSettingsTest.java +++ b/src/org/labkey/test/tests/ProjectSettingsTest.java @@ -17,7 +17,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.labkey.remoteapi.CommandException; @@ -28,12 +27,15 @@ import org.labkey.test.components.html.BootstrapMenu; import org.labkey.test.components.html.SiteNavBar; import org.labkey.test.pages.core.admin.BaseSettingsPage; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.labkey.test.pages.core.admin.BaseSettingsPage.TIME_FORMAT; import org.labkey.test.pages.core.admin.LookAndFeelSettingsPage; import org.labkey.test.pages.core.admin.ProjectSettingsPage; import org.labkey.test.params.FieldDefinition; import org.labkey.test.params.FieldDefinition.ColumnType; import org.labkey.test.params.list.IntListDefinition; import org.labkey.test.params.list.ListDefinition; +import org.labkey.test.util.APIContainerHelper; import org.labkey.test.util.DataRegionTable; import org.labkey.test.util.PortalHelper; import org.labkey.test.util.TestDataGenerator; @@ -55,8 +57,8 @@ public class ProjectSettingsTest extends BaseWebDriverTest { - private static final BaseSettingsPage.DATE_FORMAT DEFAULT_DATE_FORMAT = BaseSettingsPage.DATE_FORMAT.Default; - private static final BaseSettingsPage.TIME_FORMAT DEFAULT_TIME_FORMAT = BaseSettingsPage.TIME_FORMAT.Default; + private static final DATE_FORMAT DEFAULT_DATE_FORMAT = DATE_FORMAT.Default; + private static final TIME_FORMAT DEFAULT_TIME_FORMAT = TIME_FORMAT.Default; private static final String INJECT_CHARS = ""; @@ -125,8 +127,8 @@ private boolean checkDataInList(String projectName, String listName, List> lis public void testSiteSettingOverride() throws IOException, CommandException { - BaseSettingsPage.DATE_FORMAT dateDisplay = BaseSettingsPage.DATE_FORMAT.yyyy_MMM_dd; - BaseSettingsPage.TIME_FORMAT timeDisplay = BaseSettingsPage.TIME_FORMAT.hh_mm_a; - BaseSettingsPage.DATE_FORMAT dtDateDisplay = BaseSettingsPage.DATE_FORMAT.dd_MMM_yy; - BaseSettingsPage.TIME_FORMAT dtTimeDisplay = BaseSettingsPage.TIME_FORMAT.hh_mm_a; + DATE_FORMAT dateDisplay = DATE_FORMAT.yyyy_MMM_dd; + TIME_FORMAT timeDisplay = TIME_FORMAT.hh_mm_a; + DATE_FORMAT dtDateDisplay = DATE_FORMAT.dd_MMM_yy; + TIME_FORMAT dtTimeDisplay = TIME_FORMAT.hh_mm_a; boolean siteHelpMenuState = false; String siteSupportLink = ""; @@ -304,7 +306,7 @@ public void testSiteSettingOverride() throws IOException, CommandException projectSettingsPage.setSupportLink(supportLink); projectSettingsPage.setDefaultDateDisplayInherited(false); - projectSettingsPage.setDefaultDateDisplay(BaseSettingsPage.DATE_FORMAT.yyyy_MM_dd); + projectSettingsPage.setDefaultDateDisplay(DATE_FORMAT.yyyy_MM_dd); projectSettingsPage.setDefaultTimeDisplayInherited(false); projectSettingsPage.setDefaultTimeDisplay(DEFAULT_TIME_FORMAT); @@ -335,30 +337,45 @@ public void testSiteSettingOverride() throws IOException, CommandException resetProjectSettings(); } - // The injectionTest needs to be changed to an API tests. - // That will be done in another story along with the non-standard tests. - @Ignore @Test public void testInjection() throws IOException, CommandException { resetSiteSettings(); resetProjectSettings(); + String dateFormatInjection = DATE_FORMAT.yyyy_MM_dd + "'" + INJECT_CHARS + "'"; + String timeFormatInjection = TIME_FORMAT.HH_mm + "'" + INJECT_CHARS + "'"; + + new APIContainerHelper(this).setDateAndTimeFormats(createDefaultConnection(), PROJ_CHANGE, + dateFormatInjection, timeFormatInjection, String.format("%s %s", dateFormatInjection, timeFormatInjection)); + var projectSettingPage = ProjectSettingsPage.beginAt(this, PROJ_CHANGE); -// projectSettingPage.setDefaultDateTimeDisplay(DT_DATE_FORMAT_INJECTION, DT_TIME_FORMAT_INJECTION); - projectSettingPage.save(); + log("DateTime format: " + projectSettingPage.getDefaultDateTimeDateDisplay() + " " + projectSettingPage.getDefaultDateTimeTimeDisplay()); + log("Date format: " + projectSettingPage.getDefaultDateDisplay()); + log("Time format: " + projectSettingPage.getDefaultTimeDisplay()); _listHelper.createList(getProjectName(), "IceCream", "IceCreamID", - new FieldDefinition("IceCreamDate", ColumnType.DateAndTime)); + new FieldDefinition("IceCreamDateTime", ColumnType.DateAndTime), + new FieldDefinition("IceCreamDate", ColumnType.Date), + new FieldDefinition("IceCreamTime", ColumnType.Time)); + goToProjectHome(); clickAndWait(Locator.linkWithText("IceCream")); Map testRow = new HashMap<>(); - String testDate = "1800-05-10 10:32"; + String testDate = "1800-05-10"; + String testTime = "10:32"; + String testDateTime = String.format("%s %s", testDate, testTime); + testRow.put("IceCreamDateTime", testDateTime); testRow.put("IceCreamDate", testDate); + testRow.put("IceCreamTime", testTime); _listHelper.insertNewRow(testRow); DataRegionTable list = new DataRegionTable("query", getDriver()); String attemptedInjection = list.getDataAsText(0, 0); - assertEquals("Wrong list data from injection attempt", testDate + INJECT_CHARS, attemptedInjection); + assertEquals("Wrong list data from DateTime injection attempt", testDate + INJECT_CHARS + " " + testTime + INJECT_CHARS, attemptedInjection); + attemptedInjection = list.getDataAsText(0, 1); + assertEquals("Wrong list data from Date injection attempt", testDate + INJECT_CHARS, attemptedInjection); + attemptedInjection = list.getDataAsText(0, 2); + assertEquals("Wrong list data from Time injection attempt", testTime + INJECT_CHARS, attemptedInjection); } @Override diff --git a/src/org/labkey/test/tests/ReportAndDatasetNotificationTest.java b/src/org/labkey/test/tests/ReportAndDatasetNotificationTest.java index 5a13c45003..24f4872d7d 100644 --- a/src/org/labkey/test/tests/ReportAndDatasetNotificationTest.java +++ b/src/org/labkey/test/tests/ReportAndDatasetNotificationTest.java @@ -15,11 +15,8 @@ */ package org.labkey.test.tests; -import org.json.JSONObject; import org.junit.experimental.categories.Category; import org.labkey.remoteapi.CommandException; -import org.labkey.remoteapi.Connection; -import org.labkey.remoteapi.SimplePostCommand; import org.labkey.test.BaseWebDriverTest; import org.labkey.test.Locator; import org.labkey.test.TestFileUtils; @@ -31,6 +28,7 @@ import org.labkey.test.components.dumbster.EmailRecordTable; import org.labkey.test.components.html.BootstrapMenu; import org.labkey.test.pages.TimeChartWizard; +import org.labkey.test.util.APIContainerHelper; import org.labkey.test.util.Ext4Helper; import org.labkey.test.util.LogMethod; import org.labkey.test.util.PortalHelper; @@ -171,15 +169,9 @@ protected void verifyContentModified() throws IOException, CommandException // This test depends on a non-standard date format, one that contains a timestamp, to validate the reports are // shown as updated. The non-standard format can only be set by an API call to UpdateContainerSettings. - Connection cn = createDefaultConnection(); - SimplePostCommand command = new SimplePostCommand("admin", "UpdateContainerSettings"); - JSONObject json = new JSONObject(); - json.put("defaultDateFormat", NON_STANDARD_DATEFORMAT); - json.put("defaultDateFormatInherited", false); - json.put("defaultDateTimeFormatInherited", true); - json.put("defaultTimeFormatInherited", true); - command.setJsonObject(json); - command.execute(cn, getCurrentContainerPath()); + APIContainerHelper apiContainerHelper = new APIContainerHelper(this); + apiContainerHelper.setDateAndTimeFormats(createDefaultConnection(), getCurrentContainerPath(), + NON_STANDARD_DATEFORMAT, null, null); clickTab("Clinical and Assay Data"); waitForElement(Locator.linkWithText("GenericAssay")); diff --git a/src/org/labkey/test/tests/SimpleModuleTest.java b/src/org/labkey/test/tests/SimpleModuleTest.java index 91771335e9..548beb4fd4 100644 --- a/src/org/labkey/test/tests/SimpleModuleTest.java +++ b/src/org/labkey/test/tests/SimpleModuleTest.java @@ -233,7 +233,7 @@ protected void doSetup() ProjectSettingsPage projectSettingsPage = goToProjectSettings(); projectSettingsPage.setDefaultDateTimeDisplayInherited(false); - projectSettingsPage.setDefaultDateTimeDisplay(BaseSettingsPage.DATE_FORMAT.yyyy_MM_dd, BaseSettingsPage.TIME_FORMAT.Default); + projectSettingsPage.setDefaultDateTimeDisplay(BaseSettingsPage.DATE_FORMAT.MMMM_dd_yyyy, BaseSettingsPage.TIME_FORMAT.Default); projectSettingsPage.save(); // images for thumbnails diff --git a/src/org/labkey/test/tests/list/ListDateAndTimeTest.java b/src/org/labkey/test/tests/list/ListDateAndTimeTest.java index 77751cbf46..756df52ae5 100644 --- a/src/org/labkey/test/tests/list/ListDateAndTimeTest.java +++ b/src/org/labkey/test/tests/list/ListDateAndTimeTest.java @@ -22,6 +22,8 @@ import org.labkey.test.components.domain.DomainFormPanel; import org.labkey.test.pages.ImportDataPage; import org.labkey.test.pages.core.admin.BaseSettingsPage; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; +import org.labkey.test.pages.core.admin.BaseSettingsPage.TIME_FORMAT; import org.labkey.test.pages.core.admin.LookAndFeelSettingsPage; import org.labkey.test.pages.list.EditListDefinitionPage; import org.labkey.test.params.FieldDefinition; @@ -79,6 +81,7 @@ private void doSetup() throws IOException, CommandException _defaultTimeFormat = new SimpleDateFormat(settingsPage.getDefaultTimeDisplay()); _defaultDateTimeFormat = new SimpleDateFormat(String.format("%s %s", settingsPage.getDefaultDateTimeDateDisplay(), settingsPage.getDefaultDateTimeTimeDisplay())); + } @AfterClass @@ -1116,10 +1119,10 @@ public void testInvalidDateAndTimeInsert() throws IOException, CommandException @Test public void testDateAndTimeFormat() throws IOException, CommandException { - BaseSettingsPage.DATE_FORMAT dateFormat01 = BaseSettingsPage.DATE_FORMAT.Default; - BaseSettingsPage.TIME_FORMAT timeFormat01 = BaseSettingsPage.TIME_FORMAT.hh_mm_a; + DATE_FORMAT dateFormat01 = DATE_FORMAT.Default; + TIME_FORMAT timeFormat01 = TIME_FORMAT.hh_mm_a; String dateTimeFormat01 = String.format("%s %s", - BaseSettingsPage.DATE_FORMAT.Default, BaseSettingsPage.TIME_FORMAT.hh_mm_a); + DATE_FORMAT.Default, TIME_FORMAT.hh_mm_a); SimpleDateFormat formatterDate = new SimpleDateFormat(dateFormat01.toString()); SimpleDateFormat formatterTime = new SimpleDateFormat(timeFormat01.toString()); @@ -1201,13 +1204,14 @@ public void testDateAndTimeFormat() throws IOException, CommandException validateListDataInUI(table, expectedData); checker().screenShotIfNewError("Format01_Error"); - String dateFormat02 = "ddMMMyy"; - String timeFormat02 = "HH:mm:ss"; - String dateTimeFormat02 = "dd-MMM-yyyy HH:mm:ss"; + DATE_FORMAT dateFormat02 = DATE_FORMAT.ddMMMyy; + TIME_FORMAT timeFormat02 = TIME_FORMAT.HH_mm_ss; + DATE_FORMAT dateTimeDateFormat02 = DATE_FORMAT.dd_MMM_yyyy; + TIME_FORMAT dateTimeTimeFormat02 = TIME_FORMAT.HH_mm_ss; - formatterDate = new SimpleDateFormat(dateFormat02); - formatterTime = new SimpleDateFormat(timeFormat02); - formatterDateTime = new SimpleDateFormat(dateTimeFormat02); + formatterDate = new SimpleDateFormat(dateFormat02.toString()); + formatterTime = new SimpleDateFormat(timeFormat02.toString()); + formatterDateTime = new SimpleDateFormat(String.format("%s %s", dateTimeDateFormat02, dateTimeTimeFormat02)); clickAndWait(table.getHeaderButton("Design")); EditListDefinitionPage listDefinitionPage = new EditListDefinitionPage(getDriver()); @@ -1215,7 +1219,7 @@ public void testDateAndTimeFormat() throws IOException, CommandException DomainFormPanel domainEditor = listDefinitionPage.getFieldsPanel(); domainEditor.getField(timeCol).setTimeFormat(timeFormat02); domainEditor.getField(dateCol).setDateFormat(dateFormat02); - domainEditor.getField(dateTimeCol).setDateTimeFormat(dateTimeFormat02); + domainEditor.getField(dateTimeCol).setDateTimeFormat(dateTimeDateFormat02, dateTimeTimeFormat02); listDefinitionPage.clickSave(); @@ -1253,10 +1257,11 @@ public void testConvertDateTimeField() throws IOException, CommandException log(String.format("Create a list named '%s' with two DateTime fields that will be converted to date-only and time-only fields.", listName)); + // For dtFormatDate use a date format that has spaces. String dtFormatDate = String.format("%s %s", - BaseSettingsPage.DATE_FORMAT.yyyy_MMM_dd, BaseSettingsPage.TIME_FORMAT.HH_mm); + DATE_FORMAT.MMMM_dd_yyyy, TIME_FORMAT.HH_mm); String dtFormatTime = String.format("%s %s", - BaseSettingsPage.DATE_FORMAT.yyyy_MMM_dd, BaseSettingsPage.TIME_FORMAT.HH_mm_ss); + DATE_FORMAT.yyyy_MMM_dd, TIME_FORMAT.HH_mm_ss); SimpleDateFormat formatterFormatTime = new SimpleDateFormat(dtFormatTime); @@ -1347,8 +1352,8 @@ public void testConvertDateTimeField() throws IOException, CommandException listDefinitionPage.clickSave(); // Update default format after changing the types. - BaseSettingsPage.DATE_FORMAT dateFormat = BaseSettingsPage.DATE_FORMAT.Default; - BaseSettingsPage.TIME_FORMAT timeFormat = BaseSettingsPage.TIME_FORMAT.Default; + DATE_FORMAT dateFormat = DATE_FORMAT.Default; + TIME_FORMAT timeFormat = TIME_FORMAT.Default; SimpleDateFormat formatterDate = new SimpleDateFormat(dateFormat.toString()); SimpleDateFormat formatterTime = new SimpleDateFormat(timeFormat.toString()); diff --git a/src/org/labkey/test/tests/query/QueryMetadataTest.java b/src/org/labkey/test/tests/query/QueryMetadataTest.java index ad016f8cc1..b9e393f1b2 100644 --- a/src/org/labkey/test/tests/query/QueryMetadataTest.java +++ b/src/org/labkey/test/tests/query/QueryMetadataTest.java @@ -7,7 +7,7 @@ import org.labkey.test.BaseWebDriverTest; import org.labkey.test.categories.Daily; import org.labkey.test.components.domain.DomainFieldRow; -import org.labkey.test.pages.core.admin.BaseSettingsPage; +import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT; import org.labkey.test.pages.query.QueryMetadataEditorPage; import org.labkey.test.params.FieldDefinition; import org.labkey.test.params.experiment.SampleTypeDefinition; @@ -217,7 +217,7 @@ public void testEnsureOnlyModifiedColumnAppearsInMetadataXML() var editPage = QueryMetadataEditorPage.beginAt(this, getProjectName(), "lists", TEST_LIST); DomainFieldRow fieldRow = editPage.fieldsPanel().getField("Created"); fieldRow.setDateTimeInherited(false); - fieldRow.setDateTimeFormatDate(BaseSettingsPage.DATE_FORMAT.ddMMMyy.toString()); + fieldRow.setDateTimeFormat(DATE_FORMAT.ddMMMyy); editPage.clickSave(); var queryXmlPage = editPage.clickEditSource(); @@ -244,7 +244,7 @@ public void testAssayQueryMetadata() var editPage = QueryMetadataEditorPage.beginAt(this, getProjectName(), "assay.General." + TEST_ASSAY, "Data"); DomainFieldRow fieldRow = editPage.fieldsPanel().getField("Created"); fieldRow.setDateTimeInherited(false); - fieldRow.setDateTimeFormatDate(BaseSettingsPage.DATE_FORMAT.ddMMMyy.toString()); + fieldRow.setDateTimeFormat(DATE_FORMAT.ddMMMyy); editPage.aliasField("Row Id"); editPage.clickSave(); diff --git a/src/org/labkey/test/util/APIContainerHelper.java b/src/org/labkey/test/util/APIContainerHelper.java index 676e4b4cc9..63d57a8d68 100644 --- a/src/org/labkey/test/util/APIContainerHelper.java +++ b/src/org/labkey/test/util/APIContainerHelper.java @@ -19,6 +19,7 @@ import org.jetbrains.annotations.Nullable; import org.json.JSONObject; import org.labkey.remoteapi.CommandException; +import org.labkey.remoteapi.CommandResponse; import org.labkey.remoteapi.Connection; import org.labkey.remoteapi.SimplePostCommand; import org.labkey.remoteapi.security.CreateContainerCommand; @@ -279,4 +280,57 @@ public String getContainerId(String containerPath) throws CommandException throw new RuntimeException("Unable to get container ID for: " + containerPath, e); } } + + public CommandResponse setDateAndTimeFormats(Connection connection, String containerPath, + @Nullable String dateFormat, + @Nullable String timeFormat, + @Nullable String dateTimeFormat) throws IOException, CommandException + { + + JSONObject json = new JSONObject(); + + if(null != dateFormat) + { + json.put("defaultDateFormat", dateFormat); + json.put("defaultDateFormatInherited", false); + } + else + { + json.put("defaultDateFormatInherited", true); + } + + if(null != timeFormat) + { + json.put("defaultTimeFormat", timeFormat); + json.put("defaultTimeFormatInherited", false); + } + else + { + json.put("defaultTimeFormatInherited", true); + } + + if(null != dateTimeFormat) + { + json.put("defaultDateTimeFormat", dateTimeFormat); + json.put("defaultDateTimeFormatInherited", false); + } + else + { + json.put("defaultDateTimeFormatInherited", true); + } + + return setDateAndTimeFormats(connection, containerPath, json); + + } + + public CommandResponse setDateAndTimeFormats(Connection connection, String containerPath, JSONObject json) throws IOException, CommandException + { + + SimplePostCommand command = new SimplePostCommand("admin", "UpdateContainerSettings"); + command.setJsonObject(json); + + return command.execute(connection, containerPath); + + } + }