任何build议在浏览器中testingextjs代码,最好用selenium?

我们一直在使用selenium大获成功来处理高级别的网站testing(除了在模块级别的广泛的python doctests)。 但是现在我们在很多页面上使用extjs,并且很难将Seleniumtesting用于像网格这样的复杂组件。

有没有人有成功编写基于extjs的网页自动化testing? 许多谷歌search发现有类似问题的人,但很less有答案。 谢谢!

使用SeleniumtestingExtJS的最大障碍是ExtJS不提供标准的HTML元素,而Selenium IDE会天真地(正确地)生成命令,这些命令针对的是仅仅作为装饰的元素 – 多余的元素可以帮助ExtJS处理整个桌面 – 外观和感觉。 这里有一些技巧和窍门,我在编写自动化的Seleniumtesting中针对ExtJS应用程序进行了收集。

一般提示

定位元素

通过在Firefox上使用Selenium IDElogging用户操作来生成Seleniumtesting用例时,Selenium会将logging的操作基于HTML元素的ID。 然而,对于大多数可点击的元素,ExtJS使用生成的id,如“ext-gen-345”,即使没有进行任何代码更改,在随后访问同一页面时也可能会发生变化。 在logging用户对testing的操作之后,需要手动完成所有这些取决于生成的ID的操作并replace它们。 有两种types的replace可以做:

用CSS或XPath定位器replaceId定位器

CSS定位符以“css =”开头,XPath定位符以“//”开头(“xpath =”前缀是可选的)。 CSS定位器不那么冗长,更易于阅读,应该优于XPath定位器。 但是,在某些情况下,需要使用XPath定位器,因为CSS定位器根本无法将其裁剪。

执行JavaScript

由于ExtJS进行的复杂渲染,某些元素不仅仅需要简单的鼠标/键盘交互。 例如,一个Ext.form.CombBox实际上不是一个<select>元素,而是一个带有分离下拉列表的文本input,它位于文档树的底部。 为了正确地模拟ComboBoxselect,可以首先模拟点击下拉箭头,然后单击出现的列表。 但是,通过CSS或XPath定位器来定位这些元素可能会很麻烦。 另一种方法是定位ComoBox组件本身并调用其上的方法来模拟select:

 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命令以更简洁的forms执行上述操作:

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

应对AJAX和慢速渲染

当用户操作导致页面转换或重新加载时,Selenium对所有等待页面加载的命令都有“* AndWait”特性。 但是,由于AJAX提取不涉及实际的页面加载,因此这些命令不能用于同步。 解决scheme是利用视觉线索,例如有无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') 

依赖任意暂停不是一个好主意,因为在不同的浏览器或不同的机器上运行testing所产生的时间差异会使testing案例变得不稳定。

不可点击的项目

一些元素不能由click命令触发。 这是因为事件监听器实际上是在容器上,注意其子元素上的鼠标事件,最终会冒泡到父代。 选项卡控件就是一个例子。 要点击一个标签,你必须在tab标签处模拟一个mouseDown事件:

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

字段validation

具有关联的正则expression式或vtypes进行validation的表单字段(Ext.form。*组件)将在用户input文本后立即触发validation(默认设置为250毫秒的validationDelay延迟属性),或者立即在字段失去焦点 – 或模糊(请参阅validateOnDelay属性)。 为了在发出typesSelenium命令后在字段中input一些文本来触发字段validation,您必须执行以下任一操作:

  • 触发延迟validation

    当字段接收到keyup事件时,ExtJS会触发validation延迟计时器。 要触发这个定时器,只需发出一个虚拟的keyup事件(不pipe你用哪个key作为ExtJS忽略它),然后是一个比validationDelay更长的短暂停顿:

     Command: keyUp Target: someTextArea Value: x Command: pause Target: 500 
  • 触发立即validation

    您可以在该字段中注入模糊事件以触发立即validation:

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

检查validation结果

validation之后,您可以检查是否存在错误字段:

 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

    命令:点击目标:css =button:包含('保存')

    通过其标题selectbutton

  • 选项2

    命令:点击目标:css =#save-optionsbutton

    通过其IDselectbutton

从Ext.form.ComboBox中select一个值

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

首先设置该值,然后在有观察者的情况下显式激发select事件。

这个博客帮了我很多。 他在这个话题上写了不less东西,看起来还是很活跃的。 这家伙似乎也很欣赏好的devise。

他基本上谈论使用发送JavaScript来做查询,并使用Ext.ComponentQuery.query方法来检索的东西,就像你在你的分机应用程序在内部做的一样。 这样,你可以使用xtypes和itemIds,而不必担心试图parsing任何疯狂的自动生成的东西。

我发现这篇文章特别有帮助。

可能很快就会在这里发布一些更详细的内容 – 仍然试图让我的头正确地做到这一点

我一直在用Selen来testing我的ExtJs Web应用程序。 最大的问题之一是在网格中select一个项目,以便做一些事情。

为此,我编写了一个辅助方法(在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)"; } 

当我需要select一行时,我只需要打电话:

 selenium.runScript( SeleniumExtJsUtils.selectGridRow("<myGridId>", 5) ); 

为了这个工作,我需要在网格上设置我的ID,而不是让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')]" 

你可以提供更多的洞察你使用extjstesting的问题types吗?

我觉得有用的一个Selenium扩展是waitForCondition 。 如果您的问题似乎与Ajax事件有关,则可以使用waitForCondition等待事件发生。

Ext JS网页可能很难testing,因为它们最终会像Ext JS网格一样产生复杂的HTML。

HTML5机器人通过使用一系列最佳实践来处理这个问题,如何根据不dynamic的属性和条件来可靠地查找和交互组件。 然后为所有需要与之交互的HTML,Ext JS和Sencha Touch组件提供快捷方式。 它有两种口味:

  1. Java – 熟悉的Selenium和基于JUnit的API,内置了对所有现代浏览器的Web驱动支持。
  2. Gwen – 一种人性化的语言,可以快速轻松地创build和维护浏览器testing,这些testing随附自己的集成开发环境。 所有这些都基于Java API。

例如,如果您想要查找包含文本“Foo”的Ext JS网格行,则可以在Java中执行以下操作:

 findExtJsGridRow("Foo"); 

…你可以在格温做以下事情:

 extjsgridrow by text "Foo" 

Java和Gwen有很多关于如何使用Ext JS特定组件的文档。 该文档还详细介绍了所有这些Ext JS组件的HTML结果,您也可能会发现它们很有用。

在页面上通过网格ID获取网格的有用技巧:我认为你可以从这个API扩展更多有用的function。

  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的testing框架,并遇到了extjs的问题(因为它是客户端渲染)。 一旦DOM准备就绪,我发现find一个元素是很有用的。

 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实现不同的UI实现方面有点复杂。

您可以使用Firebug和Firexpath作为Firefox扩展来testing某个元素的xpath,并简单地将完整的xpath作为parameter passing给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数据属性更轻松地进行testing

从Sencha文档 :

当没有对象引用可用时,可以使用itemId作为获取对组件的引用的替代方法。 而不是与Ext.getCmp一起使用一个id,使用itemId与Ext.container.Container.getComponent将检索itemId的或id的。 由于itemId是容器内部的MixedCollection的索引,因此itemId在本地被限定在容器中 – 避免了与需要唯一ID的Ext.ComponentManager的潜在冲突。

重写Ext.AbstractComponentonBoxReady方法,我设置了一个自定义数据属性(其名称来自每个组件的自定义testIdAttr属性)到组件的itemId值(如果存在)。 将Testing.overrides.AbstractComponent类添加到您的application.js文件的requires数组中。

 /** * 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); } }); 

该方法为开发人员提供了在代码中重用描述性标识符的方法,并且每次渲染页面时都可以使用这些标识符。 不再需要通过非描述性的dynamic生成的ID进行search。

当我使用WebDrivertestingExtJS应用程序时,我使用了下一个方法:通过标签的文本查找字段,并从标签获得@for属性。 例如,我们有一个标签

 <label id="dynamic_id_label" class="TextboxLabel" for="textField_which_I_am_lloking_for"> Name Of Needed Label <label/> 

我们需要指出WebDriver的一些input: //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)]

所以,它会从@for属性中selectid并进一步使用它。 这可能是最简单的情况,但它给你的方式来定位元素。 当你没有标签的时候要困难得多,但是你需要find一些元素并且写下你的xpath来寻找兄弟,下降/提升元素。