我在寫一個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 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 is not a function
「嘗試B」的錯誤更加劇烈。
InvalidSelectorError: invalid selector: An invalid or illegal selector was specified (Session info: chrome=47.0.2526.111) (Driver info: chromedriver=2.19.346078 (6f1f0cde889532d48ce8242342d0b84f94b114a1),platform=Windows NT 6.3 x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 30 milliseconds For documentation on this error, please visit: http://seleniumhq.org/exceptions/invalid_selector_exception.html Build info: version: '2.47.1', revision: '411b314', time: '2015-07-30 03:03:16' System info: host: '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' Driver info: org.openqa.selenium.chrome.ChromeDriver Capabilities [{applicationCacheEnabled=false, rotatable=false, mobileEmulationEnabled=false, chrome={userDataDir=C:\Users\kpalmer\AppData\Local\Temp\2\scoped_dir7352_8503}, takesHeapSnapshot=true, databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false, version=47.0.2526.111, platform=WIN8_1, browserConnectionEnabled=false, nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true, webStorageEnabled=true, browserName=chrome, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true}] Session ID: 12959162beeed374185734ef29b03b57 *** Element info: {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]"));
};
哇!希望我昨天會問。感謝@alecxe。我現在就給這個鏡頭。 –
這更接近該商標。我需要現在修復我對函數的調用,因爲出現以下錯誤:TypeError:lib.getCheckboxInRow(...)。然後不是函數。 –