我正在测试ExtJS web应用程序的UI,我是一个初学者。我试图通过使用CasperJS/PhantomJS工具测试ExtJS小部件。此外,我使用revive生成所需的CasperJs脚本,并对其进行必要的更改。
由于ExtJs动态地为它创建的DOM元素生成唯一的id,我想知道如何在CasperJs脚本中为测试提供这些id。
例如,下面的Casper脚本是由resurrection生成的:
casper.waitForSelector("#ext-gen1142 .x-tree-icon.x-tree-icon-parent",
function success() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
this.click("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
},
function fail() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
});
casper.waitForSelector("#gridview-1038",
function success() {
test.assertExists("#gridview-1038");
this.click("#gridview-1038");
},
function fail() {
test.assertExists("#gridview-1038");
});
这里#ext-gen1142和#gridview-1038是动态创建的id。在测试中应该如何提供数据?是否有任何存根或模拟工具在代码中与ExtJs一起工作,以便在测试期间运行时提供这些id ?
我遇到了SinonJS。可以使用它吗?或者我需要使用这个答案中提到的CSS或XPath定位器吗?使用CSS或Xpath定位器有多可靠?
提前感谢!
回答这个问题并不容易,但这里有一些想法…
-
不要依赖生成的id。从来没有。如果你运气好,它们会在你不喜欢的时候改变。
-
你最好的朋友可能是你附加到组件上的伪CSS类。您也可以使用id,但这只有在页面中只出现一次的元素时才合理。如果是这样的话,它们是开始选择/查询的非常好的锚。
使用ExtJS可以使用 XPath,但是必须仔细选择元素。ExtJS在生成小的东西时非常冗长,因此您的路径可能相当复杂。当Sencha放弃对有问题的浏览器(IE <8)也许他们改变了模板,你的XPath找不到任何东西。
SinonJS很棒。但是它对DOM问题没有多大帮助。但是你可以在测试中使用它。我想它将在测试控制器或非平凡模型的部分中获得最大回报。
根据实际UI组件和屏幕部分对测试组件建模。不要只是记录一个脚本。测试代码应该像产品代码一样设计。如果您创建了测试代码和逻辑的可重用组件,您就不必担心更改。在最好的情况下,一个组件中的更改只会触及该特定组件的测试代码。
我知道你有ExtJS。但是花点时间看看AngularJS,看看测试JavaScript web应用程序的所有部分是多么容易。我并不是说你应该切换到AngularJS,但是你可以从中学到很多。看看Deft JS,因为它有很多增强ExtJS应用程序可测试性的概念。
我使用Siesta进行ExtJs测试。它对所有JavaScript(基于jQuery和其他)都非常有效,但它是专门为ExtJS/Sencha Touch设计的。
它具有将CSSquery和ComponentQuery结合起来选择元素的功能,我认为这将为您解决许多问题。
在付费版本中,甚至有一个测试记录器来记录场景并将它们用于您的测试。
这是一个演示
下面是一些示例代码:
StartTest(function(t) {
t.chain(
{ waitFor : 'CQ', args : 'gridpanel' },
function(next, grids) {
var userGrid = grids[0];
t.willFireNTimes(userGrid.store, 'write', 1);
next();
},
{ waitFor : 'rowsVisible', args : 'gridpanel' },
{ action : 'doubleclick', target : 'gridpanel => .x-grid-cell' },
// waiting for popup window to appear
{ waitFor : 'CQ', args : 'useredit' },
// When using target, >> specifies a Component Query
{ action : 'click', target : '>>field[name=firstname]'},
function(next) {
// Manually clear text field
t.cq1('field[name=firstname]').setValue();
next();
},
{ action : 'type', target : '>>field[name=firstname]', text : 'foo' },
{ action : 'click', target : '>>useredit button[text=Save]'},
function(next) {
t.matchGridCellContent(t.cq1('gridpanel'), 0, 0, 'foo Spencer', 'Updated name found in grid');
}
);
})