Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Page object pattern with protractor

I am trying to creat to page object files with protractor.

My app has the following layout. enter image description here and page object files..

navbar_po.js

var NavBar = function() {
    // define navbar elements and operations
    //  .
    //  .   
};
module.exports = NavBar;

subNavbar_po.js

var SubNavBar = function() {
    // define subnavbar elements and operations
    //  .
    //  .   
};
module.exports = SubNavBar;

page1_po.js

var Page1 = function() {

    this.navbar = function(){
        var navbar = require('./navbar_po.js');
        return new navbar();
    }
    this.subnavbar = function(){
        var subnavbar = require('./subNavbar_po.js');
        return new subnavbar();
    }

    // define Page1 particular elements and operations
    //  .
    //  .
};
module.exports = Page1;

and I access the navbar elements as follows in test script..

var page1 = new require('./page1_po.js');   

page1.navbar.something_method();
page1.subnavbar.something_method();

Is this the best way?

I don't want to define the same navbar elements for each page object file.

Is there any other good way?

like image 729
dafunk Avatar asked Mar 11 '23 15:03

dafunk


1 Answers

Ok, great question, super detailed information too!

🛠 Let's get to it. We'll be using ES6 syntax!

Small structural conventions will make the project easier to maintain and won't need defining the same navbar (or any other) elements for each page object file.

Also, the suggested filename kebab-case style will help keep things recognizable as your project grows :)

navbar_po.js // suggest renaming to nav-bar.pageObject.js

export default class NavBar {
  constructor() {
    this.homePageButton = element(by.id('home-button'))
    // more element locators
  }

  function clickHomePageButton() {
    this.homePageButton.click()
  }

  // more operations
}

subNavbar_po.js // suggest renaming to sub-nav-bar.pageObject.js

export default class SubNavBar {
  constructor() {
    this.aboutPageButton = element(by.id('about-button'))
    // more element locators
  }

  function clickAboutPageButton() {
    this.aboutPageButton.click()
  }

  // more operations
}

page1_po.js // suggest renaming to page-one.pageObject.js

import SubNavBar from './sub-nav-bar.pageObject' // the .js at the end can be omitted, it will know it's JS!
import navBar from './nav-bar.pageObject'

export default class pageOne {
  constructor() {
    this.NavBar = NavBar
    this.SubNavBar = SubNavBar
    // more element locators
  }

  function visitHomePageThenAboutPage() {
    const navBar = new NavBar()
    const subNavBar = new SubNavBar

    navBar.clickHomePageButton()
    subNavBar.clickAboutPageButton()
  }

  // more operations
}

your test script

pageOne.spec.js

If any of your elements change, you only ever need to change them in the relevant pageObject file. Nothing else needs changing, not even your test script!

import PageOne from './page-one.pageObject');   

describe('navigating', () => {
   it('should go to home and about', () => {
     const pageOne = new PageOne()
     pageOne.visitHomePageThenAboutPage()
     // expect statement
   }
}

💡 pageObject concept

Imagine that your test script mimics human interaction with your site. And pageObjects are how you abstract away and hide exactly what needs to be done for those user behaviours to interact with your page.

📚 Resources

The following is a great styleguide that helps keep things manageable ✨

https://github.com/CarmenPopoviciu/protractor-styleguide

Also, checkout this (disclaimer: my) curated list on all things awesome for Protractor! Make a pull request if you ever want to add anything!

Good luck testing!

https://github.com/chowdhurian/awesome-protractor

like image 133
Manil Avatar answered Mar 15 '23 11:03

Manil