testbench icon indicating copy to clipboard operation
testbench copied to clipboard

Add TestBench API/support for accessing and testing Grid inline editor components

Open MatthewVaadin opened this issue 1 year ago • 1 comments

When using the inline editing feature of a Grid component, there isn't any API in TestBench to access and test editor components.

Consider the following view (taken from the example in the docs):

Grid<Person> grid = new Grid<>(Person.class, false);
Editor<Person> editor = grid.getEditor();

Grid.Column<Person> firstNameColumn = grid
        .addColumn(Person::getFirstName).setHeader("First name")
        .setWidth("120px").setFlexGrow(0);
Grid.Column<Person> lastNameColumn = grid.addColumn(Person::getLastName)
        .setHeader("Last name").setWidth("120px").setFlexGrow(0);
Grid.Column<Person> emailColumn = grid.addColumn(Person::getEmail)
        .setHeader("Email");
Grid.Column<Person> editColumn = grid.addComponentColumn(person -> {
    Button editButton = new Button("Edit");
    editButton.addClickListener(e -> {
        if (editor.isOpen())
            editor.cancel();
        grid.getEditor().editItem(person);
    });
    return editButton;
}).setWidth("150px").setFlexGrow(0);

Binder<Person> binder = new Binder<>(Person.class);
editor.setBinder(binder);
editor.setBuffered(true);

TextField firstNameField = new TextField();
firstNameField.setWidthFull();
binder.forField(firstNameField)
        .asRequired("First name must not be empty")
        .withStatusLabel(firstNameValidationMessage)
        .bind(Person::getFirstName, Person::setFirstName);
firstNameColumn.setEditorComponent(firstNameField);

TextField lastNameField = new TextField();
lastNameField.setWidthFull();
binder.forField(lastNameField).asRequired("Last name must not be empty")
        .withStatusLabel(lastNameValidationMessage)
        .bind(Person::getLastName, Person::setLastName);
lastNameColumn.setEditorComponent(lastNameField);

EmailField emailField = new EmailField();
emailField.setWidthFull();
binder.forField(emailField).asRequired("Email must not be empty")
        .withValidator(
                new EmailValidator("Enter a valid email address"))
        .withStatusLabel(emailValidationMessage)
        .bind(Person::getEmail, Person::setEmail);
emailColumn.setEditorComponent(emailField);

Button saveButton = new Button("Save", e -> editor.save());
Button cancelButton = new Button(VaadinIcon.CLOSE.create(),
        e -> editor.cancel());
cancelButton.addThemeVariants(ButtonVariant.LUMO_ICON,
        ButtonVariant.LUMO_ERROR);
HorizontalLayout actions = new HorizontalLayout(saveButton,
        cancelButton);
actions.setPadding(false);
editColumn.setEditorComponent(actions);

If I try to test the "Edit" button:

var grid = $(Grid.java).first();
var editColumn = test(grid).getCellComponent(0, 3);
var editButton = $(Button.class, editColumn).first();
test(editButton).click();

I get the following error: java.lang.IllegalStateException: Button[caption='Edit'] is not usable

To work around this, I can call click() directly on the component:

...
editButton.click();

var firstNameColumn = (Grid.Column) grid.getColumns().get(0);
var firstNameField = (TextField) firstNameColumn.getEditorComponent();

assertThat(firstNameField.getValue()).isEqualTo("Aria");

Then the assertion fails because the value in the field is empty. I can "force" it to update by doing another query:

...
firstNameField = $(TextField.class, firstNameField).first(); // Doesn't have to involve the first name field

assertThat(firstNameField.getValue()).isEqualTo("Aria");

This time the assertion passes.

There are two issues that this highlights:

  1. It seems that some simple things like testing components in a grid doesn't work using the tester classes.
  2. There is no API to test inline editing.

The second used to be possible in Vaadin 8 (GridEditorTest.java).

MatthewVaadin avatar Jan 30 '25 11:01 MatthewVaadin

Example project with failing tests to show the issues: https://github.com/MatthewVaadin/grid-testing

MatthewVaadin avatar Jan 30 '25 11:01 MatthewVaadin