vaadin / flow-components

Java counterpart of Vaadin Web Components
101 stars 66 forks source link

Unable to test drag'n'dropping rows in a grid using Java #1119

Open Artur- opened 4 years ago

Artur- commented 4 years ago

Assumption: This would work

public class ExampleIT extends TestBenchTestCase {
    @Rule
    public ScreenshotOnFailureRule screenshotOnFailure = new ScreenshotOnFailureRule(this, true);

    @BeforeClass
    public static void setupClass() {
        WebDriverManager.chromedriver().setup();
    }

    @Test
    public void tst() {
        setDriver(new ChromeDriver());
        getDriver().get("https://cdn.vaadin.com/vaadin-grid/5.5.3/demo/#grid-drag-and-drop-demos");
        AtomicReference<GridElement> gridRef = new AtomicReference<>();
        waitUntil(driver -> {
            try {
                gridRef.set($("vaadin-component-demo").first().$("grid-drag-and-drop-demos").first()
                        .$("vaadin-demo-snippet").id("grid-drag-and-drop-demos-row-reordering")
                        .$("vaadin-demo-shadow-dom-renderer").first().$(GridElement.class).first());
                return true;
            } catch (Exception e) {
                return false;
            }
        });
        GridElement grid = gridRef.get();

        Assert.assertEquals("Laura", grid.getCell(0, 0).getText());
        Assert.assertEquals("Fabien", grid.getCell(1, 0).getText());
        Assert.assertEquals("Ruben", grid.getCell(2, 0).getText());

        GridTHTDElement cellInFirst = grid.getCell("Laura");
        GridTHTDElement cellInThird = grid.getCell("Ruben");

        new Actions(getDriver()).clickAndHold(cellInFirst).moveToElement(cellInThird, 0, -10).release().perform();

        Assert.assertEquals("Fabien", grid.getCell(0, 0).getText());
        Assert.assertEquals("Laura", grid.getCell(1, 0).getText());
        Assert.assertEquals("Ruben", grid.getCell(2, 0).getText());
    }

}

Reality The drag'n'drop operation does nothing and rows remain in the old order

Potential cause https://bugs.chromium.org/p/chromedriver/issues/detail?id=2695

What this project could provide

cellInFirst.dragTo(cellInThird, Position.BELOW);

implemented using JS so that grid would perform the drag'n'drop operation without needing native HTML5 d'n'd support in Chromedriver

Artur- commented 4 years ago

This is the implementation I have used in a project

import com.vaadin.flow.component.grid.testbench.GridElement;
import com.vaadin.flow.component.grid.testbench.GridTHTDElement;
import com.vaadin.testbench.TestBenchElement;

public class DragAndDropGridElement extends GridElement {

    public enum Position {
        ON_TOP("on-top", "event.clientY = rect.top + rect.height / 2"), //
        ABOVE("above", "event.clientY = rect.top"), //
        BELOW("below", "event.clientY = rect.bottom"), //
        UNDER("under", "event.clientY = rect.bottom + rect.height / 2");

        private String identifier;
        private String code;

        private Position(String identifier, String code) {
            this.identifier = identifier;
            this.code = code;
        }

        public String getIdentifier() {
            return identifier;
        }

        public String getEventCode() {
            return code;
        }
    };

    public void drag(GridTHTDElement source, GridTHTDElement target, Position position) {
        fireDragStart(source);
        fireDrop(target, position);
    }

    private void fireDragStart(GridTHTDElement source) {
        TestBenchElement src = (TestBenchElement) source.getContext();
        executeScript(createEvent("dragstart") //
                + "window.tbDragData = {text: 'foo'};"
                + "event.dataTransfer = { setDragImage: () => {}, setData: (type, data) => window.tbDragData[type] = data };"
                + "arguments[0].dispatchEvent(event);", src);
    }

    private String createEvent(String name) {
        return "const event = new Event('" + name + "', { bubbles: true, cancelable: true, composed: true });";
    }

    private void fireDrop(GridTHTDElement target, Position position) {
        TestBenchElement tgt = (TestBenchElement) target.getContext();

        executeScript(createEvent("dragover") //
                + "const row = arguments[0];" //
                + "const rect = row.getBoundingClientRect();" //
                + position.getEventCode() + ";" //
                + "row.dispatchEvent(event);", tgt); //

        executeScript(createEvent("drop") //
                + "event.dataTransfer = { getData: function(type) {return window.tbDragData[type];}, types: Object.keys(window.tbDragData) };"
                + "const row = arguments[0].assignedSlot.parentNode.parentNode;" + " console.log('row:', row);"
                + "if (!row.hasAttribute('drop-disabled')) { arguments[0].dispatchEvent(event); }", tgt);

        executeScript(createEvent("dragend") //
                + "arguments[0].$.table.dispatchEvent(event)", target.getGrid());
        executeScript("delete window.tbDragData;");
    }
}