CheckboxGroupElement.java
package org.vaadin.addons.dramafinder.element;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.options.AriaRole;
import org.vaadin.addons.dramafinder.element.shared.HasEnabledElement;
import org.vaadin.addons.dramafinder.element.shared.HasHelperElement;
import org.vaadin.addons.dramafinder.element.shared.HasLabelElement;
import org.vaadin.addons.dramafinder.element.shared.HasStyleElement;
import org.vaadin.addons.dramafinder.element.shared.HasThemeElement;
import org.vaadin.addons.dramafinder.element.shared.HasTooltipElement;
import org.vaadin.addons.dramafinder.element.shared.HasValidationPropertiesElement;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
/**
* PlaywrightElement for {@code <vaadin-checkbox-group>}.
* <p>
* Provides helpers to select and deselect the group's checkboxes by their
* label, to read the current selection and to assert it. Individual items are
* exposed as {@link CheckboxElement} instances so the full checkbox API is
* available for them.
* <p>
* The group's client-side {@code value} holds opaque server-generated item
* keys, so this element identifies items by their visible label instead.
*/
@PlaywrightElement(CheckboxGroupElement.FIELD_TAG_NAME)
public class CheckboxGroupElement extends VaadinElement
implements HasLabelElement, HasHelperElement, HasValidationPropertiesElement,
HasEnabledElement, HasThemeElement, HasStyleElement, HasTooltipElement {
public static final String FIELD_TAG_NAME = "vaadin-checkbox-group";
/**
* Create a new {@code CheckboxGroupElement}.
*
* @param locator the locator for the {@code <vaadin-checkbox-group>} element
*/
public CheckboxGroupElement(Locator locator) {
super(locator);
}
// ── Items ──────────────────────────────────────────────────────────
/**
* Get all checkboxes of the group, in DOM order.
*
* @return the group's checkboxes, empty when the group has no items
*/
public List<CheckboxElement> getCheckboxes() {
Locator checkboxes = getCheckboxLocator();
int count = checkboxes.count();
List<CheckboxElement> elements = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
elements.add(new CheckboxElement(checkboxes.nth(i)));
}
return elements;
}
/**
* Get a single checkbox of the group by its label.
*
* @param label the accessible label of the checkbox (ARIA role {@code checkbox})
* @return the matching {@code CheckboxElement}
*/
public CheckboxElement getCheckbox(String label) {
return CheckboxElement.getByLabel(getLocator(), label);
}
/**
* Count the checkboxes of the group.
*
* @return the number of checkboxes
*/
public int getCheckboxCount() {
return getCheckboxLocator().count();
}
/**
* Assert that the group contains exactly the expected number of checkboxes.
*
* @param expected expected checkbox count
*/
public void assertCheckboxCount(int expected) {
assertThat(getCheckboxLocator()).hasCount(expected);
}
// ── Selection ──────────────────────────────────────────────────────
/**
* Select the checkboxes matching the given labels. Already selected
* checkboxes are left untouched.
*
* @param labels labels of the checkboxes to select
*/
public void selectByLabel(String... labels) {
for (String label : labels) {
getCheckbox(label).check();
}
waitForVaadinIdle();
}
/**
* Deselect the checkboxes matching the given labels. Already deselected
* checkboxes are left untouched.
*
* @param labels labels of the checkboxes to deselect
*/
public void deselectByLabel(String... labels) {
for (String label : labels) {
getCheckbox(label).uncheck();
}
waitForVaadinIdle();
}
/**
* Deselect every checkbox of the group.
*/
public void deselectAll() {
Locator checked = getCheckedCheckboxLocator();
for (int i = checked.count() - 1; i >= 0; i--) {
new CheckboxElement(checked.nth(i)).uncheck();
}
waitForVaadinIdle();
}
/**
* Get the labels of the currently selected checkboxes, in DOM order.
* <p>
* Labels are used rather than the group's {@code value} array because the
* latter contains server-generated item keys that carry no meaning in a
* test.
*
* @return the labels of the selected checkboxes, empty when nothing is selected
*/
public List<String> getSelectedValues() {
Object result = getLocator().evaluate(
"el => Array.from(el.querySelectorAll('" + CheckboxElement.FIELD_TAG_NAME + "'))"
+ ".filter(cb => cb.checked)"
+ ".map(cb => cb.label != null ? cb.label : cb.textContent.trim())");
if (result instanceof List<?> list) {
List<String> labels = new ArrayList<>(list.size());
for (Object label : list) {
labels.add(String.valueOf(label));
}
return labels;
}
return Collections.emptyList();
}
/**
* Assert that exactly the checkboxes with the given labels are selected.
* Passing no label (or {@code null}) asserts that nothing is selected.
*
* @param labels labels of the checkboxes expected to be selected
*/
public void assertSelected(String... labels) {
if (labels == null || labels.length == 0) {
assertThat(getCheckedCheckboxLocator()).hasCount(0);
return;
}
assertThat(getCheckedCheckboxLocator()).hasCount(labels.length);
for (String label : labels) {
getCheckbox(label).assertChecked();
}
}
// ── Static factories ───────────────────────────────────────────────
/**
* Get a {@code CheckboxGroupElement} by its accessible label.
*
* @param page the Playwright page
* @param label the accessible label of the group (ARIA role {@code group})
* @return the matching {@code CheckboxGroupElement}
*/
public static CheckboxGroupElement getByLabel(Page page, String label) {
return new CheckboxGroupElement(
page.locator(FIELD_TAG_NAME).and(
page.getByRole(AriaRole.GROUP,
new Page.GetByRoleOptions().setName(label))).first());
}
/**
* Get a {@code CheckboxGroupElement} by its accessible label within a given scope.
*
* @param locator the locator to search within
* @param label the accessible label of the group (ARIA role {@code group})
* @return the matching {@code CheckboxGroupElement}
*/
public static CheckboxGroupElement getByLabel(Locator locator, String label) {
return new CheckboxGroupElement(
locator.locator(FIELD_TAG_NAME).and(
locator.page().getByRole(AriaRole.GROUP,
new Page.GetByRoleOptions().setName(label))).first());
}
// ── Internal ───────────────────────────────────────────────────────
private Locator getCheckboxLocator() {
return getLocator().locator(CheckboxElement.FIELD_TAG_NAME);
}
private Locator getCheckedCheckboxLocator() {
return getLocator().locator(CheckboxElement.FIELD_TAG_NAME + ":has(input:checked)");
}
}