Каковы внутренние механизмы механизма Selenium waitFor? - PullRequest
8 голосов
/ 16 ноября 2010

Я пытаюсь настроить поведение команды click Selenium (через user-extentions.js), перехватывая вызовы doClick (locator). По сути, мне нужно откладывать действия кликов всякий раз, когда отображается индикатор занятости нашего приложения.

(Теперь стандартный ответ для такого рода вещей заключается в том, чтобы вставить в сценарий waitFor в этих ситуациях. Действительно, в настоящее время в наших сценариях их содержится миллионы. Я пытаюсь устранить их.)

Обнаружение элемента страницы является тривиальной частью. Самое сложное - заставить сценарий действительно ждать. Моя многообещающая, но неудачная попытка выглядит так:

var nativeClick = Selenium.prototype.doClick;
Selenium.prototype.doClick = function(locator) {
  this.doWaitForCondition("!selenium.browserbot.findElementOrNull('busy-indicator')", 5000);
  return nativeClick.call(this, locator);
}

doWaitForCondition вызывается перед каждым кликом, но не ожидает, когда условие оценивается как ложное. nativeClick всегда вызывается немедленно, поэтому задержка не вводится. Я подозреваю, что функция doWaitForCondition на самом деле не производит никакого ожидания, а скорее устанавливает условия для нее в цикле выполнения команды. И в этом случае команда click уже запущена, и я пытаюсь выполнить команду внутри команды.

Может кто-нибудь пролить свет на то, как работает команда Selenium и waitFor, или предложить предложения о том, как это можно сделать?

Ответы [ 2 ]

5 голосов
/ 15 апреля 2011

Я наконец-то решил это. И с подходом, который намного лучше, чем пытаться перехватить обработку кликов в ее различных формах. Моя уточненная цель: отложить выполнение команды сценария, когда наше приложение «занято».

Как работает обработка команд Selenium:

По завершении каждая команда селена возвращает объект ActionResult, (см. ActionHandler.prototype.execute) . Атрибут terminationCondition для этого объекта - это функция, которая определяет, когда селен может перейти к следующей команде, (TestLoop.prototype.continueTestWhenConditionIsTrue) . По сути, селен многократно выполняет функцию условия, пока не получит значение true. Результат объекта это довольно тривиально:

function ActionResult(terminationCondition) {
  this.terminationCondition = terminationCondition;
}

Настройка:

Я хочу отложить выполнение в любое время myAppIsBusy() вернет true. Конечно, все стандартные задержки также должны оставаться на месте, например, ожидание загрузки страницы и явные условия waitFor в соответствии со сценарием. Решение состоит в том, чтобы переопределить объект результата селена в моем user-extensions.js следующим образом:

function ActionResult(terminationCondition) {
  this.terminationCondition = function() {
    // a null terminationCondition means okay to continue
    return (!terminationCondition || terminationCondition()) && !myAppIsBusy();
  }
}

Самое замечательное то, что это достаточно низкий уровень, чтобы он работал как для IDE, так и для RC.

Обратите внимание, что это не влияет на типы команд Accessor или Assert, которые возвращают различные объекты результата. Но это должно быть хорошо, потому что эти команды не влияют на состояние приложения.

0 голосов
/ 17 ноября 2010

Что ж, взгляд на класс java драйверов com.thoughtworks.selenium.Wait показывает следующее:

public void wait(String message, long timeoutInMilliseconds, long intervalInMilliseconds) {
    long start = System.currentTimeMillis();
    long end = start + timeoutInMilliseconds;
    while (System.currentTimeMillis() < end) {
        if (until()) return;
        try {
            Thread.sleep(intervalInMilliseconds);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    throw new WaitTimedOutException(message);
}

Я не слишком глубоко в селен, но я ожидаю, что каждый метод waitXXX указывает на это.

Итак, Selenium работает с Thread.sleep(). Хотя это может показаться не идеальным решением, оно показывает, по крайней мере, что вы не можете сделать его хуже, используя Thread.sleep () самостоятельно при необходимости. ; -)

...