litRenderer) {
+ if ((LitRendererTestUtil.getProperties(litRenderer, this::getField)
+ .stream()
+ .allMatch(propertyName -> propertyName.equals("label")))
+ && (LitRendererTestUtil
+ .getFunctionNames(litRenderer, this::getField)
+ .isEmpty())) {
+ return getLitRendererPropertyValue(index, "label",
+ String.class);
+ } else {
+ throw new UnsupportedOperationException(
+ "VirtualListTester is unable to get item text when VirtualList uses a LitRenderer.");
+ }
+ }
+
+ throw new UnsupportedOperationException(
+ "VirtualListTester is unable to get item text for this VirtualList's renderer.");
+ }
+
+ /**
+ * Get an initialized copy of the component for the item.
+ *
+ * Note, this is not the actual component.
+ *
+ * @param index
+ * the zero-based index of the item
+ * @return initialized component for the target item
+ * @throws IllegalArgumentException
+ * when the VirtualList is not using a ComponentRenderer
+ */
+ public Component getItemComponent(int index) {
+ ensureVisible();
+
+ if (getItemRenderer() instanceof ComponentRenderer, Y> componentRenderer) {
+ var item = getItem(index);
+ return componentRenderer.createComponent(item);
+ }
+ throw new IllegalArgumentException(
+ "VirtualList doesn't use a ComponentRenderer.");
+ }
+
+ @SuppressWarnings("unchecked")
+ private Renderer getItemRenderer() {
+ var rendererField = getField("renderer");
+ try {
+ return (Renderer) rendererField.get(getComponent());
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Get property value for item's LitRenderer.
+ *
+ * @param index
+ * the zero-based index of the item
+ * @param propertyName
+ * the name of the LitRenderer property
+ * @param propertyClass
+ * the class of the value of the LitRenderer property
+ * @param
+ * the type of the LitRenderer property
+ * @return value of the LitRenderer property
+ * @throws IllegalArgumentException
+ * when the VirtualList is not using a LitRenderer or when the
+ * given type of the property does not match the actual property
+ * type
+ */
+ public V getLitRendererPropertyValue(int index, String propertyName,
+ Class propertyClass) {
+ ensureVisible();
+
+ if (getItemRenderer() instanceof LitRenderer litRenderer) {
+ return LitRendererTestUtil.getPropertyValue(litRenderer,
+ this::getField, this::getItem, index, propertyName,
+ propertyClass);
+ } else {
+ throw new IllegalArgumentException(
+ "This VirtualList doesn't use a LitRenderer.");
+ }
+ }
+
+ /**
+ * Invoke named function for item's LitRenderer using the supplied JSON
+ * arguments.
+ *
+ * @param index
+ * the zero-based index of the item
+ * @param functionName
+ * the name of the LitRenderer function to invoke
+ * @param jsonArray
+ * the arguments to pass to the function
+ *
+ * @see #invokeLitRendererFunction(int, String)
+ * @throws IllegalArgumentException
+ * when the VirtualList is not using a LitRenderer
+ */
+ public void invokeLitRendererFunction(int index, String functionName,
+ JsonArray jsonArray) {
+ ensureVisible();
+
+ if (getItemRenderer() instanceof LitRenderer litRenderer) {
+ LitRendererTestUtil.invokeFunction(litRenderer, this::getField,
+ this::getItem, index, functionName, jsonArray);
+ } else {
+ throw new IllegalArgumentException(
+ "This VirtualList doesn't use a LitRenderer.");
+ }
+ }
+
+ /**
+ * Invoke named function for item's LitRenderer.
+ *
+ * @param index
+ * the zero-based index of the item
+ * @param functionName
+ * the name of the LitRenderer function to invoke
+ *
+ * @see #invokeLitRendererFunction(int, String, JsonArray)
+ * @throws IllegalArgumentException
+ * when the VirtualList is not using a LitRenderer
+ */
+ public void invokeLitRendererFunction(int index, String functionName) {
+ invokeLitRendererFunction(index, functionName, Json.createArray());
+ }
+
+ private Query saneQuery() {
+ return new Query<>(0, SANE_FETCH_LIMIT, Collections.emptyList(), null,
+ null);
+ }
+
+}
diff --git a/vaadin-testbench-unit-shared/src/main/java/com/vaadin/testbench/unit/LitRendererTestUtil.java b/vaadin-testbench-unit-shared/src/main/java/com/vaadin/testbench/unit/LitRendererTestUtil.java
new file mode 100644
index 000000000..a1131e37b
--- /dev/null
+++ b/vaadin-testbench-unit-shared/src/main/java/com/vaadin/testbench/unit/LitRendererTestUtil.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2000-2024 Vaadin Ltd
+ *
+ * This program is available under Vaadin Commercial License and Service Terms.
+ *
+ * See for the full
+ * license.
+ */
+package com.vaadin.testbench.unit;
+
+import com.vaadin.flow.data.renderer.LitRenderer;
+import com.vaadin.flow.function.SerializableBiConsumer;
+import com.vaadin.flow.function.ValueProvider;
+import elemental.json.JsonArray;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.IntFunction;
+
+/**
+ * Utility methods for unit testing properties and functions of LitRenderers.
+ */
+public class LitRendererTestUtil {
+
+ private LitRendererTestUtil() throws InstantiationException {
+ throw new InstantiationException(LitRendererTestUtil.class.getName()
+ + " should not be instantiated");
+ }
+
+ /**
+ * Gets the property names for the supplied {@link LitRenderer} using the
+ * given field getter.
+ *
+ * @param litRenderer
+ * the LitRenderer with properties to get
+ * @param fieldGetter
+ * the field getter of the ComponentTester
+ * @return the set of property names of the LitRenderer
+ * @param
+ * the type being renderer by the LitRenderer
+ */
+ public static Set getProperties(LitRenderer litRenderer,
+ BiFunction, String, Field> fieldGetter) {
+ var valueProvidersField = fieldGetter.apply(LitRenderer.class,
+ "valueProviders");
+ try {
+ @SuppressWarnings("unchecked")
+ var valueProviders = (Map>) valueProvidersField
+ .get(litRenderer);
+ return valueProviders.keySet();
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static ValueProvider findProperty(
+ LitRenderer litRenderer,
+ BiFunction, String, Field> fieldGetter,
+ String propertyName) {
+ var valueProvidersField = fieldGetter.apply(LitRenderer.class,
+ "valueProviders");
+ try {
+ @SuppressWarnings("unchecked")
+ var valueProviders = (Map>) valueProvidersField
+ .get(litRenderer);
+ var valueProvider = valueProviders.get(propertyName);
+ if (valueProvider == null) {
+ throw new IllegalArgumentException("Property " + propertyName
+ + " is not registered in LitRenderer.");
+ }
+ return valueProvider;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the property value for the supplied {@link LitRenderer}.
+ *
+ * @param litRenderer
+ * the LitRenderer with properties to get
+ * @param fieldGetter
+ * the field getter of the ComponentTester
+ * @param itemGetter
+ * the getter for the item rendered by the LitRenderer
+ * @param index
+ * the index of the item rendered by the LitRenderer
+ * @param propertyName
+ * the name of the property of the LitRenderer
+ * @param propertyClass
+ * the type of the property value
+ * @return the property value
+ * @param
+ * the type being renderer by the LitRenderer
+ * @param
+ * the type of the property value
+ * @throws IllegalArgumentException
+ * when the type of property value does not match propertyClass
+ */
+ public static V getPropertyValue(LitRenderer litRenderer,
+ BiFunction, String, Field> fieldGetter,
+ IntFunction itemGetter, int index, String propertyName,
+ Class propertyClass) {
+ var valueProvider = findProperty(litRenderer, fieldGetter,
+ propertyName);
+ var untypedValue = valueProvider.apply(itemGetter.apply(index));
+ if (propertyClass.isInstance(untypedValue)) {
+ return propertyClass.cast(untypedValue);
+ } else {
+ throw new IllegalArgumentException(
+ "Type of property value does not match propertyClass - expected %s, found %s."
+ .formatted(propertyClass.getCanonicalName(),
+ untypedValue.getClass()
+ .getCanonicalName()));
+ }
+ }
+
+ /**
+ * Gets the function names for the supplied {@link LitRenderer} using the
+ * given field getter.
+ *
+ * @param litRenderer
+ * the LitRenderer with properties to get
+ * @param fieldGetter
+ * the field getter of the ComponentTester
+ * @return the set of function names of the LitRenderer
+ * @param
+ * the type being renderer by the LitRenderer
+ */
+ public static Set getFunctionNames(LitRenderer litRenderer,
+ BiFunction, String, Field> fieldGetter) {
+ var clientCallablesField = fieldGetter.apply(LitRenderer.class,
+ "clientCallables");
+ try {
+ @SuppressWarnings("unchecked")
+ var clientCallables = (Map>) clientCallablesField
+ .get(litRenderer);
+ return clientCallables.keySet();
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static SerializableBiConsumer findFunction(
+ LitRenderer litRenderer,
+ BiFunction, String, Field> fieldGetter,
+ String functionName) {
+ var clientCallablesField = fieldGetter.apply(LitRenderer.class,
+ "clientCallables");
+ try {
+ @SuppressWarnings("unchecked")
+ var clientCallables = (Map>) clientCallablesField
+ .get(litRenderer);
+ var callable = clientCallables.get(functionName);
+ if (callable == null) {
+ throw new IllegalArgumentException("Function " + functionName
+ + " is not registered in LitRenderer.");
+ }
+ return callable;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Invokes the function by name for the supplied {@link LitRenderer} using
+ * the given field getter.
+ *
+ * @param litRenderer
+ * the LitRenderer with properties to get
+ * @param fieldGetter
+ * the field getter of the ComponentTester
+ * @param itemGetter
+ * the getter for the item rendered by the LitRenderer
+ * @param index
+ * the index of the item rendered by the LitRenderer
+ * @param functionName
+ * the name of the function of the LitRenderer
+ * @param jsonArray
+ * additional parameters to pass to the function
+ * @param
+ * the type being renderer by the LitRenderer
+ * @throws IllegalArgumentException
+ * when the function is not registered in LitRenderer
+ */
+ public static void invokeFunction(LitRenderer litRenderer,
+ BiFunction, String, Field> fieldGetter,
+ IntFunction itemGetter, int index, String functionName,
+ JsonArray jsonArray) {
+ var callable = findFunction(litRenderer, fieldGetter, functionName);
+ callable.accept(itemGetter.apply(index), jsonArray);
+ }
+
+}
diff --git a/vaadin-testbench-unit-shared/src/main/java/com/vaadin/testbench/unit/TesterWrappers.java b/vaadin-testbench-unit-shared/src/main/java/com/vaadin/testbench/unit/TesterWrappers.java
index 22381d21f..6566b7444 100644
--- a/vaadin-testbench-unit-shared/src/main/java/com/vaadin/testbench/unit/TesterWrappers.java
+++ b/vaadin-testbench-unit-shared/src/main/java/com/vaadin/testbench/unit/TesterWrappers.java
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2000-2022 Vaadin Ltd
+/*
+ * Copyright (C) 2000-2024 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
@@ -8,8 +8,6 @@
*/
package com.vaadin.testbench.unit;
-import java.math.BigDecimal;
-
import com.vaadin.flow.component.accordion.Accordion;
import com.vaadin.flow.component.accordion.AccordionTester;
import com.vaadin.flow.component.button.Button;
@@ -124,6 +122,10 @@
import com.vaadin.flow.component.timepicker.TimePickerTester;
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.UploadTester;
+import com.vaadin.flow.component.virtuallist.VirtualList;
+import com.vaadin.flow.component.virtuallist.VirtualListTester;
+
+import java.math.BigDecimal;
@SuppressWarnings("unchecked")
public interface TesterWrappers {
@@ -433,4 +435,12 @@ default ChartTester test(Chart chart) {
default SideNavTester test(SideNav sideNav) {
return BaseUIUnitTest.internalWrap(SideNavTester.class, sideNav);
}
+
+ default VirtualListTester, V> test(VirtualList virtualList) {
+ return BaseUIUnitTest.internalWrap(VirtualListTester.class, virtualList);
+ }
+
+ default VirtualListTester, V> test(VirtualList virtualList, Class itemType) {
+ return BaseUIUnitTest.internalWrap(VirtualListTester.class, virtualList);
+ }
}
diff --git a/vaadin-testbench-unit/pom.xml b/vaadin-testbench-unit/pom.xml
index 96dcfe12e..dd40829ac 100644
--- a/vaadin-testbench-unit/pom.xml
+++ b/vaadin-testbench-unit/pom.xml
@@ -30,8 +30,8 @@
- 1.6.21
- 1.6.21
+ 1.9.20
+ 1.9.20
4.13.2