2016-01-20 2 views
2

Я пишу тест Typcript/Protractor, который должен оценивать и выбирать элементы флажка в сетке. В этих флажках отсутствуют идентификаторы. Поскольку я могу получить дескриптор элементов ввода, которые находятся в той же строке, что и эти флажки, я пытаюсь получить их через комбинацию элементов поиска (by.id, by.xpath и by.css). Но мои попытки терпят неудачу.Как я могу вернуть этот элемент флажка с помощью Protractor?

Что я хотел бы написать, это небольшая функция, которая вернет целевой элемент флажка из строки на основе удаленного элемента «sibling» в строке и индекса флажка в строке. Я пробовал несколько вещей, и то, что я считаю наиболее перспективными, выкладывается здесь.

Это раздел разметки из сетки, на которую я нацеливаюсь. Несколько ячеек информации опущены для ясности. Это то, с чем я борюсь. Я не могу изменить разметку, меня попросили написать тесты Protractor.

<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 &amp;&amp; !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 &amp;&amp; !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> 

В этом случае, у меня есть ручка на поле ввода с идентификатором loanLossAssumptionrating3InputField. Отсюда, я должен получить другие флажки из этой строки ui-grid. В этом примере перед гаммой разметки появляется один флажок перед 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 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']}

Проведя много часов работы над этим, я не понимаю, почему они терпят неудачу.

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

Благодарим за помощь.

=== Edit 1/2/2016 днем ​​===

Спасибо @alecxe, ты огромная помощь. Вот окончательные реализации, с которыми я работал. Оба эти подхода работают.

Любой из них будет работать в моей странице.

lib.getCheckboxInRow(fields.ratingFieldId, 0).click(); 

lib.getCheckboxArrayInRow(fields.ratingFieldId).filter(function (checkboxArray, index) { 
    return (index === 0); 
}).first().click(); 

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

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]")); 
}; 

ответ

2

Давайте рассмотрим ваши попытки.

  • Attempt A

Вы получаете ошибку TypeError: element(...).element(...).then is not a function, так как вы не можете разрешить ElementFinder с then() так транспортир 2.0.0 (changelog).

Вы можете просто продолжать сцепление 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(); 
} 

, которая, по существу, становится таким же, как Попытка А.

+0

Wow! Хотел бы я спросить вчера. Спасибо @alecxe. Сейчас я делаю это. –

+0

Это намного ближе к знаку. Мне нужно исправить мой вызов функции сейчас, так как появляется следующая ошибка: TypeError: lib.getCheckboxInRow (...), а затем не является функцией. –

Смежные вопросы