From e30bdda3be978ce4db43ba4d28d970a64c8ce31c Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 30 Jun 2025 09:53:11 -0500 Subject: [PATCH 01/12] Issue 53197: randomFieldName() to include WIDE_PLACEHOLDER --- src/org/labkey/test/tests/component/GridPanelTest.java | 10 +++++----- src/org/labkey/test/util/TestDataGenerator.java | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/org/labkey/test/tests/component/GridPanelTest.java b/src/org/labkey/test/tests/component/GridPanelTest.java index d38641af9b..e399fc196d 100644 --- a/src/org/labkey/test/tests/component/GridPanelTest.java +++ b/src/org/labkey/test/tests/component/GridPanelTest.java @@ -64,11 +64,11 @@ public class GridPanelTest extends GridPanelBaseTest // Column names. private static final String FILTER_NAME_COL = "Name"; private static final String FILTER_EXPDATE_COL = "Expiration Date"; - private static final String FILTER_STRING_COL = "Str"; - private static final String FILTER_INT_COL = "Int"; - private static final String FILTER_EXTEND_CHAR_COL = "\u0106\u00D8\u0139"; - private static final String FILTER_BOOL_COL = "Bool"; - private static final String FILTER_DATE_COL = "Date"; + private static final String FILTER_STRING_COL = TestDataGenerator.randomFieldName("Str", 0, 5); + private static final String FILTER_INT_COL = TestDataGenerator.randomFieldName("Int", 0, 5); + private static final String FILTER_EXTEND_CHAR_COL = TestDataGenerator.randomFieldName("\u0106\u00D8\u0139", 0, 5); + private static final String FILTER_BOOL_COL = TestDataGenerator.randomFieldName("Bool", 0, 5); + private static final String FILTER_DATE_COL = TestDataGenerator.randomFieldName("Date", 0, 5); private static final String FILTER_STORED_AMOUNT_COL = "Amount"; // Views and columns used in the views. The views are only applied to the small sample type (Small_SampleType). diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 68315ca9bf..b83c7a9002 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -576,12 +576,11 @@ public static String randomFieldName(String part, int numStartChars, int numEndC public static String randomFieldName(@NotNull String part, int numStartChars, int numEndChars, @Nullable String exclusion) { // use the characters that we know are encoded in fieldKeys plus characters that we know clients are using - // Issue 53197: Field name with double byte character can cause client side exception in Firefox when trying to customize grid view. - String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;<>?!@#^" + NON_LATIN_STRING;// + WIDE_PLACEHOLDER ; + String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;<>?!@#^" + NON_LATIN_STRING + WIDE_PLACEHOLDER ; String randomFieldName = randomName(part, numStartChars, numEndChars, chars, exclusion); TestLogger.log("Generated random field name: " + randomFieldName); - return randomFieldName; + return randomFieldName + WIDE_PLACEHOLDER; // TODO remove this hardcoded WIDE_PLACEHOLDER after a few TC runs } public static String randomChoice(List choices) From 2e7e63835ad7ccb2ed2e180f109bcd7e06f91993 Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 7 Jul 2025 17:18:59 -0500 Subject: [PATCH 02/12] GridPaneLtest to use FieldInfo and randomFieldName() --- .../test/tests/component/GridPanelTest.java | 272 +++++++++--------- 1 file changed, 141 insertions(+), 131 deletions(-) diff --git a/src/org/labkey/test/tests/component/GridPanelTest.java b/src/org/labkey/test/tests/component/GridPanelTest.java index e399fc196d..e87595acd7 100644 --- a/src/org/labkey/test/tests/component/GridPanelTest.java +++ b/src/org/labkey/test/tests/component/GridPanelTest.java @@ -23,6 +23,7 @@ import org.labkey.test.components.ui.search.FilterExpressionPanel; import org.labkey.test.components.ui.search.FilterFacetedPanel; import org.labkey.test.params.FieldDefinition; +import org.labkey.test.params.FieldInfo; import org.labkey.test.params.FieldKey; import org.labkey.test.params.experiment.SampleTypeDefinition; import org.labkey.test.util.DataRegionTable; @@ -64,11 +65,11 @@ public class GridPanelTest extends GridPanelBaseTest // Column names. private static final String FILTER_NAME_COL = "Name"; private static final String FILTER_EXPDATE_COL = "Expiration Date"; - private static final String FILTER_STRING_COL = TestDataGenerator.randomFieldName("Str", 0, 5); - private static final String FILTER_INT_COL = TestDataGenerator.randomFieldName("Int", 0, 5); - private static final String FILTER_EXTEND_CHAR_COL = TestDataGenerator.randomFieldName("\u0106\u00D8\u0139", 0, 5); - private static final String FILTER_BOOL_COL = TestDataGenerator.randomFieldName("Bool", 0, 5); - private static final String FILTER_DATE_COL = TestDataGenerator.randomFieldName("Date", 0, 5); + private static final FieldInfo FILTER_STRING_COL = new FieldInfo("Str\uD83D\uDC7E]|*안", FieldDefinition.ColumnType.String); + private static final FieldInfo FILTER_INT_COL = new FieldInfo("Int&`~_@", FieldDefinition.ColumnType.Integer); + private static final FieldInfo FILTER_EXTEND_CHAR_COL = new FieldInfo(TestDataGenerator.randomFieldName("\u0106\u00D8\u0139", 0, 5), FieldDefinition.ColumnType.String); + private static final FieldInfo FILTER_BOOL_COL = new FieldInfo(TestDataGenerator.randomFieldName("Bool", 0, 5), FieldDefinition.ColumnType.Boolean); + private static final FieldInfo FILTER_DATE_COL = new FieldInfo(TestDataGenerator.randomFieldName("Date", 0, 5), FieldDefinition.ColumnType.DateAndTime); private static final String FILTER_STORED_AMOUNT_COL = "Amount"; // Views and columns used in the views. The views are only applied to the small sample type (Small_SampleType). @@ -77,7 +78,7 @@ public class GridPanelTest extends GridPanelBaseTest private static final String VIEW_FILTERED_COLUMN = "Filtered_Column"; private static final List extraColumnsNames = Arrays.asList("IsAliquot", "genId"); // Special case for adding the columns to the view and calling getRows api. private static final List extraColumnsHeaders = Arrays.asList("Is Aliquot", "Gen Id"); // The column headers as they appear in the UI and exported file. - private static final List removedColumns = Arrays.asList(FILTER_BOOL_COL); +// private static final List removedColumns = Arrays.asList(FILTER_BOOL_COL); // Various values used to populate Str field for records. Also used in filtering/searching. // Note: Small_SampleType is populated with random data and will have none of these values. @@ -143,10 +144,11 @@ private void doSetup() throws IOException, CommandException private void createSmallSampleType() throws IOException, CommandException { SampleTypeDefinition props = new SampleTypeDefinition(SMALL_SAMPLE_TYPE) - .setFields(Arrays.asList(new FieldDefinition(FILTER_INT_COL, FieldDefinition.ColumnType.Integer), - new FieldDefinition(FILTER_STRING_COL, FieldDefinition.ColumnType.String), - new FieldDefinition(FILTER_DATE_COL, FieldDefinition.ColumnType.DateAndTime), - new FieldDefinition(FILTER_BOOL_COL, FieldDefinition.ColumnType.Boolean))); + .setFields(Arrays.asList( + FILTER_INT_COL.getFieldDefinition(), + FILTER_STRING_COL.getFieldDefinition(), + FILTER_DATE_COL.getFieldDefinition(), + FILTER_BOOL_COL.getFieldDefinition())); TestDataGenerator sampleSetDataGenerator = SampleTypeAPIHelper.createEmptySampleType(getProjectName(), props); @@ -159,10 +161,10 @@ private void createSmallSampleType() throws IOException, CommandException sampleSetDataGenerator.addCustomRow( Map.of(FILTER_NAME_COL, String.format("%s%d", SMALL_SAMPLE_PREFIX, rowCount), - FILTER_INT_COL, TestDataGenerator.randomInt(1, INT_MAX), - FILTER_STRING_COL, stringSets.get(setIndex++), - FILTER_DATE_COL, sampleSetDataGenerator.randomDateString(DateUtils.addWeeks(new Date(), -25), new Date()), - FILTER_BOOL_COL, sampleSetDataGenerator.randomBoolean()) + FILTER_INT_COL.getName(), TestDataGenerator.randomInt(1, INT_MAX), + FILTER_STRING_COL.getName(), stringSets.get(setIndex++), + FILTER_DATE_COL.getName(), sampleSetDataGenerator.randomDateString(DateUtils.addWeeks(new Date(), -25), new Date()), + FILTER_BOOL_COL.getName(), sampleSetDataGenerator.randomBoolean()) ); } @@ -190,14 +192,14 @@ private void createSmallSampleType() throws IOException, CommandException log(String.format("Create the '%s' view for the '%s' sample type.", VIEW_FEWER_COLUMNS, SMALL_SAMPLE_TYPE)); cv = drtSamples.openCustomizeGrid(); - for(String columnName : removedColumns) + for(String columnName : List.of(FILTER_BOOL_COL.getFieldKey().toString())) { cv.removeColumn(columnName); } cv.saveCustomView(VIEW_FEWER_COLUMNS); log(String.format("Finally create a view named '%s' for '%s' that only has a filter.", VIEW_FILTERED_COLUMN, SMALL_SAMPLE_TYPE)); - drtSamples.setFilter(FieldKey.encodePart(FILTER_STRING_COL), "Contains One Of", String.format("%1$s\n%1$s%2$s", stringSetMembers.get(0), stringSetMembers.get(1))); + drtSamples.setFilter(FILTER_STRING_COL.getFieldKey().toString(), "Contains One Of", String.format("%1$s\n%1$s%2$s", stringSetMembers.get(0), stringSetMembers.get(1))); cv = drtSamples.openCustomizeGrid(); cv.saveCustomView(VIEW_FILTERED_COLUMN); @@ -209,9 +211,9 @@ private void createSmallSampleType() throws IOException, CommandException private void createFilterSampleType() throws IOException, CommandException { List fields = new ArrayList<>(); - fields.add(new FieldDefinition(FILTER_STRING_COL, FieldDefinition.ColumnType.String)); - fields.add(new FieldDefinition(FILTER_INT_COL, FieldDefinition.ColumnType.Integer)); - fields.add(new FieldDefinition(FILTER_EXTEND_CHAR_COL, FieldDefinition.ColumnType.String)); + fields.add(FILTER_STRING_COL.getFieldDefinition()); + fields.add(FILTER_INT_COL.getFieldDefinition()); + fields.add(FILTER_EXTEND_CHAR_COL.getFieldDefinition()); SampleTypeDefinition sampleTypeDefinition = new SampleTypeDefinition(FILTER_SAMPLE_TYPE).setFields(fields); @@ -291,9 +293,9 @@ else if(sampleId % 7 == 0 && stringWithNumCount < NUMBER_STRING_COUNT) sampleSetDataGenerator.addCustomRow( Map.of(FILTER_NAME_COL, String.format("%s%d", FILTER_SAMPLE_PREFIX, sampleId++), - FILTER_INT_COL, intValue++, - FILTER_STRING_COL, filterColValue, - FILTER_EXTEND_CHAR_COL, extColValue)); + FILTER_INT_COL.getName(), intValue++, + FILTER_STRING_COL.getName(), filterColValue, + FILTER_EXTEND_CHAR_COL.getName(), extColValue)); } @@ -557,13 +559,13 @@ public void testSelectAllButtonWithFilteredResults() QueryGrid grid = beginAtQueryGrid(FILTER_SAMPLE_TYPE); log("Validate that the 'Select All' button works as expected."); - grid.filterColumn(FILTER_STRING_COL, Filter.Operator.EQUAL, MULTI_PAGE_STRING); + grid.filterColumn(FILTER_STRING_COL.getName(), Filter.Operator.EQUAL, MULTI_PAGE_STRING); checker().fatal() .verifyTrue("The 'Select All' button is not present.", grid.hasSelectAllButton()); grid.selectAllRows(); - grid.removeColumnFilter(FILTER_STRING_COL); + grid.removeColumnFilter(FILTER_STRING_COL.getName()); checker().withScreenshot("Select_All_Button_Error") .verifyEquals("Number of selected rows not as expected after filter removed.", String.format(SELECTED_TEXT_FORMAT, MULTI_PAGE_COUNT * DEFAULT_PAGE_SIZE, FILTER_SAMPLE_TYPE_SIZE), grid.getSelectionStatusCount()); @@ -591,9 +593,9 @@ public void testSelectAllOnPageWithFilteredResults() QueryGrid grid = beginAtQueryGrid(FILTER_SAMPLE_TYPE); log("Validate the select all check box at the top of the gird works as expected."); - grid.filterColumn(FILTER_STRING_COL, Filter.Operator.EQUAL, MULTI_PAGE_STRING); + grid.filterColumn(FILTER_STRING_COL.getName(), Filter.Operator.EQUAL, MULTI_PAGE_STRING); grid.selectAllOnPage(true); - grid.removeColumnFilter(FILTER_STRING_COL); + grid.removeColumnFilter(FILTER_STRING_COL.getName()); checker().withScreenshot("Select_All_On_Page_Error") .verifyEquals("Using check box at top of grid did not select the expected samples.", String.format(SELECTED_TEXT_FORMAT, DEFAULT_PAGE_SIZE, FILTER_SAMPLE_TYPE_SIZE), grid.getSelectionStatusCount()); @@ -718,14 +720,14 @@ public void testMultipleFiltersOnOneColumn() throws IOException, CommandExceptio int low = INT_MAX - 3; int high = INT_MAX; - log(String.format("Filter the '%s' for values greater than %d and less than or equal to %d.", FILTER_INT_COL, low, high)); + log(String.format("Filter the '%s' for values greater than %d and less than or equal to %d.", FILTER_INT_COL.getName(), low, high)); - grid.filterColumn(FILTER_INT_COL, Filter.Operator.GT, low, Filter.Operator.LTE, high); + grid.filterColumn(FILTER_INT_COL.getName(), Filter.Operator.GT, low, Filter.Operator.LTE, high); // Query the table to get the expected number of rows. List filters = List.of( - new Filter(FILTER_INT_COL, low, Filter.Operator.getOperator("GREATER_THAN")), - new Filter(FILTER_INT_COL, high, Filter.Operator.getOperator("LESS_THAN_OR_EQUAL"))); + new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN")), + new Filter(FILTER_INT_COL.getFieldKey().toString(), high, Filter.Operator.getOperator("LESS_THAN_OR_EQUAL"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().withScreenshot("Multiple_Filters_One_Column_Error") @@ -831,7 +833,7 @@ public void testFilterErrorAndFilterOnlyTab() log(String.format("Filter on the '%s' field. This should only provide a 'Filter' tab.", FILTER_INT_COL)); - filterDialog.selectField(FILTER_INT_COL); + filterDialog.selectField(FILTER_INT_COL.getLabel()); checker().verifyFalse(String.format("There should be no 'Choose Values' tab for the '%s' field.", FILTER_INT_COL), filterDialog.getTabText().contains("Choose Values")); @@ -847,7 +849,7 @@ public void testFilterErrorAndFilterOnlyTab() String errorMsg = filterDialog.confirmExpectingError(); checker().verifyEquals("Expected error message not present.", - String.format("Missing filter values for: %s.", FILTER_INT_COL), errorMsg); + String.format("Missing filter values for: %s.", FILTER_INT_COL.getLabel()), errorMsg); checker().screenShotIfNewError("Filter_Dialog_Error"); @@ -885,7 +887,7 @@ public void testInteractionBetweenDialogTabs() throws IOException, CommandExcept log(String.format("Select '%s' and get the list of values for the field before filtering.", FILTER_STRING_COL)); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); FilterFacetedPanel facetedPanel = filterDialog.selectFacetTab(); @@ -919,7 +921,7 @@ public void testInteractionBetweenDialogTabs() throws IOException, CommandExcept log(String.format("Open the dialog again and validate that the list of values to select from for '%s' is reduced.", FILTER_STRING_COL)); filterDialog = grid.getGridBar().openFilterDialog(); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); facetedPanel = filterDialog.selectFacetTab(); actualValues = facetedPanel.getAvailableValues(); @@ -943,7 +945,7 @@ public void testInteractionBetweenDialogTabs() throws IOException, CommandExcept log("Validate that applying a filter for a fields checks the values in the dialog."); filterDialog = grid.getGridBar().openFilterDialog(); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); String firstFilterValue = stringSets.get(0); @@ -996,11 +998,11 @@ public void testInteractionBetweenDialogTabs() throws IOException, CommandExcept // Query the table to get the expected number of rows to be returned. List filters = List.of( - new Filter(FILTER_STRING_COL, String.format("%s;%s", firstFilterValue, secondFilterValue), + new Filter(FILTER_STRING_COL.getFieldKey().toString(), String.format("%s;%s", firstFilterValue, secondFilterValue), Filter.Operator.getOperator("IN"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); - checker().verifyEquals("Filter did not return the expected number of rows.", + checker().verifyEquals("Filter did not return the expected number of rows.", // TODO here expectedCount, grid.getRecordCount()); } @@ -1029,15 +1031,15 @@ public void testSearchAndFilter() throws IOException, CommandException GridFilterModal filterDialog = grid.getGridBar().openFilterDialog(); - filterDialog.selectField(FILTER_INT_COL); + filterDialog.selectField(FILTER_INT_COL.getLabel()); - log(String.format("Filter '%s' for values between %d and %d.", FILTER_INT_COL, low, high)); + log(String.format("Filter '%s' for values between %d and %d.", FILTER_INT_COL.getLabel(), low, high)); FilterExpressionPanel expressionPanel = filterDialog.selectExpressionTab(); expressionPanel.setFilters(new FilterExpressionPanel.Expression(Filter.Operator.GT, low), new FilterExpressionPanel.Expression(Filter.Operator.LT, high)); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); filterDialog.selectFacetTab(); @@ -1055,9 +1057,9 @@ public void testSearchAndFilter() throws IOException, CommandException // Query the table to get the expected number of rows to be returned. Will modify this list later so make it mutable. List filters = new ArrayList<>(); - filters.add(new Filter(FILTER_STRING_COL, oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); - filters.add(new Filter(FILTER_INT_COL, low, Filter.Operator.getOperator("GREATER_THAN"))); - filters.add(new Filter(FILTER_INT_COL, high, Filter.Operator.getOperator("LESS_THAN"))); + filters.add(new Filter(FILTER_STRING_COL.getFieldKey().toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); + filters.add(new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN"))); + filters.add(new Filter(FILTER_INT_COL.getFieldKey().toString(), high, Filter.Operator.getOperator("LESS_THAN"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Number of rows after filter applied not as expected.", @@ -1072,7 +1074,7 @@ public void testSearchAndFilter() throws IOException, CommandException grid.getGridBar().searchFor(searchString); // Because the search string is specific to the Str column a query can be used to get the expected count. - filters.add(new Filter(FILTER_STRING_COL, searchString, Filter.Operator.getOperator("CONTAINS"))); + filters.add(new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().withScreenshot("Filter_With_Search_Error") @@ -1088,7 +1090,7 @@ public void testSearchAndFilter() throws IOException, CommandException // Again can use a query to get the expected number of rows from the search. filters = new ArrayList<>(); - filters.add(new Filter(FILTER_STRING_COL, searchString, Filter.Operator.getOperator("CONTAINS"))); + filters.add(new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Number of rows after filter were cleared not as expected.", @@ -1122,15 +1124,15 @@ public void testFilterPills() throws IOException, CommandException GridFilterModal filterDialog = grid.getGridBar().openFilterDialog(); - filterDialog.selectField(FILTER_INT_COL); + filterDialog.selectField(FILTER_INT_COL.getLabel()); - log(String.format("Filter '%s' for values greater than %d and less than %d.", FILTER_INT_COL, low, high)); + log(String.format("Filter '%s' for values greater than %d and less than %d.", FILTER_INT_COL.getLabel(), low, high)); FilterExpressionPanel expressionPanel = filterDialog.selectExpressionTab(); expressionPanel.setFilters(new FilterExpressionPanel.Expression(Filter.Operator.GT, low), new FilterExpressionPanel.Expression(Filter.Operator.LT, high)); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); String oneOfFilter = String.format("%s\n%s\n%s", stringSetMembers.get(0), stringSetMembers.get(1), stringSetMembers.get(2)); @@ -1140,8 +1142,8 @@ public void testFilterPills() throws IOException, CommandException expressionPanel.setFilter(new FilterExpressionPanel.Expression(Filter.Operator.CONTAINS_ONE_OF, oneOfFilter)); List expectedValues = new ArrayList<>(); - expectedValues.add(FILTER_INT_COL); - expectedValues.add(FILTER_STRING_COL); + expectedValues.add(FILTER_INT_COL.getLabel()); + expectedValues.add(FILTER_STRING_COL.getLabel()); List actualValues = filterDialog.getFilteredFieldLabels(); @@ -1149,16 +1151,16 @@ public void testFilterPills() throws IOException, CommandException Collections.sort(actualValues); checker().withScreenshot("Filtered_Fields_Not_Marked") - .verifyEquals(String.format("The '%s' and '%s' fields are not marked as filtered.", FILTER_INT_COL, FILTER_STRING_COL), + .verifyEquals(String.format("The '%s' and '%s' fields are not marked as filtered.", FILTER_INT_COL.getLabel(), FILTER_STRING_COL), expectedValues, actualValues); filterDialog.confirm(); - String pillToRemove = String.format("%s < %d", FILTER_INT_COL, high); + String pillToRemove = String.format("%s < %d", FILTER_INT_COL.getLabel(), high); expectedValues = new ArrayList<>(); expectedValues.add(pillToRemove); - expectedValues.add(String.format("%s > %d", FILTER_INT_COL, low)); + expectedValues.add(String.format("%s > %d", FILTER_INT_COL.getLabel(), low)); expectedValues.add(String.format("%s Contains One Of %s", FILTER_STRING_COL, oneOfFilter.replace("\n", ", "))); List filterPills = grid.getFilterStatusValues(); @@ -1172,9 +1174,9 @@ public void testFilterPills() throws IOException, CommandException expectedValues, actualValues); List filters = List.of( - new Filter(FILTER_INT_COL, low, Filter.Operator.getOperator("GREATER_THAN")), - new Filter(FILTER_INT_COL, high, Filter.Operator.getOperator("LESS_THAN")), - new Filter(FILTER_STRING_COL, oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); + new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN")), + new Filter(FILTER_INT_COL.getFieldKey().toString(), high, Filter.Operator.getOperator("LESS_THAN")), + new Filter(FILTER_STRING_COL.getFieldKey().toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Rows returned after filters applied not as expected.", @@ -1193,8 +1195,8 @@ public void testFilterPills() throws IOException, CommandException } filters = List.of( - new Filter(FILTER_INT_COL, low, Filter.Operator.getOperator("GREATER_THAN")), - new Filter(FILTER_STRING_COL, oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); + new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN")), + new Filter(FILTER_STRING_COL.getFieldKey().toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Rows returned after filter pill removed not as expected.", @@ -1220,18 +1222,18 @@ public void testFilterPills() throws IOException, CommandException */ expectedValues = new ArrayList<>(); - expectedValues.add(FILTER_INT_COL); - expectedValues.add(FILTER_STRING_COL); + expectedValues.add(FILTER_INT_COL.getLabel()); + expectedValues.add(FILTER_STRING_COL.getLabel()); actualValues = filterDialog.getFilteredFieldLabels(); Collections.sort(expectedValues); Collections.sort(actualValues); - checker().verifyEquals(String.format("Both the '%s' and '%s' fields should be marked as filtered.", FILTER_INT_COL, FILTER_STRING_COL), + checker().verifyEquals(String.format("Both the '%s' and '%s' fields should be marked as filtered.", FILTER_INT_COL.getLabel(), FILTER_STRING_COL), expectedValues, actualValues); - filterDialog.selectField(FILTER_INT_COL); + filterDialog.selectField(FILTER_INT_COL.getLabel()); expressionPanel = filterDialog.selectExpressionTab(); @@ -1248,7 +1250,7 @@ public void testFilterPills() throws IOException, CommandException checker().screenShotIfNewError("Populated_Filter_Int_Field_Error"); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); expressionPanel = filterDialog.selectExpressionTab(); @@ -1270,13 +1272,13 @@ public void testFilterPills() throws IOException, CommandException private void createSemicolonSampleType() throws IOException, CommandException { SampleTypeDefinition props = new SampleTypeDefinition(SEMICOLON_SAMPLE_TYPE) - .setFields(Arrays.asList(new FieldDefinition(FILTER_STRING_COL, FieldDefinition.ColumnType.String))); + .setFields(Arrays.asList(FILTER_STRING_COL.getFieldDefinition())); TestDataGenerator sampleSetDataGenerator = SampleTypeAPIHelper.createEmptySampleType(getProjectName(), props); for (int i = 0; i < SEMICOLON_VALUES.length; i++) - sampleSetDataGenerator.addCustomRow(Map.of(FILTER_NAME_COL, "Semi_" + i, FILTER_STRING_COL, SEMICOLON_VALUES[i])); + sampleSetDataGenerator.addCustomRow(Map.of(FILTER_NAME_COL, "Semi_" + i, FILTER_STRING_COL.getName(), SEMICOLON_VALUES[i])); // add a second for one of the values to test with filtering behavior - sampleSetDataGenerator.addCustomRow(Map.of(FILTER_NAME_COL, "Semi_5", FILTER_STRING_COL, SEMICOLON_VALUES[4])); + sampleSetDataGenerator.addCustomRow(Map.of(FILTER_NAME_COL, "Semi_5", FILTER_STRING_COL.getName(), SEMICOLON_VALUES[4])); sampleSetDataGenerator.insertRows(); } @@ -1325,7 +1327,7 @@ public void testFilterValueWithSemicolon() throws IOException, CommandException log("Testing filtering for individual values using faceted filter tab"); for (String value : SEMICOLON_VALUES) { - GridFilterModal filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL); + GridFilterModal filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL.getLabel()); filterModal.selectFacetTab().selectValue(value); filterModal.confirm(); int expectedCount = value.equals(SEMICOLON_VALUES[4]) ? 2 : 1; @@ -1337,7 +1339,7 @@ public void testFilterValueWithSemicolon() throws IOException, CommandException log("Testing selected faceted value, switching tabs, and confirming Equals filter"); for (String value : SEMICOLON_VALUES) { - GridFilterModal filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL); + GridFilterModal filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL.getLabel()); filterModal.selectFacetTab().selectValue(value); FilterExpressionPanel expressionPanel = filterModal.selectExpressionTab(); checker().verifyTrue("Filter type not as expected", expressionPanel.hasFilterType(0, "Equals")); @@ -1350,7 +1352,7 @@ public void testFilterValueWithSemicolon() throws IOException, CommandException } log("Testing combination of selected faceted values, switching tabs, and confirming Equals One Of filter type/values"); - GridFilterModal filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL); + GridFilterModal filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL.getLabel()); FilterFacetedPanel facetedPanel = filterModal.selectFacetTab(); facetedPanel.selectValue(SEMICOLON_VALUES[0]); facetedPanel.checkValues(SEMICOLON_VALUES[4]); @@ -1359,7 +1361,7 @@ public void testFilterValueWithSemicolon() throws IOException, CommandException checker().verifyEquals("Filter value not as expected", expressionPanel.getFilterTextValue(0), SEMICOLON_VALUES[0] + "\n" + SEMICOLON_VALUES[4]); filterModal.confirm(); checker().verifyEquals("Number of records returned from filter not as expected.", 3, grid.getRecordCount()); - filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL); + filterModal = grid.getGridBar().openFilterDialog().selectField(FILTER_STRING_COL.getLabel()); facetedPanel = filterModal.selectFacetTab(); facetedPanel.selectValue(SEMICOLON_VALUES[0]); facetedPanel.checkValues(SEMICOLON_VALUES[4]); @@ -1390,7 +1392,7 @@ public void testSearchIsSameAsContainsFilter() throws IOException, CommandExcept // Identify how many rows should be returned. List filters = List.of( - new Filter(FILTER_STRING_COL, searchString, Filter.Operator.getOperator("CONTAINS"))); + new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); int actualCount = grid.getRecordCount(); @@ -1405,7 +1407,7 @@ public void testSearchIsSameAsContainsFilter() throws IOException, CommandExcept GridFilterModal filterDialog = grid.getGridBar().openFilterDialog(); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); FilterExpressionPanel expressionPanel = filterDialog.selectExpressionTab(); expressionPanel.setFilter(new FilterExpressionPanel.Expression(Filter.Operator.CONTAINS, searchString)); @@ -1451,15 +1453,15 @@ public void testSearchAcrossColumns() throws IOException, CommandException checker().verifyEquals("Number of records returned from search not as expected.", expectedCount, actualCount); - log(String.format("Validate that the result set did not return a row where the search value was in the %s field.", FILTER_INT_COL)); + log(String.format("Validate that the result set did not return a row where the search value was in the %s field.", FILTER_INT_COL.getLabel())); List actualIds = grid.getColumnDataAsText(FILTER_NAME_COL); // Query the table to get a list of samples/rows that should not be in the result from the search. List filters = List.of(new Filter(FILTER_NAME_COL, searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), - new Filter(FILTER_STRING_COL, searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), - new Filter(FILTER_EXTEND_CHAR_COL, searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), - new Filter(FILTER_INT_COL, searchString, Filter.Operator.getOperator("EQUAL"))); + new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), + new Filter(FILTER_EXTEND_CHAR_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), + new Filter(FILTER_INT_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("EQUAL"))); List> rows = getExpectedResults(FILTER_SAMPLE_TYPE, null, Arrays.asList(FILTER_NAME_COL), filters); boolean error = false; @@ -1499,23 +1501,23 @@ public void testFilteringAndSearchingForExtendedCharacters() throws IOException, grid.getGridBar().clearSearch(); - log(String.format("Filter the '%s' column for value '%s'.", FILTER_EXTEND_CHAR_COL, EXTEND_RECORD_STRING)); + log(String.format("Filter the '%s' column for value '%s'.", FILTER_EXTEND_CHAR_COL.getLabel(), EXTEND_RECORD_STRING)); GridFilterModal filterDialog = grid.getGridBar().openFilterDialog(); - filterDialog.selectField(FILTER_EXTEND_CHAR_COL); + filterDialog.selectField(FILTER_EXTEND_CHAR_COL.getLabel()); FilterExpressionPanel expressionPanel = filterDialog.selectExpressionTab(); expressionPanel.setFilter(new FilterExpressionPanel.Expression(Filter.Operator.CONTAINS, EXTEND_RECORD_STRING)); filterDialog.confirm(); List filters = List.of( - new Filter(FILTER_EXTEND_CHAR_COL, EXTEND_RECORD_STRING, Filter.Operator.getOperator("EQUAL"))); + new Filter(FILTER_EXTEND_CHAR_COL.getFieldKey().toString(), EXTEND_RECORD_STRING, Filter.Operator.getOperator("EQUAL"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().withScreenshot("Filter_Extended_Error") .verifyEquals(String.format("Number of records returned when filtering column '%s' for '%s' not as expected.", - FILTER_EXTEND_CHAR_COL, EXTEND_RECORD_STRING), + FILTER_EXTEND_CHAR_COL.getLabel(), EXTEND_RECORD_STRING), expectedCount, grid.getRecordCount()); } @@ -1534,14 +1536,16 @@ public void testExport() throws IOException, CommandException log("Filter the grid and validate only the filtered results are exported."); grid.filterColumn(FILTER_STRING_COL, Filter.Operator.EQUAL, MULTI_PAGE_STRING); - List columns = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL, FILTER_INT_COL, FILTER_EXTEND_CHAR_COL); + List columnsFKs = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL.getFieldKey().toString(), FILTER_INT_COL.getFieldKey().toString(), FILTER_EXTEND_CHAR_COL.getFieldKey().toString()); + List columnNames = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL.getName(), FILTER_INT_COL.getName(), FILTER_EXTEND_CHAR_COL.getName()); + List columnLabels = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL.getLabel(), FILTER_INT_COL.getLabel(), FILTER_EXTEND_CHAR_COL.getLabel()); List filters = List.of( - new Filter(FILTER_STRING_COL, MULTI_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); - List> expectedValues = getExpectedResults(FILTER_SAMPLE_TYPE, null, columns, filters); + new Filter(FILTER_STRING_COL.getFieldKey().toString(), MULTI_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); + List> expectedValues = getExpectedResults(FILTER_SAMPLE_TYPE, null, columnsFKs, filters); File exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); - validateExportedData(exportedFile, expectedValues, columns); + validateExportedData(exportedFile, expectedValues, columnNames, columnLabels); log("Validate that if there are selected rows only they are exported."); grid.clearFilters(); @@ -1553,12 +1557,12 @@ public void testExport() throws IOException, CommandException grid.clearFilters(); filters = List.of( - new Filter(FILTER_STRING_COL, ONE_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); - expectedValues = getExpectedResults(FILTER_SAMPLE_TYPE, null, columns, filters); + new Filter(FILTER_STRING_COL.getFieldKey().toString(), ONE_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); + expectedValues = getExpectedResults(FILTER_SAMPLE_TYPE, null, columnsFKs, filters); exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); - validateExportedData(exportedFile, expectedValues, columns); + validateExportedData(exportedFile, expectedValues, columnNames, columnLabels); log(String.format("Using sample type '%s' validate that if a view is selected the expected columns are exported.", SMALL_SAMPLE_TYPE)); @@ -1570,12 +1574,12 @@ public void testExport() throws IOException, CommandException exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); // The extra column added have spaces in the name so the column header in the exported file, so use the header values. - columns = new ArrayList<>(extraColumnsHeaders); - columns.add(FILTER_DATE_COL); + List columns = new ArrayList<>(extraColumnsHeaders); + columns.add(FILTER_DATE_COL.getLabel()); columns.add(FILTER_NAME_COL); - columns.add(FILTER_BOOL_COL); - columns.add(FILTER_STRING_COL); - columns.add(FILTER_INT_COL); + columns.add(FILTER_BOOL_COL.getLabel()); + columns.add(FILTER_STRING_COL.getLabel()); + columns.add(FILTER_INT_COL.getLabel()); validateExportedColumnHeader(exportedFile, columns, new ArrayList<>()); log(String.format("Now select the '%s' view.", VIEW_FEWER_COLUMNS)); @@ -1584,11 +1588,11 @@ public void testExport() throws IOException, CommandException exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); columns = new ArrayList<>(); - columns.add(FILTER_DATE_COL); + columns.add(FILTER_DATE_COL.getLabel()); columns.add(FILTER_NAME_COL); - columns.add(FILTER_STRING_COL); - columns.add(FILTER_INT_COL); - validateExportedColumnHeader(exportedFile, columns, removedColumns); + columns.add(FILTER_STRING_COL.getLabel()); + columns.add(FILTER_INT_COL.getLabel()); + validateExportedColumnHeader(exportedFile, columns, List.of(FILTER_BOOL_COL.getLabel())); // Test for Issue 46465 (Sample export do not respect filter when samples have been selected) grid = beginAtQueryGrid(FILTER_SAMPLE_TYPE); @@ -1601,7 +1605,7 @@ public void testExport() throws IOException, CommandException int rowsCountBefore = grid.getRecordCount(); - grid.filterColumn(FILTER_INT_COL, Filter.Operator.GT, 10); + grid.filterColumn(FILTER_INT_COL.getName(), Filter.Operator.GT, 10); int rowCountAfter = grid.getRecordCount(); @@ -1612,18 +1616,21 @@ public void testExport() throws IOException, CommandException List> expectedData = new ArrayList<>(); - List intColData = grid.getColumnDataAsText(FILTER_INT_COL); + List intColData = grid.getColumnDataAsText(FILTER_INT_COL.getLabel()); for(String colValue : intColData) { // All the rows will have the same value in the string column (FILTER_STRING_COL). - expectedData.add(Map.of(FILTER_STRING_COL, NUMBER_STRING, - FILTER_INT_COL, colValue)); + expectedData.add(Map.of(FILTER_STRING_COL.getName(), NUMBER_STRING, + FILTER_INT_COL.getName(), colValue)); } exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); - validateExportedData(exportedFile, expectedData, Arrays.asList(FILTER_STRING_COL, FILTER_INT_COL)); + validateExportedData(exportedFile, expectedData, + Arrays.asList(FILTER_STRING_COL.getName(), FILTER_INT_COL.getName()), + Arrays.asList(FILTER_STRING_COL.getLabel(), FILTER_INT_COL.getLabel()) + ); } } @@ -1672,10 +1679,10 @@ public void testFilterDialogWithViews() throws IOException, CommandException List expectedList = new ArrayList<>(extraColumnsHeaders); expectedList.add(FILTER_NAME_COL); - expectedList.add(FILTER_STRING_COL); - expectedList.add(FILTER_INT_COL); - expectedList.add(FILTER_BOOL_COL); - expectedList.add(FILTER_DATE_COL); + expectedList.add(FILTER_STRING_COL.getLabel()); + expectedList.add(FILTER_INT_COL.getLabel()); + expectedList.add(FILTER_BOOL_COL.getLabel()); + expectedList.add(FILTER_DATE_COL.getLabel()); checker().withScreenshot("View_Extra_Field_Error") .verifyTrue(String.format("The fields listed in the dialog do not have expected values '%s'.", expectedList), @@ -1688,7 +1695,7 @@ public void testFilterDialogWithViews() throws IOException, CommandException grid.selectView(VIEW_FEWER_COLUMNS); expectedList.removeAll(extraColumnsHeaders); - expectedList.removeAll(removedColumns); + expectedList.remove(FILTER_BOOL_COL.getLabel()); filterDialog = grid.getGridBar().openFilterDialog(); actualList = filterDialog.getAvailableFieldLabels(); @@ -1696,9 +1703,9 @@ public void testFilterDialogWithViews() throws IOException, CommandException checker().verifyTrue(String.format("The fields listed in the dialog are not as expected. Expected '%s'.", expectedList), actualList.containsAll(expectedList)); - for(String removedColumn : removedColumns) + for(String removedColumn : List.of(FILTER_BOOL_COL.getLabel())) { - checker().verifyFalse(String.format("The field '%s' is listed in the dialog, it should not be.", removedColumn), + checker().fatal().verifyFalse(String.format("The field '%s' is listed in the dialog, it should not be.", removedColumn), actualList.contains(removedColumn)); } @@ -1709,14 +1716,14 @@ public void testFilterDialogWithViews() throws IOException, CommandException log("Go back to default view. Filter on a column to be removed, then change view that does not include the column."); grid.selectView(VIEW_DEFAULT); - log(String.format("Filter column '%s' to true.", FILTER_BOOL_COL)); - grid.filterColumn(FILTER_BOOL_COL, Filter.Operator.EQUAL, true); + log(String.format("Filter column '%s' to true.", FILTER_BOOL_COL.getName())); + grid.filterColumn(FILTER_BOOL_COL.getName(), Filter.Operator.EQUAL, true); - log(String.format("Change view to '%s' which should remove column '%s' from the grid.", VIEW_FEWER_COLUMNS, FILTER_BOOL_COL)); + log(String.format("Change view to '%s' which should remove column '%s' from the grid.", VIEW_FEWER_COLUMNS, FILTER_BOOL_COL.getName())); grid.selectView(VIEW_FEWER_COLUMNS); // Get the expected sample id. - List filters = List.of(new Filter(FILTER_BOOL_COL, true, Filter.Operator.getOperator("EQUAL"))); + List filters = List.of(new Filter(FILTER_BOOL_COL.getFieldKey().toString(), true, Filter.Operator.getOperator("EQUAL"))); int expectedCount = getExpectedResults(SMALL_SAMPLE_TYPE, VIEW_FEWER_COLUMNS, null, filters).size(); checker().withScreenshot("View_Filtered_Removed_Column_Error") @@ -1735,10 +1742,11 @@ public void testFilterDialogWithViews() throws IOException, CommandException expectedList = new ArrayList<>(); expectedList.add(FILTER_NAME_COL); expectedList.add(FILTER_EXPDATE_COL); - expectedList.add(FILTER_INT_COL); - expectedList.add(FILTER_STRING_COL); - expectedList.add(FILTER_DATE_COL); + expectedList.add(FILTER_INT_COL.getLabel()); + expectedList.add(FILTER_STRING_COL.getLabel()); + expectedList.add(FILTER_DATE_COL.getLabel()); expectedList.add(FILTER_STORED_AMOUNT_COL); + expectedList.add("Status"); // TODo remove me before commit actualList = filterDialog.getAvailableFieldLabels(); @@ -1750,13 +1758,13 @@ public void testFilterDialogWithViews() throws IOException, CommandException // Build the list of expected values. // Get the expected sample id. - filters = List.of(new Filter(FILTER_BOOL_COL, true, Filter.Operator.getOperator("EQUAL"))); - List> strValues = getExpectedResults(SMALL_SAMPLE_TYPE, VIEW_FEWER_COLUMNS, List.of(FILTER_STRING_COL), filters); + filters = List.of(new Filter(FILTER_BOOL_COL.getFieldKey().toString(), true, Filter.Operator.getOperator("EQUAL"))); + List> strValues = getExpectedResults(SMALL_SAMPLE_TYPE, VIEW_FEWER_COLUMNS, List.of(FILTER_STRING_COL.getFieldKey().toString()), filters); expectedList = new ArrayList<>(); for(Map row : strValues) { - String value = row.get(FILTER_STRING_COL).toString(); + String value = row.get(FILTER_STRING_COL.getName()).toString(); if(!expectedList.contains(value)) { @@ -1766,7 +1774,7 @@ public void testFilterDialogWithViews() throws IOException, CommandException expectedList.add(ALL_OPTION); log(String.format("Validate that the list of values for the '%s' is as expected.", FILTER_STRING_COL)); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); actualList = filterDialog.selectFacetTab().getAvailableValues(); Collections.sort(expectedList); @@ -1784,7 +1792,7 @@ public void testFilterDialogWithViews() throws IOException, CommandException grid.selectView(VIEW_EXTRA_COLUMNS); List filterPills = grid.getFilterStatusValues(); - String expectedValue = String.format("%s = true", FILTER_BOOL_COL); + String expectedValue = String.format("%s = true", FILTER_BOOL_COL.getName()); checker().withScreenshot("View_Filter_Pill_Error").verifyTrue(String.format("Filter pills not as expected. There should only be one with value of '%s'", expectedValue), filterPills.size() == 1 && filterPills.get(0).getText().equals(expectedValue)); @@ -1793,11 +1801,12 @@ public void testFilterDialogWithViews() throws IOException, CommandException expectedList = new ArrayList<>(extraColumnsHeaders); expectedList.add(FILTER_NAME_COL); expectedList.add(FILTER_EXPDATE_COL); - expectedList.add(FILTER_STRING_COL); - expectedList.add(FILTER_INT_COL); - expectedList.add(FILTER_BOOL_COL); - expectedList.add(FILTER_DATE_COL); + expectedList.add(FILTER_STRING_COL.getLabel()); + expectedList.add(FILTER_INT_COL.getLabel()); + expectedList.add(FILTER_BOOL_COL.getLabel()); + expectedList.add(FILTER_DATE_COL.getLabel()); expectedList.add(FILTER_STORED_AMOUNT_COL); + expectedList.add("Status"); // TODO remove me before commit filterDialog = grid.getGridBar().openFilterDialog(); @@ -1809,7 +1818,7 @@ public void testFilterDialogWithViews() throws IOException, CommandException checker().verifyEquals("List of available fields not as expected.", expectedList, actualList); - expectedList = Arrays.asList(FILTER_BOOL_COL); + expectedList = Arrays.asList(FILTER_BOOL_COL.getLabel()); actualList = filterDialog.getFilteredFieldLabels(); checker().verifyEquals(String.format("List of filtered fields with view '%s' not as expected.", FILTER_BOOL_COL), @@ -1833,7 +1842,7 @@ public void testFilterDialogWithViews() throws IOException, CommandException actualList.isEmpty()); log("Make sure the values to filter for are as expected."); - filterDialog.selectField(FILTER_STRING_COL); + filterDialog.selectField(FILTER_STRING_COL.getLabel()); actualList = filterDialog.selectFacetTab().getAvailableValues(); // Going to hard code the expected values rather try and be clever and figure them out. @@ -1856,10 +1865,11 @@ public void testFilterDialogWithViews() throws IOException, CommandException * * @param exportedFile The exported csv/tsv file. * @param expectedValues A list of the expected values in the rows. - * @param columns The columns to validate against. + * @param columnNames The columns to validate against. + * @param columnLabels The columns to validate against. * @throws IOException Can be thrown by the file reader. */ - private void validateExportedData(File exportedFile, List> expectedValues, List columns) throws IOException + private void validateExportedData(File exportedFile, List> expectedValues, List columnNames, List columnLabels) throws IOException { try (CSVReader reader = new CSVReader(Readers.getReader(exportedFile), GridBar.ExportType.CSV.getSeparator())) @@ -1885,10 +1895,10 @@ private void validateExportedData(File exportedFile, List> e // Check the values from the identified columns (exported vs. expected). All exported values are stings // so need to convert the expected values. - for (String column : columns) + for (int colIndex = 0; colIndex < columnNames.size(); colIndex++) { - checker().verifyEquals(String.format("Value for column '%s' on row %d not as expected.", column, rowIndex + 1), - expectedRowData.get(column).toString(), actualRowData.get(column)); + checker().verifyEquals(String.format("Value for column '%s' on row %d not as expected.", columnNames.get(colIndex), rowIndex + 1), + expectedRowData.get(columnNames.get(colIndex)).toString(), actualRowData.get(columnLabels.get(colIndex))); } } From 8ad24c1918f5890b738a0216be67fb214bcf219f Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 7 Jul 2025 17:19:36 -0500 Subject: [PATCH 03/12] remove TODOs --- src/org/labkey/test/tests/component/GridPanelTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/org/labkey/test/tests/component/GridPanelTest.java b/src/org/labkey/test/tests/component/GridPanelTest.java index e87595acd7..6686e3e23a 100644 --- a/src/org/labkey/test/tests/component/GridPanelTest.java +++ b/src/org/labkey/test/tests/component/GridPanelTest.java @@ -1002,7 +1002,7 @@ public void testInteractionBetweenDialogTabs() throws IOException, CommandExcept Filter.Operator.getOperator("IN"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); - checker().verifyEquals("Filter did not return the expected number of rows.", // TODO here + checker().verifyEquals("Filter did not return the expected number of rows.", expectedCount, grid.getRecordCount()); } @@ -1746,7 +1746,6 @@ public void testFilterDialogWithViews() throws IOException, CommandException expectedList.add(FILTER_STRING_COL.getLabel()); expectedList.add(FILTER_DATE_COL.getLabel()); expectedList.add(FILTER_STORED_AMOUNT_COL); - expectedList.add("Status"); // TODo remove me before commit actualList = filterDialog.getAvailableFieldLabels(); @@ -1806,7 +1805,6 @@ public void testFilterDialogWithViews() throws IOException, CommandException expectedList.add(FILTER_BOOL_COL.getLabel()); expectedList.add(FILTER_DATE_COL.getLabel()); expectedList.add(FILTER_STORED_AMOUNT_COL); - expectedList.add("Status"); // TODO remove me before commit filterDialog = grid.getGridBar().openFilterDialog(); From f09dc78d378d06f5d1456a081541310de9ef6808 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 8 Jul 2025 09:52:16 -0500 Subject: [PATCH 04/12] remove hardcoded WIDE_PLACEHOLDER --- src/org/labkey/test/util/TestDataGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index b83c7a9002..594ecd07a6 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -580,7 +580,7 @@ public static String randomFieldName(@NotNull String part, int numStartChars, in String randomFieldName = randomName(part, numStartChars, numEndChars, chars, exclusion); TestLogger.log("Generated random field name: " + randomFieldName); - return randomFieldName + WIDE_PLACEHOLDER; // TODO remove this hardcoded WIDE_PLACEHOLDER after a few TC runs + return randomFieldName; } public static String randomChoice(List choices) From 46ea2441bf340350a66ee276dc44eb501c7ae8e5 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 8 Jul 2025 09:53:16 -0500 Subject: [PATCH 05/12] put back comment re: 53197 --- src/org/labkey/test/util/TestDataGenerator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 594ecd07a6..b19442d986 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -576,6 +576,7 @@ public static String randomFieldName(String part, int numStartChars, int numEndC public static String randomFieldName(@NotNull String part, int numStartChars, int numEndChars, @Nullable String exclusion) { // use the characters that we know are encoded in fieldKeys plus characters that we know clients are using + // Issue 53197: Field name with double byte character can cause client side exception in Firefox when trying to customize grid view. String chars = ALL_ILLEGAL_QUERY_KEY_CHARACTERS + " %()=+-[]_|*`'\":;<>?!@#^" + NON_LATIN_STRING + WIDE_PLACEHOLDER ; String randomFieldName = randomName(part, numStartChars, numEndChars, chars, exclusion); From 2b7d109f14ed466ed170b80910dc8db78dfc006b Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 8 Jul 2025 14:08:38 -0500 Subject: [PATCH 06/12] CustomizeView.addItem to use encodeUriPath() --- .../labkey/test/components/CustomizeView.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/components/CustomizeView.java b/src/org/labkey/test/components/CustomizeView.java index e2e801c044..1b882bf740 100644 --- a/src/org/labkey/test/components/CustomizeView.java +++ b/src/org/labkey/test/components/CustomizeView.java @@ -31,6 +31,7 @@ import org.labkey.test.selenium.LazyWebElement; import org.labkey.test.selenium.RefindingWebElement; import org.labkey.test.util.DataRegionTable; +import org.labkey.test.util.EscapeUtil; import org.labkey.test.util.Ext4Helper; import org.labkey.test.util.LogMethod; import org.labkey.test.util.LoggedParam; @@ -378,7 +379,8 @@ private void addItem(String[] fieldKeyParts, String columnName, ViewItemType typ changeTab(type); // Expand all nodes necessary to reveal the desired node. - WebElement fieldRow = expandPivots(fieldKeyParts); + String[] encodedParts = Arrays.stream(fieldKeyParts).map(this::encodeFieldKeyPart).toArray(String[]::new); // Issue 53197 + WebElement fieldRow = expandPivots(encodedParts); WebElement checkbox = Locator.css("input[type=button]").findElement(fieldRow); WebElement rowLabel = Locator.byClass("x4-tree-node-text").findElement(fieldRow); rowLabel.click(); @@ -386,6 +388,19 @@ private void addItem(String[] fieldKeyParts, String columnName, ViewItemType typ itemXPath(type, fieldKeyParts).waitForElement(this, 2_000); } + private String encodeFieldKeyPart(String fieldKeyPart) + { + String _fieldKeyPart = EscapeUtil.encodeUriPath(fieldKeyPart); + if (_fieldKeyPart != null) + { + // Jetty encodes # ? ; but we want to preserve these characters in paths + _fieldKeyPart = _fieldKeyPart.replaceAll("%23", "#"); + _fieldKeyPart = _fieldKeyPart.replaceAll("%3F", "?"); + _fieldKeyPart = _fieldKeyPart.replaceAll("%3B", ";"); + } + return _fieldKeyPart; + } + public void addColumn(String[] fieldKeyParts, String label) { addItem(fieldKeyParts, label, ViewItemType.Columns); From e5403a184392030f03de518199e9cdb31e3366cb Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 8 Jul 2025 15:06:29 -0500 Subject: [PATCH 07/12] Code review feedback for usages of FieldInfo in GridPanelTest --- .../test/tests/component/GridPanelTest.java | 118 +++++++++--------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/src/org/labkey/test/tests/component/GridPanelTest.java b/src/org/labkey/test/tests/component/GridPanelTest.java index 6686e3e23a..cc2000a087 100644 --- a/src/org/labkey/test/tests/component/GridPanelTest.java +++ b/src/org/labkey/test/tests/component/GridPanelTest.java @@ -192,14 +192,14 @@ private void createSmallSampleType() throws IOException, CommandException log(String.format("Create the '%s' view for the '%s' sample type.", VIEW_FEWER_COLUMNS, SMALL_SAMPLE_TYPE)); cv = drtSamples.openCustomizeGrid(); - for(String columnName : List.of(FILTER_BOOL_COL.getFieldKey().toString())) + for(String columnName : List.of(FILTER_BOOL_COL.toString())) { cv.removeColumn(columnName); } cv.saveCustomView(VIEW_FEWER_COLUMNS); log(String.format("Finally create a view named '%s' for '%s' that only has a filter.", VIEW_FILTERED_COLUMN, SMALL_SAMPLE_TYPE)); - drtSamples.setFilter(FILTER_STRING_COL.getFieldKey().toString(), "Contains One Of", String.format("%1$s\n%1$s%2$s", stringSetMembers.get(0), stringSetMembers.get(1))); + drtSamples.setFilter(FILTER_STRING_COL.toString(), "Contains One Of", String.format("%1$s\n%1$s%2$s", stringSetMembers.get(0), stringSetMembers.get(1))); cv = drtSamples.openCustomizeGrid(); cv.saveCustomView(VIEW_FILTERED_COLUMN); @@ -559,7 +559,7 @@ public void testSelectAllButtonWithFilteredResults() QueryGrid grid = beginAtQueryGrid(FILTER_SAMPLE_TYPE); log("Validate that the 'Select All' button works as expected."); - grid.filterColumn(FILTER_STRING_COL.getName(), Filter.Operator.EQUAL, MULTI_PAGE_STRING); + grid.filterColumn(FILTER_STRING_COL, Filter.Operator.EQUAL, MULTI_PAGE_STRING); checker().fatal() .verifyTrue("The 'Select All' button is not present.", grid.hasSelectAllButton()); @@ -593,7 +593,7 @@ public void testSelectAllOnPageWithFilteredResults() QueryGrid grid = beginAtQueryGrid(FILTER_SAMPLE_TYPE); log("Validate the select all check box at the top of the gird works as expected."); - grid.filterColumn(FILTER_STRING_COL.getName(), Filter.Operator.EQUAL, MULTI_PAGE_STRING); + grid.filterColumn(FILTER_STRING_COL, Filter.Operator.EQUAL, MULTI_PAGE_STRING); grid.selectAllOnPage(true); grid.removeColumnFilter(FILTER_STRING_COL.getName()); checker().withScreenshot("Select_All_On_Page_Error") @@ -720,14 +720,14 @@ public void testMultipleFiltersOnOneColumn() throws IOException, CommandExceptio int low = INT_MAX - 3; int high = INT_MAX; - log(String.format("Filter the '%s' for values greater than %d and less than or equal to %d.", FILTER_INT_COL.getName(), low, high)); + log(String.format("Filter the '%s' for values greater than %d and less than or equal to %d.", FILTER_INT_COL, low, high)); - grid.filterColumn(FILTER_INT_COL.getName(), Filter.Operator.GT, low, Filter.Operator.LTE, high); + grid.filterColumn(FILTER_INT_COL, Filter.Operator.GT, low, Filter.Operator.LTE, high); // Query the table to get the expected number of rows. List filters = List.of( - new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN")), - new Filter(FILTER_INT_COL.getFieldKey().toString(), high, Filter.Operator.getOperator("LESS_THAN_OR_EQUAL"))); + new Filter(FILTER_INT_COL.toString(), low, Filter.Operator.getOperator("GREATER_THAN")), + new Filter(FILTER_INT_COL.toString(), high, Filter.Operator.getOperator("LESS_THAN_OR_EQUAL"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().withScreenshot("Multiple_Filters_One_Column_Error") @@ -998,7 +998,7 @@ public void testInteractionBetweenDialogTabs() throws IOException, CommandExcept // Query the table to get the expected number of rows to be returned. List filters = List.of( - new Filter(FILTER_STRING_COL.getFieldKey().toString(), String.format("%s;%s", firstFilterValue, secondFilterValue), + new Filter(FILTER_STRING_COL.toString(), String.format("%s;%s", firstFilterValue, secondFilterValue), Filter.Operator.getOperator("IN"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); @@ -1057,9 +1057,9 @@ public void testSearchAndFilter() throws IOException, CommandException // Query the table to get the expected number of rows to be returned. Will modify this list later so make it mutable. List filters = new ArrayList<>(); - filters.add(new Filter(FILTER_STRING_COL.getFieldKey().toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); - filters.add(new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN"))); - filters.add(new Filter(FILTER_INT_COL.getFieldKey().toString(), high, Filter.Operator.getOperator("LESS_THAN"))); + filters.add(new Filter(FILTER_STRING_COL.toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); + filters.add(new Filter(FILTER_INT_COL.toString(), low, Filter.Operator.getOperator("GREATER_THAN"))); + filters.add(new Filter(FILTER_INT_COL.toString(), high, Filter.Operator.getOperator("LESS_THAN"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Number of rows after filter applied not as expected.", @@ -1074,7 +1074,7 @@ public void testSearchAndFilter() throws IOException, CommandException grid.getGridBar().searchFor(searchString); // Because the search string is specific to the Str column a query can be used to get the expected count. - filters.add(new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); + filters.add(new Filter(FILTER_STRING_COL.toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().withScreenshot("Filter_With_Search_Error") @@ -1090,7 +1090,7 @@ public void testSearchAndFilter() throws IOException, CommandException // Again can use a query to get the expected number of rows from the search. filters = new ArrayList<>(); - filters.add(new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); + filters.add(new Filter(FILTER_STRING_COL.toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Number of rows after filter were cleared not as expected.", @@ -1174,9 +1174,9 @@ public void testFilterPills() throws IOException, CommandException expectedValues, actualValues); List filters = List.of( - new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN")), - new Filter(FILTER_INT_COL.getFieldKey().toString(), high, Filter.Operator.getOperator("LESS_THAN")), - new Filter(FILTER_STRING_COL.getFieldKey().toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); + new Filter(FILTER_INT_COL.toString(), low, Filter.Operator.getOperator("GREATER_THAN")), + new Filter(FILTER_INT_COL.toString(), high, Filter.Operator.getOperator("LESS_THAN")), + new Filter(FILTER_STRING_COL.toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Rows returned after filters applied not as expected.", @@ -1195,8 +1195,8 @@ public void testFilterPills() throws IOException, CommandException } filters = List.of( - new Filter(FILTER_INT_COL.getFieldKey().toString(), low, Filter.Operator.getOperator("GREATER_THAN")), - new Filter(FILTER_STRING_COL.getFieldKey().toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); + new Filter(FILTER_INT_COL.toString(), low, Filter.Operator.getOperator("GREATER_THAN")), + new Filter(FILTER_STRING_COL.toString(), oneOfFilter, Filter.Operator.getOperator("CONTAINS_ONE_OF"))); expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().verifyEquals("Rows returned after filter pill removed not as expected.", @@ -1392,7 +1392,7 @@ public void testSearchIsSameAsContainsFilter() throws IOException, CommandExcept // Identify how many rows should be returned. List filters = List.of( - new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); + new Filter(FILTER_STRING_COL.toString(), searchString, Filter.Operator.getOperator("CONTAINS"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); int actualCount = grid.getRecordCount(); @@ -1453,15 +1453,15 @@ public void testSearchAcrossColumns() throws IOException, CommandException checker().verifyEquals("Number of records returned from search not as expected.", expectedCount, actualCount); - log(String.format("Validate that the result set did not return a row where the search value was in the %s field.", FILTER_INT_COL.getLabel())); + log(String.format("Validate that the result set did not return a row where the search value was in the %s field.", FILTER_INT_COL)); List actualIds = grid.getColumnDataAsText(FILTER_NAME_COL); // Query the table to get a list of samples/rows that should not be in the result from the search. List filters = List.of(new Filter(FILTER_NAME_COL, searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), - new Filter(FILTER_STRING_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), - new Filter(FILTER_EXTEND_CHAR_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), - new Filter(FILTER_INT_COL.getFieldKey().toString(), searchString, Filter.Operator.getOperator("EQUAL"))); + new Filter(FILTER_STRING_COL.toString(), searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), + new Filter(FILTER_EXTEND_CHAR_COL.toString(), searchString, Filter.Operator.getOperator("DOES_NOT_CONTAIN")), + new Filter(FILTER_INT_COL.toString(), searchString, Filter.Operator.getOperator("EQUAL"))); List> rows = getExpectedResults(FILTER_SAMPLE_TYPE, null, Arrays.asList(FILTER_NAME_COL), filters); boolean error = false; @@ -1512,7 +1512,7 @@ public void testFilteringAndSearchingForExtendedCharacters() throws IOException, filterDialog.confirm(); List filters = List.of( - new Filter(FILTER_EXTEND_CHAR_COL.getFieldKey().toString(), EXTEND_RECORD_STRING, Filter.Operator.getOperator("EQUAL"))); + new Filter(FILTER_EXTEND_CHAR_COL.toString(), EXTEND_RECORD_STRING, Filter.Operator.getOperator("EQUAL"))); int expectedCount = getExpectedResults(FILTER_SAMPLE_TYPE, null, null, filters).size(); checker().withScreenshot("Filter_Extended_Error") @@ -1536,16 +1536,15 @@ public void testExport() throws IOException, CommandException log("Filter the grid and validate only the filtered results are exported."); grid.filterColumn(FILTER_STRING_COL, Filter.Operator.EQUAL, MULTI_PAGE_STRING); - List columnsFKs = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL.getFieldKey().toString(), FILTER_INT_COL.getFieldKey().toString(), FILTER_EXTEND_CHAR_COL.getFieldKey().toString()); - List columnNames = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL.getName(), FILTER_INT_COL.getName(), FILTER_EXTEND_CHAR_COL.getName()); - List columnLabels = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL.getLabel(), FILTER_INT_COL.getLabel(), FILTER_EXTEND_CHAR_COL.getLabel()); + List columns = Arrays.asList(new FieldInfo(FILTER_NAME_COL), FILTER_STRING_COL, FILTER_INT_COL, FILTER_EXTEND_CHAR_COL); + List columnsFKs = Arrays.asList(FILTER_NAME_COL, FILTER_STRING_COL.toString(), FILTER_INT_COL.toString(), FILTER_EXTEND_CHAR_COL.toString()); List filters = List.of( - new Filter(FILTER_STRING_COL.getFieldKey().toString(), MULTI_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); + new Filter(FILTER_STRING_COL.toString(), MULTI_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); List> expectedValues = getExpectedResults(FILTER_SAMPLE_TYPE, null, columnsFKs, filters); File exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); - validateExportedData(exportedFile, expectedValues, columnNames, columnLabels); + validateExportedData(exportedFile, expectedValues, columns); log("Validate that if there are selected rows only they are exported."); grid.clearFilters(); @@ -1557,12 +1556,12 @@ public void testExport() throws IOException, CommandException grid.clearFilters(); filters = List.of( - new Filter(FILTER_STRING_COL.getFieldKey().toString(), ONE_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); + new Filter(FILTER_STRING_COL.toString(), ONE_PAGE_STRING, Filter.Operator.getOperator("EQUAL"))); expectedValues = getExpectedResults(FILTER_SAMPLE_TYPE, null, columnsFKs, filters); exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); - validateExportedData(exportedFile, expectedValues, columnNames, columnLabels); + validateExportedData(exportedFile, expectedValues, columns); log(String.format("Using sample type '%s' validate that if a view is selected the expected columns are exported.", SMALL_SAMPLE_TYPE)); @@ -1574,25 +1573,25 @@ public void testExport() throws IOException, CommandException exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); // The extra column added have spaces in the name so the column header in the exported file, so use the header values. - List columns = new ArrayList<>(extraColumnsHeaders); - columns.add(FILTER_DATE_COL.getLabel()); - columns.add(FILTER_NAME_COL); - columns.add(FILTER_BOOL_COL.getLabel()); - columns.add(FILTER_STRING_COL.getLabel()); - columns.add(FILTER_INT_COL.getLabel()); - validateExportedColumnHeader(exportedFile, columns, new ArrayList<>()); + List columnLabels = new ArrayList<>(extraColumnsHeaders); + columnLabels.add(FILTER_DATE_COL.getLabel()); + columnLabels.add(FILTER_NAME_COL); + columnLabels.add(FILTER_BOOL_COL.getLabel()); + columnLabels.add(FILTER_STRING_COL.getLabel()); + columnLabels.add(FILTER_INT_COL.getLabel()); + validateExportedColumnHeader(exportedFile, columnLabels, new ArrayList<>()); log(String.format("Now select the '%s' view.", VIEW_FEWER_COLUMNS)); grid.selectView(VIEW_FEWER_COLUMNS); exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); - columns = new ArrayList<>(); - columns.add(FILTER_DATE_COL.getLabel()); - columns.add(FILTER_NAME_COL); - columns.add(FILTER_STRING_COL.getLabel()); - columns.add(FILTER_INT_COL.getLabel()); - validateExportedColumnHeader(exportedFile, columns, List.of(FILTER_BOOL_COL.getLabel())); + columnLabels = new ArrayList<>(); + columnLabels.add(FILTER_DATE_COL.getLabel()); + columnLabels.add(FILTER_NAME_COL); + columnLabels.add(FILTER_STRING_COL.getLabel()); + columnLabels.add(FILTER_INT_COL.getLabel()); + validateExportedColumnHeader(exportedFile, columnLabels, List.of(FILTER_BOOL_COL.getLabel())); // Test for Issue 46465 (Sample export do not respect filter when samples have been selected) grid = beginAtQueryGrid(FILTER_SAMPLE_TYPE); @@ -1605,7 +1604,7 @@ public void testExport() throws IOException, CommandException int rowsCountBefore = grid.getRecordCount(); - grid.filterColumn(FILTER_INT_COL.getName(), Filter.Operator.GT, 10); + grid.filterColumn(FILTER_INT_COL, Filter.Operator.GT, 10); int rowCountAfter = grid.getRecordCount(); @@ -1616,7 +1615,7 @@ public void testExport() throws IOException, CommandException List> expectedData = new ArrayList<>(); - List intColData = grid.getColumnDataAsText(FILTER_INT_COL.getLabel()); + List intColData = grid.getColumnDataAsText(FILTER_INT_COL); for(String colValue : intColData) { @@ -1627,10 +1626,7 @@ public void testExport() throws IOException, CommandException exportedFile = grid.getGridBar().exportData(GridBar.ExportType.CSV); - validateExportedData(exportedFile, expectedData, - Arrays.asList(FILTER_STRING_COL.getName(), FILTER_INT_COL.getName()), - Arrays.asList(FILTER_STRING_COL.getLabel(), FILTER_INT_COL.getLabel()) - ); + validateExportedData(exportedFile, expectedData, List.of(FILTER_STRING_COL, FILTER_INT_COL)); } } @@ -1716,14 +1712,14 @@ public void testFilterDialogWithViews() throws IOException, CommandException log("Go back to default view. Filter on a column to be removed, then change view that does not include the column."); grid.selectView(VIEW_DEFAULT); - log(String.format("Filter column '%s' to true.", FILTER_BOOL_COL.getName())); - grid.filterColumn(FILTER_BOOL_COL.getName(), Filter.Operator.EQUAL, true); + log(String.format("Filter column '%s' to true.", FILTER_BOOL_COL)); + grid.filterColumn(FILTER_BOOL_COL, Filter.Operator.EQUAL, true); - log(String.format("Change view to '%s' which should remove column '%s' from the grid.", VIEW_FEWER_COLUMNS, FILTER_BOOL_COL.getName())); + log(String.format("Change view to '%s' which should remove column '%s' from the grid.", VIEW_FEWER_COLUMNS, FILTER_BOOL_COL)); grid.selectView(VIEW_FEWER_COLUMNS); // Get the expected sample id. - List filters = List.of(new Filter(FILTER_BOOL_COL.getFieldKey().toString(), true, Filter.Operator.getOperator("EQUAL"))); + List filters = List.of(new Filter(FILTER_BOOL_COL.toString(), true, Filter.Operator.getOperator("EQUAL"))); int expectedCount = getExpectedResults(SMALL_SAMPLE_TYPE, VIEW_FEWER_COLUMNS, null, filters).size(); checker().withScreenshot("View_Filtered_Removed_Column_Error") @@ -1757,8 +1753,8 @@ public void testFilterDialogWithViews() throws IOException, CommandException // Build the list of expected values. // Get the expected sample id. - filters = List.of(new Filter(FILTER_BOOL_COL.getFieldKey().toString(), true, Filter.Operator.getOperator("EQUAL"))); - List> strValues = getExpectedResults(SMALL_SAMPLE_TYPE, VIEW_FEWER_COLUMNS, List.of(FILTER_STRING_COL.getFieldKey().toString()), filters); + filters = List.of(new Filter(FILTER_BOOL_COL.toString(), true, Filter.Operator.getOperator("EQUAL"))); + List> strValues = getExpectedResults(SMALL_SAMPLE_TYPE, VIEW_FEWER_COLUMNS, List.of(FILTER_STRING_COL.toString()), filters); expectedList = new ArrayList<>(); for(Map row : strValues) @@ -1863,16 +1859,16 @@ public void testFilterDialogWithViews() throws IOException, CommandException * * @param exportedFile The exported csv/tsv file. * @param expectedValues A list of the expected values in the rows. - * @param columnNames The columns to validate against. - * @param columnLabels The columns to validate against. + * @param columns The columns to validate against. * @throws IOException Can be thrown by the file reader. */ - private void validateExportedData(File exportedFile, List> expectedValues, List columnNames, List columnLabels) throws IOException + private void validateExportedData(File exportedFile, List> expectedValues, List columns) throws IOException { try (CSVReader reader = new CSVReader(Readers.getReader(exportedFile), GridBar.ExportType.CSV.getSeparator())) { - + List columnNames = columns.stream().map(FieldInfo::getName).toList(); + List columnLabels = columns.stream().map(FieldInfo::getLabel).toList(); List allRows = reader.readAll(); // Use headerRow, the column names, as keys for the map of actual data. From 2d7198d5e7b18d76fa5319c0c923209eed9f6db0 Mon Sep 17 00:00:00 2001 From: cnathe Date: Tue, 8 Jul 2025 15:29:08 -0500 Subject: [PATCH 08/12] CustomizeView.addItem to use encodeUriPath() --- src/org/labkey/test/components/CustomizeView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/components/CustomizeView.java b/src/org/labkey/test/components/CustomizeView.java index 1b882bf740..c498bb5ee5 100644 --- a/src/org/labkey/test/components/CustomizeView.java +++ b/src/org/labkey/test/components/CustomizeView.java @@ -393,10 +393,11 @@ private String encodeFieldKeyPart(String fieldKeyPart) String _fieldKeyPart = EscapeUtil.encodeUriPath(fieldKeyPart); if (_fieldKeyPart != null) { - // Jetty encodes # ? ; but we want to preserve these characters in paths + // Jetty encodes # ? ; ' but we want to preserve these characters in paths _fieldKeyPart = _fieldKeyPart.replaceAll("%23", "#"); _fieldKeyPart = _fieldKeyPart.replaceAll("%3F", "?"); _fieldKeyPart = _fieldKeyPart.replaceAll("%3B", ";"); + _fieldKeyPart = _fieldKeyPart.replaceAll("%27", "'"); } return _fieldKeyPart; } From 4f00bc54be4a1914c58230d94368a450c4bda0a0 Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 9 Jul 2025 16:29:49 -0500 Subject: [PATCH 09/12] fixup CustomizeView after merge from develop --- src/org/labkey/test/components/CustomizeView.java | 15 --------------- src/org/labkey/test/util/TestDataGenerator.java | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/org/labkey/test/components/CustomizeView.java b/src/org/labkey/test/components/CustomizeView.java index 215d6a48aa..2398c2ec2d 100644 --- a/src/org/labkey/test/components/CustomizeView.java +++ b/src/org/labkey/test/components/CustomizeView.java @@ -373,7 +373,6 @@ private void addItem(CharSequence fieldKey, ViewItemType type) changeTab(type); // Expand all nodes necessary to reveal the desired node. - //String[] encodedParts = Arrays.stream(fieldKeyParts).map(this::encodeFieldKeyPart).toArray(String[]::new); // Issue 53197 WebElement fieldRow = expandPivots(fieldKey); WebElement checkbox = Locator.css("input[type=button]").findElement(fieldRow); WebElement rowLabel = Locator.byClass("x4-tree-node-text").findElement(fieldRow); @@ -382,20 +381,6 @@ private void addItem(CharSequence fieldKey, ViewItemType type) itemXPath(type, fieldKey).waitForElement(this, 2_000); } - private String encodeFieldKeyPart(String fieldKeyPart) - { - String _fieldKeyPart = EscapeUtil.encodeUriPath(fieldKeyPart); - if (_fieldKeyPart != null) - { - // Jetty encodes # ? ; ' but we want to preserve these characters in paths - _fieldKeyPart = _fieldKeyPart.replaceAll("%23", "#"); - _fieldKeyPart = _fieldKeyPart.replaceAll("%3F", "?"); - _fieldKeyPart = _fieldKeyPart.replaceAll("%3B", ";"); - _fieldKeyPart = _fieldKeyPart.replaceAll("%27", "'"); - } - return _fieldKeyPart; - } - public void addFilter(CharSequence fieldKey, String filter_type) { addFilter(fieldKey, filter_type, ""); diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index a35446b0fc..8be17a400a 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -592,7 +592,7 @@ public static String randomFieldName(@NotNull String part, int numStartChars, in } TestLogger.log("Generated random field name: " + randomFieldName); - return randomFieldName; + return randomFieldName + WIDE_CHAR; // TODO remove this before merge (added for extra TC testing) } public static String randomChoice(List choices) From e3a93146409ccc2d1c4cf02f3355da722e9a3b8a Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 9 Jul 2025 16:31:58 -0500 Subject: [PATCH 10/12] remove unused import --- src/org/labkey/test/components/CustomizeView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/labkey/test/components/CustomizeView.java b/src/org/labkey/test/components/CustomizeView.java index 2398c2ec2d..4e688abdc5 100644 --- a/src/org/labkey/test/components/CustomizeView.java +++ b/src/org/labkey/test/components/CustomizeView.java @@ -31,7 +31,6 @@ import org.labkey.test.params.FieldKey; import org.labkey.test.selenium.RefindingWebElement; import org.labkey.test.util.DataRegionTable; -import org.labkey.test.util.EscapeUtil; import org.labkey.test.util.Ext4Helper; import org.labkey.test.util.LogMethod; import org.labkey.test.util.LoggedParam; From 3b42951d64e62ddb276f7ca753d6abbaec320479 Mon Sep 17 00:00:00 2001 From: cnathe Date: Thu, 10 Jul 2025 07:55:29 -0500 Subject: [PATCH 11/12] code review feedback for usages of FieldInfo --- src/org/labkey/test/tests/component/GridPanelTest.java | 10 +++++----- src/org/labkey/test/util/TestDataGenerator.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/org/labkey/test/tests/component/GridPanelTest.java b/src/org/labkey/test/tests/component/GridPanelTest.java index cc2000a087..94c0c2197e 100644 --- a/src/org/labkey/test/tests/component/GridPanelTest.java +++ b/src/org/labkey/test/tests/component/GridPanelTest.java @@ -192,14 +192,14 @@ private void createSmallSampleType() throws IOException, CommandException log(String.format("Create the '%s' view for the '%s' sample type.", VIEW_FEWER_COLUMNS, SMALL_SAMPLE_TYPE)); cv = drtSamples.openCustomizeGrid(); - for(String columnName : List.of(FILTER_BOOL_COL.toString())) + for(FieldInfo column : List.of(FILTER_BOOL_COL)) { - cv.removeColumn(columnName); + cv.removeColumn(column); } cv.saveCustomView(VIEW_FEWER_COLUMNS); log(String.format("Finally create a view named '%s' for '%s' that only has a filter.", VIEW_FILTERED_COLUMN, SMALL_SAMPLE_TYPE)); - drtSamples.setFilter(FILTER_STRING_COL.toString(), "Contains One Of", String.format("%1$s\n%1$s%2$s", stringSetMembers.get(0), stringSetMembers.get(1))); + drtSamples.setFilter(FILTER_STRING_COL, "Contains One Of", String.format("%1$s\n%1$s%2$s", stringSetMembers.get(0), stringSetMembers.get(1))); cv = drtSamples.openCustomizeGrid(); cv.saveCustomView(VIEW_FILTERED_COLUMN); @@ -565,7 +565,7 @@ public void testSelectAllButtonWithFilteredResults() .verifyTrue("The 'Select All' button is not present.", grid.hasSelectAllButton()); grid.selectAllRows(); - grid.removeColumnFilter(FILTER_STRING_COL.getName()); + grid.removeColumnFilter(FILTER_STRING_COL); checker().withScreenshot("Select_All_Button_Error") .verifyEquals("Number of selected rows not as expected after filter removed.", String.format(SELECTED_TEXT_FORMAT, MULTI_PAGE_COUNT * DEFAULT_PAGE_SIZE, FILTER_SAMPLE_TYPE_SIZE), grid.getSelectionStatusCount()); @@ -595,7 +595,7 @@ public void testSelectAllOnPageWithFilteredResults() log("Validate the select all check box at the top of the gird works as expected."); grid.filterColumn(FILTER_STRING_COL, Filter.Operator.EQUAL, MULTI_PAGE_STRING); grid.selectAllOnPage(true); - grid.removeColumnFilter(FILTER_STRING_COL.getName()); + grid.removeColumnFilter(FILTER_STRING_COL); checker().withScreenshot("Select_All_On_Page_Error") .verifyEquals("Using check box at top of grid did not select the expected samples.", String.format(SELECTED_TEXT_FORMAT, DEFAULT_PAGE_SIZE, FILTER_SAMPLE_TYPE_SIZE), grid.getSelectionStatusCount()); diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 8be17a400a..a35446b0fc 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -592,7 +592,7 @@ public static String randomFieldName(@NotNull String part, int numStartChars, in } TestLogger.log("Generated random field name: " + randomFieldName); - return randomFieldName + WIDE_CHAR; // TODO remove this before merge (added for extra TC testing) + return randomFieldName; } public static String randomChoice(List choices) From 4cf110a9cad1f1a4bd2448259834a5834468ae86 Mon Sep 17 00:00:00 2001 From: cnathe Date: Thu, 10 Jul 2025 08:38:14 -0500 Subject: [PATCH 12/12] CustomizeView.encodeFieldKeyPart --- .../labkey/test/components/CustomizeView.java | 19 +++++++++++++++++-- .../test/tests/component/GridPanelTest.java | 1 - 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/org/labkey/test/components/CustomizeView.java b/src/org/labkey/test/components/CustomizeView.java index 4e688abdc5..9d8fb0ff73 100644 --- a/src/org/labkey/test/components/CustomizeView.java +++ b/src/org/labkey/test/components/CustomizeView.java @@ -31,6 +31,7 @@ import org.labkey.test.params.FieldKey; import org.labkey.test.selenium.RefindingWebElement; import org.labkey.test.util.DataRegionTable; +import org.labkey.test.util.EscapeUtil; import org.labkey.test.util.Ext4Helper; import org.labkey.test.util.LogMethod; import org.labkey.test.util.LoggedParam; @@ -335,6 +336,20 @@ public enum ViewItemType Sort } + private String encodeFieldKeyPart(String fieldKeyPart) + { + String _fieldKeyPart = EscapeUtil.encodeUriPath(fieldKeyPart); + if (_fieldKeyPart != null) + { + // Jetty encodes # ? ; ' but we want to preserve these characters in paths + _fieldKeyPart = _fieldKeyPart.replaceAll("%23", "#"); + _fieldKeyPart = _fieldKeyPart.replaceAll("%3F", "?"); + _fieldKeyPart = _fieldKeyPart.replaceAll("%3B", ";"); + _fieldKeyPart = _fieldKeyPart.replaceAll("%27", "'"); + } + return _fieldKeyPart; + } + /** * expand customize view fields tree to expose the specified column * @return The row element for the specified column @@ -343,7 +358,7 @@ private WebElement expandPivots(CharSequence fieldKey) { Iterator fieldKeyIterator = Objects.requireNonNull(FieldKey.fromFieldKey(fieldKey), "Invalid fieldKey: " + fieldKey).getIterator(); FieldKey currentFieldKey = fieldKeyIterator.next(); - String dataRecordId = currentFieldKey.toString().toUpperCase(); + String dataRecordId = encodeFieldKeyPart(currentFieldKey.toString().toUpperCase()); while (fieldKeyIterator.hasNext()) { @@ -358,7 +373,7 @@ private WebElement expandPivots(CharSequence fieldKey) WebDriverWrapper.waitFor(() -> Locator.css("tr[data-recordid] + tr:not(.x4-grid-row)").findElements(getComponentElement()).isEmpty(), 2000); // Spacer row appears during expansion animation currentFieldKey = fieldKeyIterator.next(); - dataRecordId = currentFieldKey.toString().toUpperCase(); + dataRecordId = encodeFieldKeyPart(currentFieldKey.toString().toUpperCase()); } return Locator.tag("tr").withClass("x4-grid-data-row").withAttribute("data-recordid", dataRecordId).findElement(getComponentElement()); diff --git a/src/org/labkey/test/tests/component/GridPanelTest.java b/src/org/labkey/test/tests/component/GridPanelTest.java index 94c0c2197e..99711eba1f 100644 --- a/src/org/labkey/test/tests/component/GridPanelTest.java +++ b/src/org/labkey/test/tests/component/GridPanelTest.java @@ -78,7 +78,6 @@ public class GridPanelTest extends GridPanelBaseTest private static final String VIEW_FILTERED_COLUMN = "Filtered_Column"; private static final List extraColumnsNames = Arrays.asList("IsAliquot", "genId"); // Special case for adding the columns to the view and calling getRows api. private static final List extraColumnsHeaders = Arrays.asList("Is Aliquot", "Gen Id"); // The column headers as they appear in the UI and exported file. -// private static final List removedColumns = Arrays.asList(FILTER_BOOL_COL); // Various values used to populate Str field for records. Also used in filtering/searching. // Note: Small_SampleType is populated with random data and will have none of these values.