我试图在Protractor测试中聚合一个用Angular编写的数据表中的日期列表。我正在从Protractor测试中调用的PageObject类进行聚合。我知道我的代码成功地抓取了我想要的文本,但是当我尝试console.log返回的数组时,我得到一个空数组。我还是Javascript / Typescript,Angular和Protractor的新手,这可能是我对这个开发环境的异步性质的新见解的结果。
代码如下,
带有方法的PageObject SpecMapper类:
import { browser, element, by } from 'protractor';
export class SpecMapperPage {
getImportDateSubmittedColumnValues() {
let stringDatesArray: Array<string> = [];
// currently this css selector gets rows in both import and export tables
// TODO: get better identifiers on the import and export tables and columns
element.all(by.css('md-card-content tbody tr.ng-tns-c3-0')).each(function(row, index){
// check outerHTML for presence of "unclickable", the rows in the export table
row.getAttribute('outerHTML').then(function(outerHTML:string) {
// specifically look for rows without unclickable
if(outerHTML.indexOf("unclickable") < 0){
// grab the columns and get the third column, where the date submitted field is
// TODO: get better identifiers on the import and export columns
row.all(by.css("td.ng-tns-c3-0")).get(2).getText().then(function(text:string) {
stringDatesArray.push(text);
});
}
});
});
return stringDatesArray;
}
}
我知道它不是最漂亮的代码,但它是临时占位符,而我的开发人员让我有更好的属性/类/ ID来抓取我的变量。需要注意的关键是我创建了一个字符串Array来保存我认为在方法完成时返回的值。
我使用了WebStorm并在stringDatesArray.push(text)
和return stringDatesArray
行添加了断点。第一行显示text
变量有一个我正在寻找并成功推送的字符串变量。我在调试模式下看到了成功,因为我可以看到stringDatesArray
并查看其中的值。但是第二行,即数组返回,表明局部变量stringDatesArray
为空。当我尝试console.log数组时,在以下代码中回应:
量角器在我的测试中运行Spec类:
import { SpecMapperPage } from "./app.po";
import {browser, ExpectedConditions} from "protractor";
describe('spec mapper app', () => {
let page: SpecMapperPage;
let PROJECT_ID: string = '57';
let PROJECT_NAME: string = 'DO NOT DELETE - AUTOMATED TESTING PROJECT';
beforeEach(() => {
page = new SpecMapperPage();
});
describe('import/export page', () => {
it('verify sort order is desc', () => {
browser.waitForAngularEnabled(false);
// Step 1: Launch Map Data from Dashboard
page.navigateTo(PROJECT_ID);
browser.driver.sleep(5000).then(() => {
// Verify: Mapping Screen displays
// Verify on the specmapper page by checking the breadcrumbs
expect(page.getProjectNameBreadCrumbText()).toContain(PROJECT_NAME);
expect(page.getProjectMapperBreadCrumbText()).toEqual("MAPPER");
// Verify: Verify Latest Submitted Date is displayed at the top
// Verify: Verify the Submitted Date column is in descending order
console.log(page.getImportDateSubmittedColumnValues());
});
});
});
});
我承认这段代码没有积极使用量角器的细节,我们的应用程序已知问题几个月内无法解决,所以我99%的时间直接访问驱动程序。
您需要注意,我将上面发布的方法称为browser.driver.sleep().then()
子句page.getImportDateSubmittedColumnValues()
中的最后一行。
我想也许我在加载页面之前遇到异步问题,因此我把它放在.then()
子句中;但通过调试得知并非如此。一旦我正确地返回数组,此代码应该可以工作。
console.log正在打印一个空的[]
数组。这与我在PageObject SpecMapper类中直接调试上述方法时看到的结果是同义的。我希望做一些验证,确保字符串格式正确,然后我将进行一些日期顺序比较。我觉得返回从页面检索到的数据数据并不是一个不寻常的请求,但我似乎无法找到一个很好的方式谷歌我想做的事情。
如果我遇到一些非常明显的障碍,我很抱歉,我还在学习Typescript / Angular / Protractor的细微差别。谢谢你的考虑!
我试图使用整理的承诺似乎很有希望,但在执行时却落空了。
我更新的PageObject SpecMapper类
import {browser, element, by, protractor} from 'protractor';
export class SpecMapperPage {
getImportDateSubmittedColumnValues() {
let promisesArray = [];
let stringDatesArray: Array<string> = [];
// This CSS selector grabs the import table and any cells with the label .created-date
element.all(by.css('.import-component .created-date')).each(function(cell, index) {
// cell.getText().then(function(text:string) {
// console.log(text);
// });
promisesArray.push(cell.getText());
});
return protractor.promise.all(promisesArray).then(function(results) {
for(let result of results) {
stringDatesArray.push(result);
}
return stringDatesArray;
});
}
}
我更新的规范测试使用更新的SpecMapper PO类
import { SpecMapperPage } from "./specMapper.po";
import {browser, ExpectedConditions} from "protractor";
describe('spec mapper app', () => {
let page: SpecMapperPage;
let PROJECT_ID: string = '57';
let PROJECT_NAME: string = 'DO NOT DELETE - AUTOMATED TESTING PROJECT';
beforeEach(() => {
page = new SpecMapperPage();
});
describe('import/export page', () => {
it('TC2963: ImportComponentGrid_ShouldDefaultSortBySubmittedDateInDescendingOrder_WhenPageIsLoaded', () => {
browser.waitForAngularEnabled(false);
// Step 1: Launch Map Data from Dashboard
page.navigateTo(PROJECT_ID);
browser.driver.sleep(5000).then(() => {
// Verify: Mapping Screen displays
// Verify on the specmapper page by checking the breadcrumbs
expect(page.getProjectNameBreadCrumbText()).toContain(PROJECT_NAME);
expect(page.getProjectMapperBreadCrumbText()).toEqual("MAPPER");
// Verify: Verify Latest Submitted Date is displayed at the top
// Verify: Verify the Submitted Date column is in descending order
page.getImportDateSubmittedColumnValues().then(function(results) {
for(let value of results) {
console.log("a value is: " + value);
}
});
});
});
});
});
当我在return stringDatesArray;
行的PO类中断点时,我在不同的范围内有以下变量。请注意,promisesArray有3个对象,但进入protractor.promise.all(
块的结果数组有0个对象。我不确定我的脱节是什么。 :/
我认为我遇到了范围问题,我遇到了理解问题。你会注意到getText()
上已注释掉的承诺解决方案,这是我的POC证明我得到了我期待的字符串值,所以我不确定为什么会这样#&# 39;不在Promise Array结构中工作,作为下面的解决方案。
我能找到的其他相关问题与抓取表格的特定行有关,而不是专门聚合要在Protractor中返回进行测试验证的数据。如果您有兴趣,可以找到它here。
答案 0 :(得分:1)
正如您所提到的那样,您的问题是由console.log在实际填充之前返回变量的值引起的。
我从这个答案中拿了一个片段,可以让你解决它:Is there a way to resolve multiple promises with Protractor?
var x = element(by.id('x')).sendKeys('xxx');
var y = element(by.id('y')).sendKeys('yyy');
var z = element(by.id('z')).sendKeys('zzz');
myFun(x,y,z);
//isEnabled() is contained in the expect() function, so it'll wait for
// myFun() promise to be fulfilled
expect(element(by.id('myButton')).isEnabled()).toBe(true);
// in a common function library
function myFun(Xel,Yel,Zel) {
return protractor.promise.all([Xel,Yel,Zel]).then(function(results){
var xText = results[0];
var yText = results[1];
var zText = results[2];
});
}
因此,在您的代码中,它将类似于
getImportDateSubmittedColumnValues() {
let promisesArray = [];
let stringDatesArray: Array<string> = [];
// currently this css selector gets rows in both import and export tables
// TODO: get better identifiers on the import and export tables and columns
element.all(by.css('md-card-content tbody tr.ng-tns-c3-0')).each(function(row, index){
// check outerHTML for presence of "unclickable", the rows in the export table
row.getAttribute('outerHTML').then(function(outerHTML:string) {
// specifically look for rows without unclickable
if(outerHTML.indexOf("unclickable") < 0){
// grab the columns and get the third column, where the date submitted field is
// TODO: get better identifiers on the import and export columns
promisesArray.push(row.all(by.css("td.ng-tns-c3-0")).get(2).getText());
}
});
});
return protractor.promise.all(promisesArray).then(function(results){
// In here you'll have access to the results
});
}
你可以通过几种不同的方式来做到这一点。您可以在最后处理该方法中的数据,或者我认为您可以在“then”中返回该数组,并像这样访问它:
page.getImportDateSubmittedColumnValues().then((res) =>{
//And then here you will have access to the array
})
答案 1 :(得分:1)
我不做 Typescript 但是如果你只想从你的方法中获取一系列定位文本,那么类似的东西应该有效。
getImportDateSubmittedColumnValues() {
let stringDatesArray: Array<string> = [];
$$('.import-component .created-date').each((cell, index) => {
cell.getText().then(text => {
stringDatesArray.push(text);
});
}).then(() => {
return stringDatesArray;
});
}
答案 2 :(得分:1)
答案最终与How do I return the response from an asynchronous call?
上发布的答案有关最终的PageObject类函数:
import {browser, element, by, protractor} from 'protractor';
export class SpecMapperPage {
getImportDateSubmittedColumnValues() {
let stringDatesArray: Array<string> = [];
let promisesArray = [];
// return a promise promising that stringDatesArray will have an array of dates
return new Promise((resolve, reject) => {
// This CSS selector grabs the import table and any cells with the label .created-date
element.all(by.css('.import-component .created-date')).map((cell) => {
// Gather all the getText's we want the text from
promisesArray.push(cell.getText());
}).then(() => {
protractor.promise.all(promisesArray).then((results) => {
// Resolve the getText's values and shove into array we want to return
for(let result of results) {
stringDatesArray.push(result);
}
}).then(() => {
// Set the filled array as the resolution to the returned promise
resolve(stringDatesArray);
});
});
});
}
}
最终的测试课程:
import { SpecMapperPage } from "./specMapper.po";
import {browser, ExpectedConditions} from "protractor";
describe('spec mapper app', () => {
let page: SpecMapperPage;
let PROJECT_ID: string = '57';
let PROJECT_NAME: string = 'DO NOT DELETE - AUTOMATED TESTING PROJECT';
beforeEach(() => {
page = new SpecMapperPage();
});
describe('import/export page', () => {
it('TC2963: ImportComponentGrid_ShouldDefaultSortBySubmittedDateInDescendingOrder_WhenPageIsLoaded', () => {
browser.waitForAngularEnabled(false);
// Step 1: Launch Map Data from Dashboard
page.navigateTo(PROJECT_ID);
browser.driver.sleep(5000).then(() => {
// Verify: Mapping Screen displays
// Verify on the specmapper page by checking the breadcrumbs
expect(page.getProjectNameBreadCrumbText()).toContain(PROJECT_NAME);
expect(page.getProjectMapperBreadCrumbText()).toEqual("MAPPER");
// Verify: Verify Latest Submitted Date is displayed at the top
// Verify: Verify the Submitted Date column is in descending order
page.getImportDateSubmittedColumnValues().then((results) => {
console.log(results);
});
});
});
});
});
最重要的是等待不同的调用完成运行然后等待stringDataArray被填充。这需要我在上面提到的SO帖子中找到的承诺(解决,拒绝)结构。我最终使用lambda (()=>{})
函数调用而不是声明(function(){})
来获得更清晰的外观,该方法的工作方式相同。其他提议的解决方案都没有成功地将字符串数组传播回我的测试。我使用Protractor在Typescript中工作。