如何使用量角器返回此复选框元素?
Posted
技术标签:
【中文标题】如何使用量角器返回此复选框元素?【英文标题】:How can I return this checkbox element with Protractor? 【发布时间】:2016-04-26 15:27:32 【问题描述】:我正在编写一个 Typescript/Protractor 测试,它需要评估和选择网格上的复选框元素。这些复选框缺少 ID。由于我可以处理与这些复选框位于同一行的输入元素,因此我试图通过元素查找器(by.id、by.xpath 和 by.css)的组合来获取它们。但我的尝试失败了。
我想写的是一个小函数,它将根据行上的一个遥远的“兄弟”元素和行上的复选框索引从行中返回目标复选框元素。我已经尝试了几件事,我认为最有希望的尝试都在这里发布。
这是我要定位的网格中的一段标记。为清楚起见,省略了几列信息。这就是我正在与之抗衡的。更改标记不在我的权力范围内,我只是被要求编写量角器测试。
<div ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows track by $index" class="ui-grid-row ng-scope" ng-style="Viewport.rowStyle(rowRenderIndex)">
<div ui-grid-row="row" row-render-index="rowRenderIndex" class="ng-isolate-scope">
<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.uid" class="ui-grid-cell ng-scope ui-grid-coluiGrid-09T" ng-class=" 'ui-grid-row-header-cell': col.isRowHeader " ui-grid-cell="">
<div ng-click="grid.appScope.rowColumnSelect(row, 'rating')" ng-class="'px-grid-row-selected': grid.appScope.highlightCell(row, 'rating'), 'px-can-edit': grid.appScope.clickableCell(row.entity, 'rating'), 'px-grid-total-row': row.entity.isTotal, 'px-grid-notable-row': row.entity.isNotable" class="ng-scope">
<div class="ui-grid-cell-contents ng-hide" ng-hide="grid.appScope.showCell(row, 'rating')">
</div>
<div ng-show="grid.appScope.showCell(row, 'rating')" name="loanLossAssumption3" class="ui-grid-cell-contents">
<div ng-if="grid.appScope.haveData(row)" class="text-right ng-scope">
<div error-display-strategy="grid" px-input-field="" id="loanLossAssumptionrating3" name="loanLossAssumptionrating3" ng-if="grid.appScope.inEditMode(row, 'rating')" input-type="number" px-input-required="true" px-round-value="0" ng-model="row.entity.rating" class="ng-pristine ng-untouched ng-valid ng-scope ng-isolate-scope">
<div ng-class="'row': !vm.isGridErrorDisplay && !vm.autoWidth">
<div>
<div tooltip="" tooltip-placement="bottom" tooltip-append-to-body="true" tooltip-trigger="open" class="ng-scope">
<div px-validation="loanLossAssumptionrating3InputField" ng-class="'col-xs-12': !vm.isGridErrorDisplay && !vm.autoWidth" min="" max="" input-type="number" maxlength="" minlength="" error-display-strategy="grid" px-tooltip="" class="ng-isolate-scope">
<div class="row">
<div ng-class="vm.inputFieldClass()" class="col-xs-12">
<div class="input-group px-input-group-overrides px-no-grid-padding" ng-hide="vm.pxInputDisabled">
<span id="loanLossAssumptionrating3Prefix" name="loanLossAssumptionrating3Prefix" class="input-group-addon input-left-addon ng-binding ng-hide" ng-show="vm.prefix" ng-class="'px-auto-width': vm.autoWidth">
</span>
<div class="inner-addon">
<input id="loanLossAssumptionrating3InputField" name="loanLossAssumptionrating3InputField" class="form-control ng-pristine ng-untouched ng-valid ng-valid-px-email ng-valid-required ng-valid-unique" ng-class="'px-input-with-tooltip': !!vm.pxTooltip, 'px-auto-width': vm.autoWidth" ng-required="vm.pxInputRequired" px-round-value="0" px-edit-rate="false" type="text" ng-model="vm.ngModel" px-email-validator="" ng-disabled="vm.pxControlDisabled" placeholder="" ng-change="vm.onChange()" ng-focus="vm.showTooltip(true)" ng-blur="vm.showTooltip(false)" px-unique-field="" autocomplete="off" required="required">
</div>
<span class="fa fa-exclamation-circle inline-error form-control-feedback" ng-style="left:vm.feedbackIconLeft()" style="left: 0px;">
</span>
<span class="input-group-addon input-empty-addon" ng-hide="vm.postfix" ng-class="'px-auto-width': vm.autoWidth">
</span>
</div>
</div>
<span ng-transclude="" class="px-vertical-middle">
</span>
</div>
</div>
</div>
</div>
<div px-tooltip-view="" px-tooltip="vm.pxTooltip" ng-click="vm.applyAdjustment()" class="ng-isolate-scope">
</div>
</div>
</div>
<span ng-hide="grid.appScope.inEditMode(row, 'rating')" ng-class="'px-font-highlighted': grid.appScope.showHighlighted(row, 'rating'), 'px-font-enabled': grid.appScope.showEnabled(row, 'rating'), 'px-font-disabled': grid.appScope.showDisabled(row, 'rating'), 'px-cannot-edit': !grid.appScope.clickableCell(row.entity, 'rating')" class="ng-binding px-font-enabled px-cannot-edit ng-hide">3</span>
</div>
</div>
</div>
</div>
<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.uid"
class="ui-grid-cell ng-scope ui-grid-coluiGrid-09Y" ng-class=" 'ui-grid-row-header-cell': col.isRowHeader " ui-grid-cell="">
<div ng-click="grid.appScope.rowColumnSelect(row, 'isDefault')"
ng-class="'px-grid-row-selected': grid.appScope.highlightCell(row, 'isDefault'), 'px-can-edit': grid.appScope.clickableCell(row.entity, 'isDefault'), 'px-grid-total-row': row.entity.isTotal, 'px-grid-notable-row': row.entity.isNotable"
class="ng-scope">
<div class="ui-grid-cell-contents ng-hide" ng-hide="grid.appScope.showCell(row, 'isDefault')">
</div>
<div ng-show="grid.appScope.showCell(row, 'isDefault')" name="loanLossAssumptionfalse" class="ui-grid-cell-contents"> <!-- Changes to loanLossAssumptiontrue-->
<div ng-if="grid.appScope.haveData(row)" class="text-center ng-scope">
<input ng-disabled="!grid.appScope.inEditMode(row, 'isDefault')" type="checkbox" ng-input="row.entity.isDefault" ng-model="row.entity.isDefault"
class="ng-pristine ng-valid ng-touched">
</div>
</div>
</div>
</div>
</div>
</div>
在这种情况下,我有一个 ID 为 loanLossAssumptionrating3InputField 的输入字段句柄。从这里,我需要从此 ui-grid-row 中获取其他复选框。在此示例中,一个复选框出现在标记末尾附近,位于 6 个结束 div 标记之前。
随着时间的推移,我们构建了一个函数库,因此这里提到了“lib”。在这段代码中。这只是对我们图书馆的工作参考。这段代码在 pageObject 中。
lib.getCheckboxInRow(fields.ratingFieldId, 0).then(function (checkboxElement)
// The fields.ratingFieldId value = "loanLossAssumptionrating3InputField"
checkboxElement.click();
);
这只是一次“点击”尝试,但我还需要获取该元素并确定复选框是否被点击。在我的情况下,通过标记做到这一点的唯一方法是读取父元素中的属性。我知道该怎么做,但我提供了这个细节来说明我为什么要尝试返回元素本身。
这是我的目标函数。两种尝试如下所示。这两个都失败了。这是在我的图书馆里。
// Attempt A
public getCheckboxInRow(siblingElementId: string, checkboxIndex: number): webdriver.promise.Promise<protractor.ElementFinder>
var xPathToRow : string = "./ancestor::div[contains(concat(' ', @class, ' '), ' ui-grid-row ')][1]";
return element(by.id(siblingElementId)).element(by.xpath(xPathToRow)).then(function (row)
return row.all(by.css("input[@type='checkbox']")).filter.then(function (checkboxArray)
return checkboxArray[checkboxIndex];
);
);
// Attempt B
public getCheckboxInRow(siblingElementId: string, checkboxIndex: number): webdriver.promise.Promise<protractor.ElementFinder>
var xPathToRow : string = "./ancestor::div[contains(concat(' ', @class, ' '), ' ui-grid-row ')][1]";
var cssToCheckbox : string = "input[@type='checkbox']";
return element(by.id(siblingElementId)).element(by.xpath(xPathToRow)).all(by.css(cssToCheckbox)).filter(function(checkbox)
return true;
).then(function (checkboxArray)
return checkboxArray[checkboxIndex];
);
使用“尝试 A”会发生以下错误。
TypeError: element(...).element(...).then 不是函数
“尝试 B”的错误更加严重。
InvalidSelectorError: 无效选择器:无效或非法的选择器 已指定(会话信息:chrome=47.0.2526.111)(驱动程序信息: 铬驱动程序=2.19.346078 (6f1f0cde889532d48ce8242342d0b84f94b114a1),平台=Windows NT 6.3 x86_64) (警告:服务器未提供任何堆栈跟踪 信息)命令持续时间或超时:30毫秒对于 有关此错误的文档,请访问: http://seleniumhq.org/exceptions/invalid_selector_exception.html 构建 信息:版本:'2.47.1',修订:'411b314',时间:'2015-07-30 03:03:16' 系统信息:主机:'PSIDEVKPALM',ip:'10.226.128.27', os.name: 'Windows Server 2012 R2', os.arch: 'x86', os.version: '6.3', java.version: '1.8.0_66' 驱动程序信息: org.openqa.selenium.chrome.ChromeDriver 功能 [applicationCacheEnabled=false, 可旋转=false, mobileEmulationEnabled=false, 铬=userDataDir=C:\Users\kpalmer\AppData\Local\Temp\2\scoped_dir7352_8503, 需要HeapSnapshot=true,databaseEnabled=false,handlesAlerts=true, hasTouchScreen=false,版本=47.0.2526.111,平台=WIN8_1, browserConnectionEnabled=false,nativeEvents=true, acceptSslCerts=true,locationContextEnabled=true, webStorageEnabled=true,browserName=chrome,takeScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true] 会话 ID: 12959162beeed374185734ef29b03b57 *** 元素信息:Using=css selector, value=input[@type='checkbox']
在这方面花了很多时间,我不知道为什么会失败。
最终我想要的是一个函数,它将返回一个复选框元素,该元素与该行内的另一个元素位于同一行,基于复选框索引,以便我们可以单击复选框或确定该元素是否是选中或未选中。
感谢您的帮助。
=== 2016 年 1 月 2 日下午编辑 ===
谢谢@alecxe,你帮了大忙。这是我运行的最终实现。这两种方法都有效。
其中任何一个都可以在我的 pageObject 中使用。
lib.getCheckboxInRow(fields.ratingFieldId, 0).click();
lib.getCheckboxArrayInRow(fields.ratingFieldId).filter(function (checkboxArray, index)
return (index === 0);
).first().click();
这些是库中的目标函数。我必须调整的一件事是返回类型,从承诺到元素查找器。这些工作就像一个冠军。
public getCheckboxInRow(siblingElementId: string, checkboxIndex: number): protractor.ElementFinder
var xPathToRow : string = "./ancestor::div[contains(concat(' ', @class, ' '), ' ui-grid-row ')][1]";
return element(by.id(siblingElementId)).element(by.xpath(xPathToRow)).all(by.css("input[type=checkbox]")).filter(function (checkboxArray, index)
return index === checkboxIndex;
).first();
;
public getCheckboxArrayInRow(siblingElementId: string): protractor.ElementArrayFinder
var xPathToRow : string = "./ancestor::div[contains(concat(' ', @class, ' '), ' ui-grid-row ')][1]";
return element(by.id(siblingElementId)).element(by.xpath(xPathToRow)).all(by.css("input[type=checkbox]"));
;
【问题讨论】:
【参考方案1】:让我们回顾一下你的尝试。
Attempt A
由于 Protractor 2.0.0 (changelog) 以来您无法使用 then()
解析 ElementFinder
,因此您收到了 TypeError: element(...).element(...).then is not a function
错误。
在这种情况下,您可以继续链接 element
和 all()
:
public getCheckboxInRow(siblingElementId: string, checkboxIndex: number): webdriver.promise.Promise<protractor.ElementFinder>
var xPathToRow : string = "./ancestor::div[contains(concat(' ', @class, ' '), ' ui-grid-row ')][1]";
return element(by.id(siblingElementId)).element(by.xpath(xPathToRow)).all(by.css("input[type=checkbox]")).filter(function (checkboxArray, index)
return index === checkboxIndex;
).first();
我还修正了您应用 filter()
函数的方式。请注意 first()
调用 - 这将帮助我们获得单个过滤元素而不是数组。
Attempt B
您收到 An invalid or illegal selector was specified
错误,因为您实际上有一个无效的 CSS 选择器 input[@type='checkbox']
- 您不需要在 CSS 中的属性名称前面添加 @
- 将其替换为 input[type=checkbox]
(不需要单个引号)。
而且,您在此尝试中也没有正确应用 filter()
函数。固定版本:
public getCheckboxInRow(siblingElementId: string, checkboxIndex: number): webdriver.promise.Promise<protractor.ElementFinder>
var xPathToRow : string = "./ancestor::div[contains(concat(' ', @class, ' '), ' ui-grid-row ')][1]";
var cssToCheckbox : string = "input[type=checkbox]";
return element(by.id(siblingElementId)).element(by.xpath(xPathToRow)).all(by.css(cssToCheckbox)).filter(function(checkbox, index)
return checkboxIndex === index;
).first();
这基本上与尝试 A 相同。
【讨论】:
哇!希望我昨天会问。谢谢@alecxe。我现在试一试。 这更接近目标。我现在需要修复对函数的调用,因为出现以下错误:TypeError: lib.getCheckboxInRow(...).then is not a function。以上是关于如何使用量角器返回此复选框元素?的主要内容,如果未能解决你的问题,请参考以下文章
量角器JS chai - 我如何使用getText()断言数组中的元素文本包含字符串?