Drag and drop для Angular sortable items

angularjs
javascript
webdriver
firefox
python
Теги: #<Tag:0x00007fedb8be43f0> #<Tag:0x00007fedb8be42b0> #<Tag:0x00007fedb8be4170> #<Tag:0x00007fedb8be4030> #<Tag:0x00007fedb8bebf10>

(zub_test) #1

Привет

Помогите, пожалуйста, сделать drag and drop.
Вот приложение: https://a5hik.github.io/ng-sortable/#/kanban (этот сайт использую как пример).
Задача: в колонке Done нужно переместить карточку ‘Test user module’ самый низ (т/е/ сделать её последней в колонке Done).

Firefox 45.4.0 (c v.47 то же самое)
Selenium 2.53.6
Python 2.7.10

Вот код теста:

driver = self.driver  # type: WebDriver
driver.get("https://a5hik.github.io/ng-sortable/#/kanban")
time.sleep(5)
source = driver.find_element(By.CSS_SELECTOR, "#column3 li:nth-child(1) div.col-sm-10")
target = driver.find_element(By.CSS_SELECTOR, "#column3 li:nth-child(3) div.col-sm-10")

ActionChains(driver).click_and_hold(source).move_to_element(target).perform()
time.sleep(15)

Вижу, что элемент хватается, но когда происходит moveTo, указатель мышки передвигается без захваченного элемента. Если разбить actions на два подхода: clickAndHold и moveTo и между ними поставить паузу и в этот момент просто переместить мышку вручную (захваченный элемент сдвинется с места), то всё срабатывает.

Попробовал на джаве - результат тот же. Попробовал с помощью AWT robot - тоже неудачно.
Вариант с инсертом джаваскрпта тоже не сработал: https://gist.github.com/douglaslise/884692bb54cdf8e76702c01bc18defbd


(Сергей Кузьмин) #2

A Protractor не пробовали: ?
https://github.com/sergueik/protractor-net
https://github.com/sergueik/jProtractor
https://github.com/sergueik/jpagefactory

там (по крайней мере для java) уже есть [пример]
(https://github.com/sergueik/jProtractor/blob/master/src/test/java/com/jprotractor/integration/NgLocalFileTest.java#L1334)

public void testDragAndDropSimulate() ...

я ж его и написал … то же самое что в Selenium но
новые стратегии поиска элементов - типа

column = ngDriver
                .findElements(NgBy.repeater("column in kanbanBoard.columns")).get(0);


Enumeration<WebElement> cards = Collections.enumeration(column.findElements(NgBy.model("column.cards")));

и т.д.

            actions.moveToElement(card).build().perform();
            actions.clickAndHold(card).moveToElement(basket).release().build()
                    .perform();


test-case для вашей страницы полностью попробую позже – небольшие проблемы со временем …


(Сергей Кузьмин) #3

попробовал - работает…


        WebElement column3 = ng_board.findElement(By.id("column3"));
        NgWebElement ng_column3 = new NgWebElement(ngDriver, column3);
        Enumeration<WebElement> cards = Collections
                .enumeration(ng_column3.findElement(NgBy.model("column.cards")).findElements(NgBy
                        .repeater("card in column.cards")));

        WebElement source_card = null;
        WebElement target_card = null;

        while (cards.hasMoreElements()) {
            WebElement card = cards.nextElement();
            if (card.getText().isEmpty()) {
                break;
            }
            if (card.getText().equalsIgnoreCase("Test user module")) {
                System.err.println("source card: \"" + card.getText() + "\" found");
                source_card = card;
            }
            if (card.getText().equalsIgnoreCase("CI for user module")) {
                System.err.println("target card: \"" + card.getText() + "\" found");
                target_card = card;
            }
        }

        highlight(source_card);
        Point source_card_location = source_card.getLocation();
        highlight(target_card);
        Point target_card_location = target_card.getLocation();
        actions.moveToElement(source_card).build().perform();
        //  does not appear to work
        actions.dragAndDropBy(source_card, 0, target_card_location.y - source_card_location.y)
                .build().perform();
        Thread.sleep(1000);
    // works
        actions.clickAndHold(source_card).moveToElement(target_card).release().build()
                .perform();
        ngDriver.waitForAngular();
        Thread.sleep(1000);

код естественно можно улучшить, но проблема решена


(zub_test) #4

Спасибо огромное! Всё заработало. Оказывается вся магия заключается в этих строчках:

actions.moveToElement(source_card).build().perform();
        //  does not appear to work
        actions.dragAndDropBy(source_card, 0, target_card_location.y - source_card_location.y)
                .build().perform();
        Thread.sleep(1000);
    // works
        actions.clickAndHold(source_card).moveToElement(target_card).release().build()
                .perform();

Т.е. грубо говоря двойной драг-н-дроп - это решение проблемы.

Проверил, что происходит когда делаем перетаскивание вручную: изначально список карточек в колонке представлен в виде набора li-шек в ul. Когда начинаем перетаскивание, перетаскиваемая li скрывается, добавляется новая li как плейсхолдер + (тут самое главное): Формируется новый ul c одной li (та самая, которую мы перетаскиваем) и в новом ul уже происходит изменение позиции. Поэтому, как я понял, и нужно два драг-н-дропа. Первый который произведёт построение нового ul, и второй который будет делать собственно перетаскивание. Т/е/ всё легко перенеслось на на чистый selenium+python

Спасибо, ещё раз!

P.S. Глянул Ваши проекты на гитхабе - очень здорово!


(Сергей Кузьмин) #5

рад за вас! если нравится проект - star it!

https://github.com/sergueik/selenium_java/blob/master/protractor/jProtractor.pdf