CheckboxElement.java

package org.vaadin.addons.dramafinder.element;

import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.options.AriaRole;
import org.vaadin.addons.dramafinder.element.shared.FocusableElement;
import org.vaadin.addons.dramafinder.element.shared.HasAriaLabelElement;
import org.vaadin.addons.dramafinder.element.shared.HasCheckedElement;
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.HasValidationPropertiesElement;
import org.vaadin.addons.dramafinder.element.utils.AccessibleNameLocator;

import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

/**
 * PlaywrightElement for {@code <vaadin-checkbox>}.
 * <p>
 * Provides helpers to read and modify checked/indeterminate state and
 * access common mixins for label, helper, validation and enablement.
 * The checked-state API comes from {@link HasCheckedElement}.
 */
@PlaywrightElement(CheckboxElement.FIELD_TAG_NAME)
public class CheckboxElement extends VaadinElement
        implements FocusableElement, HasAriaLabelElement, HasCheckedElement, HasEnabledElement,
        HasHelperElement, HasStyleElement, HasLabelElement, HasValidationPropertiesElement {

    public static final String FIELD_TAG_NAME = "vaadin-checkbox";

    /**
     * Create a new {@code CheckboxElement}.
     *
     * @param locator the locator for the {@code <vaadin-checkbox>} element
     */
    public CheckboxElement(Locator locator) {
        super(locator);
    }

    /**
     * Check or uncheck the checkbox.
     *
     * @param checked {@code true} to check, {@code false} to uncheck
     * @deprecated use {@link #setChecked(boolean)} instead; this name reads as a
     *             getter and is inconsistent with the other checkbox-like
     *             elements.
     */
    @Deprecated(forRemoval = true)
    public void isChecked(boolean checked) {
        setChecked(checked);
    }

    /**
     * Whether the checkbox is in indeterminate state.
     *
     * @return {@code true} when indeterminate
     */
    public boolean isIndeterminate() {
        return getLocator().getAttribute("indeterminate") != null;
    }

    /**
     * Assert that the checkbox is indeterminate.
     */
    public void assertIndeterminate() {
        assertThat(getLocator()).hasAttribute("indeterminate", "");
    }

    /**
     * Assert that the checkbox is not indeterminate.
     */
    public void assertNotIndeterminate() {
        assertThat(getLocator()).not().hasAttribute("indeterminate", "");
    }

    /**
     * Set the indeterminate state.
     *
     * @param indeterminate {@code true} to set indeterminate
     */
    public void setIndeterminate(boolean indeterminate) {
        getLocator().evaluate("(el, val) => el.indeterminate = val", indeterminate);
    }

    /**
     * Get a {@code CheckboxElement} by its accessible label.
     * <p>
     * Page-level lookup: the label is matched case-insensitively as a substring
     * and the first match wins.
     *
     * @param page  the Playwright page
     * @param label the accessible label of the checkbox
     * @return the matching {@code CheckboxElement}
     */
    public static CheckboxElement getByLabel(Page page, String label) {
        return new CheckboxElement(
                page.locator(FIELD_TAG_NAME)
                        .filter(new Locator.FilterOptions()
                                .setHas(page.getByRole(AriaRole.CHECKBOX,
                                        new Page.GetByRoleOptions().setName(label)))
                        ).first());
    }

    /**
     * Get a {@code CheckboxElement} by its accessible label within a given scope.
     * <p>
     * Item-within-container lookup: the label must match the checkbox's full
     * accessible name, so {@code "Option 1"} no longer resolves to
     * {@code "Option 10"}. Two checkboxes sharing the label inside the scope fail
     * with a Playwright strict-mode error.
     *
     * @param locator the locator to search within (e.g. a checkbox group)
     * @param label   the full accessible label of the checkbox
     * @return the matching {@code CheckboxElement}
     */
    public static CheckboxElement getByLabel(Locator locator, String label) {
        return new CheckboxElement(
                AccessibleNameLocator.findExact(locator, FIELD_TAG_NAME, AriaRole.CHECKBOX, label));
    }
}