Любые предложения по тестированию кода extjs в браузере, желательно с seleniumом?

Мы использовали selenium с большим успехом для обработки высокоуровневого веб-сайта (в дополнение к обширным doctrineм python на уровне модуля). Однако теперь мы используем extjs для большого количества страниц, и его сложно включить тесты Selenium для сложных компонентов, таких как сетки.

Кто-нибудь успел написать автоматические тесты для веб-страниц на основе extjs? Многие поисковики ищут людей с похожими проблемами, но мало ответов. Благодаря!

Самое большое препятствие при тестировании ExtJS с Selenium заключается в том, что ExtJS не отображает стандартные HTML-элементы, а Selenium IDE наивно (и по праву) генерирует команды, ориентированные на элементы, которые просто действуют как элементы декора – лишние элементы, которые помогают ExtJS со всем настольным компьютером, смотреть и чувствовать. Вот несколько советов и трюков, которые я собрал при написании автоматизированного теста Selenium против приложения ExtJS.

Общие советы

Поиск элементов

При генерации тестовых примеров Selenium путем записи действий пользователя с Selenium IDE в Firefox Selenium будет основывать записанные действия на идентификаторах элементов HTML. Однако для большинства интерактивных элементов ExtJS использует генерируемые идентификаторы типа ext-gen-345, которые могут измениться при последующем посещении на той же странице, даже если никаких изменений кода не было сделано. После записи действий пользователя для теста необходимо выполнить ручное усилие, чтобы пройти все такие действия, которые зависят от сгенерированных идентификаторов и их замены. Существует два типа замен:

Замена локатора идентификаторов с помощью указателя CSS или XPath

Локаторы CSS начинаются с «css =», а локаторы XPath начинаются с «//» (префикс «xpath =» является необязательным). Локаторы CSS менее подробные и их легче читать, и они должны быть предпочтительнее локаторов XPath. Однако могут быть случаи, когда нужно использовать локаторы XPath, поскольку локатор CSS просто не может его обрезать.

Выполнение JavaScript

Некоторые элементы требуют больше, чем простое взаимодействие с мышью и клавиатурой из-за сложного рендеринга, выполняемого ExtJS. Например, Ext.form.CombBox на самом деле не является элементом а текстовым вводом с отдельным раскрывающимся списком, который находится где-то внизу дерева документов. Чтобы правильно имитировать выбор ComboBox, сначала можно имитировать щелчок по стрелке раскрывающегося списка, а затем щелкнуть по появившемуся списку. Однако размещение этих элементов с помощью CSS или локаторов XPath может быть громоздким. Альтернативой является найти сам компонент ComoBox и вызвать методы для имитации выбора:

 var combo = Ext.getCmp('genderComboBox'); // returns the ComboBox components combo.setValue('female'); // set the value combo.fireEvent('select'); // because setValue() doesn't trigger the event 

В Selenium команда runScript может использоваться для выполнения вышеуказанной операции в более сжатой форме:

 with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); } 

Борьба с AJAX и медленным рендерингом

Selenium имеет «* AndWait» ароматы для всех команд для ожидания загрузки страницы, когда действие пользователя приводит к переходу или перезагрузке страницы. Однако, поскольку выборки AJAX не связаны с фактическими загрузками страниц, эти команды не могут использоваться для синхронизации. Решение состоит в том, чтобы использовать визуальные подсказки, такие как наличие / отсутствие индикатора прогресса AJAX или появление строк в сетке, дополнительные компоненты, ссылки и т. Д. Например:

 Command: waitForElementNotPresent Target: css=div:contains('Loading...') 

Иногда элемент появляется только через определенное время, в зависимости от того, насколько быстро ExtJS отображает компоненты после того, как действие пользователя приводит к изменению вида. Вместо использования суровых задержек с командой pause идеальным методом является подождать, пока элемент интереса не окажется в пределах нашего понимания. Например, чтобы щелкнуть по элементу после ожидания его появления:

 Command: waitForElementPresent Target: css=span:contains('Do the funky thing') Command: click Target: css=span:contains('Do the funky thing') 

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

Предметы без клика

Команда click не может быть вызвана некоторыми элементами. Это потому, что прослушиватель событий на самом деле находится в контейнере, наблюдая за событиями мыши над его дочерними элементами, которые в конечном итоге выходят за пределы родителя. Элемент управления вкладкой – один из примеров. Чтобы щелкнуть вкладку a, вы должны имитировать событие mouseDown на ярлыке вкладки:

 Command: mouseDownAt Target: css=.x-tab-strip-text:contains('Options') Value: 0,0 

Проверка поля

Поля формы (компоненты Ext.form. *), Которые связаны с регулярными выражениями или vtypes для проверки, инициируют проверку с определенной задержкой (см. Свойство validationDelay которое установлено по умолчанию на 250 мс), после того, как пользователь вводит текст или сразу, когда поле теряет фокус – или размывает (см. свойство validateOnDelay ). Чтобы инициировать проверку поля после выдачи команды типа Selenium для ввода некоторого текста внутри поля, вам необходимо выполнить одно из следующих действий:

  • Завершение с задержкой проверки

    ExtJS отключает таймер задержки проверки, когда поле получает события блокировки. Чтобы запустить этот таймер, просто введите фиктивное событие keyup (неважно, какой ключ вы используете, поскольку ExtJS игнорирует его), за которым следует короткая пауза, длина которой больше, чем validationDelay:

     Command: keyUp Target: someTextArea Value: x Command: pause Target: 500 
  • Запуск немедленной проверки

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

     Command: runScript Target: someComponent.nameTextField.fireEvent("blur") 

Проверка результатов проверки

После проверки вы можете проверить наличие или отсутствие поля ошибки:

 Command: verifyElementNotPresent Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))] Command: verifyElementPresent Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))] 

Обратите внимание, что проверка «display: none» необходима, поскольку, когда отображается поле ошибки, а затем оно должно быть скрыто, ExtJS просто спрячет поле ошибки, а не полностью удалит его из дерева DOM.

Специальные советы для элемента

Нажатие кнопки Ext.form.Button

  • Опция 1

    Команда: нажмите objective: css = кнопка: содержит («Сохранить»)

    Выбирает кнопку по ее заголовку

  • Вариант 2

    Команда: нажмите Target: css = # save-options button

    Выбирает кнопку по ее идентификатору

Выбор значения из Ext.form.ComboBox

 Command: runScript Target: with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); } 

Сначала задает значение и затем явно запускает событие select в случае наличия наблюдателей.

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

Он в основном говорит об использовании отправки javascript для выполнения запросов и использовании метода Ext.ComponentQuery.query для извлечения файлов так же, как и в своем внешнем приложении. Таким образом, вы можете использовать xtypes и itemIds и не должны беспокоиться о том, чтобы попытаться разобрать любой из безумных автоматически генерируемых вещей.

Я нашел эту статью особенно полезной.

Могу позже опубликовать что-то более подробное здесь – все еще пытаюсь понять, как это сделать правильно

Я тестировал веб-приложение ExtJs с seleniumом. Одной из самых больших проблем был выбор элемента в сетке, чтобы что-то с ним сделать.

Для этого я написал вспомогательный метод (в classе SeleniumExtJsUtils, который представляет собой набор полезных методов для упрощения взаимодействия с ExtJs):

 /** * Javascript needed to execute in order to select row in the grid * * @param gridId Grid id * @param rowIndex Index of the row to select * @return Javascript to select row */ public static String selectGridRow(String gridId, int rowIndex) { return "Ext.getCmp('" + gridId + "').getSelectionModel().selectRow(" + rowIndex + ", true)"; } 

и когда мне нужно было выбрать строку, я бы просто позвонил:

 selenium.runScript( SeleniumExtJsUtils.selectGridRow("", 5) ); 

Для этого мне нужно установить свой идентификатор в сетке и не позволять ExtJs генерировать его собственный.

Чтобы обнаружить, что элемент виден, вы используете предложение: not(contains(@style, "display: none")

Лучше использовать это:

 visible_clause = "not(ancestor::*[contains(@style,'display: none')" + " or contains(@style, 'visibility: hidden') " + " or contains(@class,'x-hide-display')])" hidden_clause = "parent::*[contains(@style,'display: none')" + " or contains(@style, 'visibility: hidden')" + " or contains(@class,'x-hide-display')]" 

Можете ли вы более подробно рассказать о проблемах, которые возникают у вас при тестировании extjs?

Одно расширение Selenium, которое я нахожу полезным, – это waitForCondition . Если проблема связана с событиями Ajax, вы можете использовать waitForCondition для ожидания событий.

Внешние веб-страницы JS могут быть сложными для тестирования, из-за сложного HTML они в конечном итоге генерируются, как с сетями Ext JS.

HTML5 Robot занимается этим, используя ряд лучших практик для надежного поиска и взаимодействия с компонентами на основе атрибутов и условий, которые не являются динамическими. Затем он предоставляет ярлыки для этого со всеми компонентами HTML, Ext JS и Sencha Touch, с которыми вам нужно будет взаимодействовать. Он поставляется в двух вариантах:

  1. Java – знакомый интерфейс Selenium и JUnit, встроенный в поддержку веб-драйверов для всех современных браузеров.
  2. Gwen – язык человеческого стиля для быстрого и легкого создания и поддержки тестов браузера, который поставляется с собственной интегрированной средой разработки. Все они основаны на Java API.

Например, если вы хотите найти строку сетки Ext JS, содержащую текст «Foo», вы можете сделать следующее в Java:

 findExtJsGridRow("Foo"); 

… и вы можете сделать следующее в Гвен:

 extjsgridrow by text "Foo" 

Существует много документации для Java и Gwen для работы с компонентами Ext JS. В документации также описывается итоговый HTML для всех этих компонентов Ext JS, которые также могут оказаться полезными.

Полезные советы для получения сетки через идентификатор сетки на странице: Я думаю, вы можете расширить более полезную функцию из этого API.

  sub get_grid_row { my ($browser, $grid, $row) = @_; my $script = "var doc = this.browserbot.getCurrentWindow().document;\n" . "var grid = doc.getElementById('$grid');\n" . "var table = grid.getElementsByTagName('table');\n" . "var result = '';\n" . "var row = 0;\n" . "for (var i = 0; i < table.length; i++) {\n" . " if (table[i].className == 'x-grid3-row-table') {\n". " row++;\n" . " if (row == $row) {\n" . " var cols_len = table[i].rows[0].cells.length;\n" . " for (var j = 0; j < cols_len; j++) {\n" . " var cell = table[i].rows[0].cells[j];\n" . " if (result.length == 0) {\n" . " result = getText(cell);\n" . " } else { \n" . " result += '|' + getText(cell);\n" . " }\n" . " }\n" . " }\n" . " }\n" . "}\n" . "result;\n"; my $result = $browser->get_eval($script); my @res = split('\|', $result); return @res; } 

Мы разрабатываем платформу тестирования, которая использует selenium и сталкивается с проблемами с extjs (поскольку это рендеринг на стороне клиента). Мне удобнее искать элемент, когда DOM готов.

 public static boolean waitUntilDOMIsReady(WebDriver driver) { def maxSeconds = DEFAULT_WAIT_SECONDS * 10 for (count in 1..maxSeconds) { Thread.sleep(100) def ready = isDOMReady(driver); if (ready) { break; } } } public static boolean isDOMReady(WebDriver driver){ return driver.executeScript("return document.readyState"); } 

Для сложного пользовательского интерфейса, который не является формальным HTML, xPath – это всегда то, на что вы можете рассчитывать, но немного сложное, когда дело касается реализации разных пользовательских интерфейсов с использованием ExtJs.

Вы можете использовать Firebug и Firexpath в качестве расширений firefox для проверки xpath определенного элемента и простого передать полный xpath как параметр в selenium.

Например, в java-коде:

 String fullXpath = "xpath=//div[@id='mainDiv']//div[contains(@class,'x-grid-row')]//table/tbody/tr[1]/td[1]//button" selenium.click(fullXpath); 

Более простое тестирование с помощью пользовательских атрибутов данных HTML

Из документации Sencha :

ItemId может использоваться как альтернативный способ получения ссылки на компонент, когда ссылка на объект недоступна. Вместо использования id с Ext.getCmp используйте itemId с Ext.container.Container.getComponent, который будет извлекать элементы itemId или id. Поскольку itemId является индексом внутреннего MixedCollection контейнера, itemId локально привязывается к контейнеру – избегая потенциальных конфликтов с Ext.ComponentManager, для которого требуется уникальный идентификатор.

Переопределяя метод Ext.AbstractComponent onBoxReady , я устанавливаю атрибут пользовательских данных (чье имя происходит от моего собственного свойства testIdAttr каждого компонента) до значения itemId компонента, если он существует. Добавьте class Testing.overrides.AbstractComponent в требуемый массив application.js .

 /** * Overrides the Ext.AbstracComponent's onBoxReady * method to add custom data attributes to the * component's dom structure. * * @author Brian Wendt */ Ext.define('Testing.overrides.AbstractComponent', { override: 'Ext.AbstractComponent', onBoxReady: function () { var me = this, el = me.getEl(); if (el && el.dom && me.itemId) { el.dom.setAttribute(me.testIdAttr || 'data-selenium-id', me.itemId); } me.callOverridden(arguments); } }); 

Этот метод предоставляет разработчикам возможность повторно использовать описательный идентификатор в своем коде и предоставлять эти идентификаторы каждый раз, когда страница отображается. Больше не искать через не описательные, динамически генерируемые идентификаторы.

Когда я тестировал приложение ExtJS с помощью WebDriver, я использовал следующий подход: я искал поле по тексту ярлыка и получил атрибут @for от метки. Например, у нас есть ярлык

  

И нам нужно указать WebDriver на ввод: //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)] .

Таким образом, он будет выбирать идентификатор из атрибута @for и использовать его далее. Это, вероятно, самый простой случай, но он дает вам возможность найти элемент. Это намного сложнее, если у вас нет ярлыка, но тогда вам нужно найти какой-то элемент и написать xpath, чтобы найти братьев и сестер, спуститься / взобраться.

  • Ошибка java.lang.RuntimeException: Stub! в Android с тестированием Fitnesse
  • Как построить банку, используя maven, игнорируя результаты теста?
  • Selenium: Можно ли установить любое значение атрибута WebElement в Selenium?
  • Переключить вкладки с помощью Selenium WebDriver с Java
  • Почему я должен практиковать Test Driven Development и как мне начать?
  • Точное измерение времени для тестирования производительности
  • Как настроить модульное тестирование для Visual Studio C ++
  • Как проверить метод весеннего controllerа с помощью MockMvc?
  • Автоматизированные тесты для Java Swing GUI
  • Как настроить JPA для тестирования в Maven
  • Запуск приложения до и после Suite в jUnit 4.x
  • Давайте будем гением компьютера.