【问题标题】:Selenium/WebdriverJs/Protractor promise chaining with page objectsSelenium/WebdriverJs/Protractor 承诺与页面对象链接
【发布时间】:2016-05-09 23:21:35
【问题描述】:

我目前正在量角器/硒中实现页面对象模式。

由于量角器中的每个方法都返回一个承诺,为了保持一致,我的页面对象中的方法也应该返回一个承诺。

此外,我的页面对象可能具有返回另一个页面对象或页面对象自定义的函数(如 LeftNavigation、MainContent)。与其返回页面对象本身,不如在承诺中返回页面对象。目前我真的不明白该怎么做。

另外,我想在不使用 .then(..) 方法的情况下链接我的方法调用。对于 WebElements,可以在不调用 .then(..) 方法的情况下调用更多函数,例如

browser.driver.findElement(By.css('#someid')).findElement(By.css('#somebutton')).click();

我也想通过页面对象模式来实现这一点:

let pagePromise = AdminBaseBage.get(); // returns a Promise<AdminBasePage>
let mContent = page.mainContent;// should return a Promise<MainContent>
let titlePromise = mContent.getModuleTitle(); // returns a Promise<string>

甚至更好

AdminBaseBage.get().mainContent.getModuleTitle();

下面是我的 PageObjects 的摘录,这里有一些问题:

AdminBasePage.js

var LeftNavigation = require('../../pageobject/LeftNavigation.js');
var MainContent = require('../../pageobject/MainContent.js');

class AdminBasePage {

    constructor() {
        this._leftNavigation = new LeftNavigation();
        this._mainContent = new MainContent();
    }

    /**
     * @returns {Promise<AdminBasePage>}
     */
    static getPage() {
        return browser.driver.get("index.php").then(function() {
            return new AdminBasePage();
        });
    }

    /**
     * @returns <LoginPage>
     */
    logout() {
        this.leftNavigation.logout();
        return new LoginPage(); //also here I would like to return a promise.
    }

    /**
     * @returns {LeftNavigation}
     */
    get leftNavigation() {
        //Instead of return the object directly, I would like to return a promise here. 
        //But how?
        return this._leftNavigation;
    };

    /**
     * @returns {MainContent}
     */
    get mainContent() {
        //Instead of return the object directly, I would like to return a promise here. 
        //But how?
        return this._mainContent;
    };
}

module.exports = AdminBasePage;

MainContent.js

class MainContent {

    constructor() {

        /** @type {WebElementPromise} */
        this._element_mainContent = this.webDriver.findElement(By.css('#maincontent'));

    }


    /**
     * Gets the title of the main content
     *
     * @returns {webdriver.promise.Promise<string>}
     */
    getMainContentTitle() {
        return this._element_mainContent
                   .findElement(By.id('moduleTitle'))
                   .getText();
    }

}

/** @type {MainContent} */
module.exports = MainContent;

你能给点建议吗? 我希望以某种方式清楚我要解释的内容:-)

问候

【问题讨论】:

    标签: javascript selenium promise chaining


    【解决方案1】:

    您不应该尝试将 PageObject 设为 Promise。 PageObject 应该是方法/属性工厂,因此不应成为执行流程中的约束。 我会通过返回一个带有属性的元素来保持简单,而不是尝试在构造函数中定位所有元素:

    describe('Suite', function() {
    
        it('should module title be ...', function() {
            let pageAdmin = AdminBaseBage.get();
            let mContent = pageAdmin.mainContent;
            let titlePromise = mContent.getModuleTitle();
            expect(titlePromise).toEqual('module title');
        });
    
    });
    
    
    class MainContent {
    
        constructor() {
    
        }
    
        get element_module_title() { return element(By.css('#maincontent #moduleTitle')); }
    
        /**
         * Gets the title of the main content
         *
         * @returns {webdriver.promise.Promise<string>}
         */
        getModuleTitle() {
            return this.element_module_title.getText();
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      感谢您的意见。

      你说得对,页面对象不应该限制执行流程。我会忘记在这里做出承诺:-)。 我还将 constrcturos 中的元素初始化提取到 getter 方法。

      我的主页对象现在由我创建的几个页面元素(LeftNavigation、TopMenu 等)组成。 现在,这些页面元素中的每一个都可以访问它们需要的 WebElement(仅通过 getter 方法)。

      class AdminBasePage extends BasePage {
      
          constructor{
              super();
      
              /** @type {LeftNavigation} */
              this._leftNavigation = new LeftNavigation();
      
              /** @type {TopMenu} */
              this._topMenu = new TopMenu();
      
              /** @type {PathNavi} */
              this._pathNavi = new PathNavi();
      
              /** @type {ContentTopBar} */
              this._contentTopBar = new ContentTopBar();
      
          /** @type MainContent*/
              this._mainContent = new MainContent()
          }
      
         /**
          * @returns {Promise<AdminBasePage>}
          */
          static getPage() {
              return browser.driver.get("index.php").then(function() {
                  return new AdminBasePage();
              });
          }
      
          ....getters + other methods follow
      
      }
      

      我的测试现在如下所示:

      describe('module_checklist', function () {
           it('Check number of elements in list', function () {
              let page = AdminBasePage.getPage();//returns Promise<AdminBage>
      
              // check number of list rows
              page.then(function (templateListPage) {
                      return templateListPage.mainContent.getArrListRows();//returns Promise<ListRow[]>
                  })
                  .then(function (arrRows) {
                      expect(arrRows.length).toEqual(2);
                  });
      
      
              //check total number in pagination
              page.then(function (templateListPage) {
                  expect(templateListPage.mainContent.getPagination().getIntPaginationTotalNumber()).toEqual(2);
              });
          });
      }
      

      【讨论】:

      • 不需要所有的.then,你应该删除它们。
      • 这是我已经尝试过的,但它不起作用。这就是我使用.then 的原因。尝试执行此操作时:expect(page.mainContent.getPagination().getIntPaginationTotalNumber()).toEqual(2); 我收到错误TypeError: Cannot read property 'getPagination' of undefined 这是因为在这种情况下page 是一个承诺(参见方法AdminBasePage.getPage())。
      猜你喜欢
      • 2015-10-26
      • 1970-01-01
      • 2017-10-14
      • 2018-11-08
      • 2015-04-15
      • 2023-01-27
      • 2015-01-21
      • 2016-01-17
      • 1970-01-01
      相关资源
      最近更新 更多