What's the correct Protractor's syntax for Page Objects?

可紊 提交于 2019-12-03 03:49:48

Page Object Model framework becomes popular mainly because of:

  1. Less code duplicate
  2. Easy to maintain for long
  3. High readability

So, generally we develop test framework(pom) for our convenience based on testing scope and needs by following suitable framework(pom) patterns. There are NO such rules which says that, strictly we should follow any framework.

NOTE: Framework is, to make our task easy, result oriented and effective

In your case, 1st one looks good and easy. And it does not leads to confusion or conflict while in maintenance phase of it.

Example: 1st case-> element locator's declaration happens at top of each page. It would be easy to change in case any element locator changed in future.

Whereas in 2nd case, locators declared in block level(scatter across the page). It would be a time taking process to identify and change the locators if required in future.

So, Choose which one you feel comfortable based on above points.

I prefer to use ES6 class syntax (http://es6-features.org/#ClassDefinition). Here, i prepared some simple example how i work with page objects using ES6 classes and some helpful tricks.

var Page = require('../Page')
var Fragment = require('../Fragment')

class LoginPage extends Page {
    constructor() {
        super('/login');
        this.emailField = $('input.email');
        this.passwordField = $('input.password');
        this.submitButton = $('button.login');

        this.restorePasswordButton = $('button.restore');
    }

    login(username, password) {
        this.email.sendKeys(username);
        this.passwordField.sendKeys(password);
        this.submit.click();
    }

    restorePassword(email) {
        this.restorePasswordButton.click();
        new RestorePasswordModalWindow().submitEmail(email);
    }
}

class RestorePasswordModalWindow extends Fragment {
    constructor() {
        //Passing element that will be used as this.fragment;
        super($('div.modal'));
    }

    submitEmail(email) {
        //This how you can use methods from super class, just example - it is not perfect.
        this.waitUntilAppear(2000, 'Popup should appear before manipulating');
        //I love to use fragments, because they provides small and reusable parts of page.
        this.fragment.$('input.email').sendKeys(email);
        this.fragment.$('button.submit')click();
        this.waitUntilDisappear(2000, 'Popup should disappear before manipulating');
    }
}
module.exports = LoginPage;

// Page.js
class Page {
    constructor(url){
        //this will be part of page to add to base URL.
        this.url = url;
    }

    open() {
        //getting baseURL from params object in config.
        browser.get(browser.params.baseURL + this.url);
        return this; // this will allow chaining methods.
    }
}
module.exports = Page;

// Fragment.js
class Fragment {
    constructor(fragment) {
        this.fragment = fragment;
    }

    //Example of some general methods for all fragments. Notice that default method parameters will work only in node.js 6.x
    waitUntilAppear(timeout=5000, message) {
        browser.wait(this.EC.visibilityOf(this.fragment), timeout, message);
    }

    waitUntilDisappear(timeout=5000, message) {
        browser.wait(this.EC.invisibilityOf(this.fragment), timeout, message);
    }
}
module.exports = Fragment;

// Then in your test:
let loginPage = new LoginPage().open(); //chaining in action - getting LoginPage instance in return.
loginPage.restorePassword('batman@gmail.com'); // all logic is hidden in Fragment object
loginPage.login('superman@gmail.com')
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!