WebDriver: изменение события не срабатывает

У меня есть приложение, которое использует KnockoutJS, и я пытаюсь написать несколько тестов, которые проверяют форму. Если вы не знаете KnockoutJS, короткая история для него заключается в том, что он предоставляет привязки от моего взгляда к моей модели данных. Это означает, что когда я набираю значение в поле ввода, мой базовый объект автоматически обновляется этим значением поля ввода. Это делается через событие изменения по умолчанию.

Проблема, с которой я сталкиваюсь, заключается в том, что, когда мой тест WebDriver печатает в поле, событие изменения не запускается, поэтому моя базовая модель данных не имеет соответствующих значений. Это приводит к сбою проверки моей формы, когда это не должно быть.

Я сделал все, что мог найти в Интернете, чтобы сделать эту работу. Я:

  1. отправил клавишу табуляции
  2. кликнул в поле формы
  3. отправить код JavaScript для запуска фокусировки и размытия (проверка происходит при размытии)
  4. щелкнул поле формы, прежде чем вводить
  5. набор ждет только в том случае, если это была временная проблема
  6. изменил KnockoutJS для обновления поля ввода в afterkeydown

Ни один из них не работал для меня.

Кроме того, я убедился, что это не проблема всплытия событий, поскольку я явно удалил все остальные события, оставив только событие изменения KnockoutJS.

решение, которое я ищу, - это решение, которое работает для всех драйверов браузера (... по крайней мере, для основных, например IE, FF, Chrome, Safari) и не требует использования jQuery.

Как мне решить проблему?

Вот соответствующий код, который я использую для ввода значений в поле:

// find element
WebElement input = this.element.findElement(By.className("controls"))
                               .findElement(By.tagName("input"));

// to set focus?
input.click();

// erase any existing value (because clear does not send any events
for (int i = 0; i < input.getAttribute("value").length(); i++) {
    input.sendKeys(Keys.BACK_SPACE);
}

// type in value
input.sendKeys(text);

// to fire change & blur? (doesnt fire change)
//input.sendKeys(Keys.TAB);

// to fire change & blur? (doesnt fire change)
driver.findElement(By.tagName("body")).click();

Ответ 1

Итак, я считаю, что обнаружил свою проблему. Я полностью признаю, что это был PEBKAC. Я забыл, что у WebDriver есть проблемы, если окно браузера не активно фокусируется на машине (что для меня все еще странно). Когда я отлаживал проблему, я использовал свой редактор для ввода кода. Запустив код в обычном режиме и не удаляя фокус из браузера, события срабатывают, как ожидается, используя все три решения (вкладка, щелчок и javascript).

У меня есть пример проекта, показывающий все три метода, однако я являюсь основным noob с git и github, и у меня возникают проблемы с доставкой проекта. Как только я это выясню, я поделюсь проектом со всеми вами.

EDIT: появился пример кода на GitHub (https://github.com/loesak/knockout.webdriver.change.event.test). Вы можете запустить проект как webapp на сервере и запустить тест вручную или выполнить тесты через maven (mvn clean install). Я не прилагал много усилий для того, чтобы это работало надежно, поэтому предполагается, что у вас установлен Firefox, и открыт порт 0808 8080.

ИЗМЕНИТЬ: фиксированный номер указанного порта

Ответ 2

Итак, я нашел способ обойти эту проблему на данный момент, но, безусловно, считаю, что это правильное решение. Это нарушает мое правило о том, что я не использую jQuery, но я считаю, что это нормально для меня, поскольку KnockoutJS требует загрузки jQuery. Вероятно, это простой способ JavaScript. Я тестировал это с помощью FireFox, Safari и PhantomJS. Я предполагаю, что он будет работать так же хорошо и в Chrome. Я не предлагаю promises для Internet Explorer.

Я НЕ, чтобы отметить этот ответ как правильный ответ. Правильное решение должно быть через браузеры WebDriver, запускающие правильные события. Только когда я верю, что это невозможно через WebDriver, я буду отмечать это как правильный ответ.

// find element in question
WebElement input = this.element.findElement(By.className("controls"))
                               .findElement(By.tagName("input"));

// click it to fire focus event
input.click();

// erase any existing value
for (int i = 0; i < input.getAttribute("value").length(); i++) {
    input.sendKeys(Keys.BACK_SPACE);
}

// enter in desired text
input.sendKeys(text);

// fire on change event (WebDriver SHOULD DO THIS)
((JavascriptExecutor) driver).executeScript(
        "$(arguments[0]).change(); return true;"
    , input);

// click away to fire blur event
driver.findElement(By.tagName("body")).click();