如何从Protractor中的表中收集聚合数据并将其作为数组返回?

时间:2017-10-11 19:16:39

标签: javascript angular typescript protractor

我试图在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个对象。我不确定我的脱节是什么。 :/

IntelliJ Debug Vars ScreenCap

我认为我遇到了范围问题,我遇到了理解问题。你会注意到getText()上已注释掉的承诺解决方案,这是我的POC证明我得到了我期待的字符串值,所以我不确定为什么会这样#&# 39;不在Promise Array结构中工作,作为下面的解决方案。

我能找到的其他相关问题与抓取表格的特定行有关,而不是专门聚合要在Protractor中返回进行测试验证的数据。如果您有兴趣,可以找到它here

3 个答案:

答案 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中工作。