Simple template to create page objects for AngularJS Protractor tests
npm install ngpoclientPo.name.enterValue('franky');
expect(clientPo.name.getValue()).toBe('franky');
expect(clientPo.name.isVisible()).toBe(true);
expect(clientPo.payments.getRow(1).amount.getValue()).toBe('423');
npm install ngpo.
javascript
var ngpo = require('ngpo');
var els = {
nameInput: {
locator: by.model('client.name'),
po: ngpo.makeInputPo},
name: {
locator: by.binding('client.name'),
po: ngpo.makeTextPo},
clearNameButton: {
locator: by.id('clear-name-button'),
po: ngpo.makeButtonPo},
typeDd: {
locator: by.model('client.type'),
po: ngpo.makeDdSelectPo}
};
var pos = ngpo.makePos(els);
`
And run a protractor test with those elements.
`javascript
var clientPo = require('client.po.js');
describe('client', function() {
it('should allow name to be modified', function() {
clientPo.nameInput.enterValue('franky');
expect(clientPo.nameInput.getValue()).toBe('franky');
expect(clientPo.name.getValue()).toBe('franky');
it('should clear the name', function() {
clientPo.clearNameButton.click();
expect(clientPo.name.getValue()).toBe('');
expect(clientPo.nameInput.getValue()).toBe('');
});
it('should allow client type to be selected', function() {
clientPo.typeDd.enterValue('cranky');
expect(clientPo.typeDd.getValue()).toBe('cranky');
expect(clientPo.type.getValue()).toBe('cranky');
});
});
`
#### Create a list page object using jsfiddle ngpo example.
`javascript
var ngpo = require('ngpo');
//Nest the list elements as another 'els' object in the list object ('payments' here):
var els = {
addPaymentButton: {
locator: by.id('add-payment-button'),
po: ngpo.makeButtonPo},
payments: {
locator: by.repeater('payment in payments'),
po: ngpo.makeListPo,
els: {
amountInput: {
locator: by.model('payment.amount'),
po: ngpo.makeInputPo},
amount: {
locator: by.binding('payment.amount'),
po: ngpo.makeTextPo},
},
}
};
var pos = ngpo.makePos(els);
`
Run the protractor test.
`javascript
var clientPo = require('client.po.js');
describe('client', function() {
it('should have working payment inputs', function() {
expect(clientPo.payments.count()).toBe(0);
clientPo.addPaymentButton.click()
.then(() => {
expect(clientPo.payments.count()).toBe(1);
// getRow() is the ngpo method to retrieve the row's nested elements.
// ngpo uses getRow() so as to not overwrite the get() method.
return clientPo.payments.getRow(0).amountInput.enterValue(5);
})
.then(() => {
expect(clientPo.payments.getRow(0).amountInput.getValue()).toBe('5');
expect(clientPo.payments.getRow(0).amount.getValue()).toBe('5');
return clientPo.addPaymentButton.click();
})
.then(() => {
expect(clientPo.payments.count()).toBe(2);
expect(clientPo.payments.getRow(0).amount.getValue()).toBe('5');
return clientPo.payments.getRow(1).amountInput.enterValue('423');
})
.then(() => {
expect(clientPo.payments.getRow(1).amountInput.getValue()).toBe('423');
expect(clientPo.payments.getRow(1).amount.getValue()).toBe('423');
});
});
});
`
Documentation
$3
* makePos
* Make page object functions and the functions attached (in addition to all expected Protractoor functions):
* makeDefaultPo
- isVisible
* makeTextPo
- getValue
- getValueTrim
- isVisible
* makeInputPo
- enterValue
- getValue
- getValueTrim
- isVisible
* makeDateInputPo
- enterValue
- getValue
- getValueTrim
- isVisible
- getValueMmddyyyy
- getValueYyyymmdd
* makeButtonPo
- isVisible
* makeButtonWithPausePo (deprecated)
* makeDdSelectPo
- enterValue
- getValue
- getValueTrim
- isVisible
- clear (selects first item in dd list)
* makeParentPo
- getValue
- subPo.poFn()
* makeListPo
- getRow
- getRow(n).subPo.poFn()
- getCount
- getValue
* poFns (optional fns that can be attached to page objects; see Append custom functions to page object elements)
- hasClass, makeHasClassFn : expect(clientPo.deleteHobbyButton.hasClass('yada')).toBe(true)
- clearByBs, makeHasClearByBs (use to clear date field in Chrome; Protractor issue #562) : clientPo.dobInput.clearByBs()
- clickWithPause (deprecated)
- getAttributeValue
* Other functions
* pause
* acceptAlert
* dismissAlert
#### How to
* Append custom functions to page object elements
* Clear a date field in Chrome (Protractor Issue #562) - Use poFns.clearByBs. See example in Append custom functions to page object elements.
* Nest ngpo page objects.
* Create your own _makePo_ functions: See makeDefaultPo. And github/npm it: See ngpo-ui-select.
$3
#### enterValue()
Enters a value into a page element and returns a Promise. How value is entered depends on the page element. Input elements use:
`javascript
return el
.click()
.clear()
.sendKeys(value)
.sendKeys(protractor.Key.TAB);
`
Example:
` javascript
clientPo.nameInput.enterValue('franky');
expect(clientPo.nameInput.getValue()).toBe('franky');
`
#### getValue()
Returns the value of the pageObject as a Promise. How value is retrieved depends on the page element:
* makeTextPo() uses Protractor getText()
* input POs (makeInputPo, makeDateInputPo) use Protractor getAttribute('value')
* makeDdSelectPo uses el.$('option:checked').getText()
` javascript
clientPo.nameInput.enterValue('franky');
expect(clientPo.nameInput.getValue()).toBe('franky'); // input
expect(clientPo.name.getValue()).toBe('franky'); // text by.binding
`
#### getValueTrim()
Returns pageObject.getValue() to a string.trim() as a Promise.
`javascript
clientPo.nameInput.enterValue(' b o bb y ');
expect(clientPo.nameInput.getValueTrim()).toBe('b o bb y');
`
#### isVisible()
Returns true as a Promise if isPresent and isDisplayed.
`javascript
expect(clientPo.showme.isPresent()).toBe(true);
expect(clientPo.showme.isDisplayed()).toBe(true);
expect(clientPo.showme.isVisible()).toBe(true);
// hide showme element
clientPo.showmeButton.click()
.then(function() {
expect(clientPo.showme.isPresent()).toBe(true);
expect(clientPo.showme.isDisplayed()).toBe(false);
expect(clientPo.showme.isVisible()).toBe(false);
});
`
$3
#### makePos(els)
Returns a Page Object: An object-literal of Protractor ElementFinder objects possibly with methods appended. Methods appended are based on the els object passed in.
makePos calls the function assigned to the po property for every object in the els object. The po function is called with (1) the locator and (2) the respective els object.
els is an object of the form :
`javascript
var els {
poName1: {
locator: protractorLocator // Req'd. eg; by.model('client.city')
po: makePoFn //Req'd. the function to append helper functions and return a protractor ElementFinder
els: {...} // optional nested object of same form els for list or parent pos
fns: {fnName: function} // optional object of custom functions that will be appended to this ElementFinder
yourParam: value // optional; any other parameter may be included for use in custom fns
},
poName2: ...
}
`
Example
`javascript
var ngpo = require('ngpo');
var els = {
nameInput: {
locator: by.model('client.name'),
po: ngpo.makeInputPo,
myOption: 'abc'},
};
var pos = ngpo.makePos(els);
`
In the above example, when makePos is called, makeInputPo will be called with
`javascript
makeInputPo(
by.model('clientName'),
{locator: by.model('client.name'),
po: ngpo.makeInputPo
myOption: 'abc'}
)
`
And return an object with the property nameInput which would be a protractor ElementFinder with getValue and enterValue methods appended (from makeInputPo).
#### makeDefaultPo(elOrLoc, options)
Returns a Protractor ElementFinder with only the isVisible ngpo function appended.
Determines if elOrLoc is a Protractor ElementFinder or locator. If it is a locator, creates an ElementFinder from it and returns that ElementFinder. Otherwise, returns ElementFinder as-is. options is the els object for the page object being created; eg, {locator: by.binding('client.name'), po: ngpo.makeTextPo}.
Every makeXxxPo function calls this function first. Custom makeXxxPo functions should also call this function first as well which will ensure that it will work as a 'sub' PO in list and parent elements.
Example
`javascript
function myCustomPo(elOrLoc, options) {
var el = makeDefaultPo(elOrLoc);
var yank = options && options.yank ? options.yank : '';
el.isBlada() = function() {
return el.getAttribute('blada') === yank;
}
return el;
}
var els = {
berl: {
locator: by.model('something.what'),
po: myCustomPo,
yank: 'green'
}
}
`
#### makeTextPo(elOrLoc, options)
Returns a Protractor ElementFinder with one appended function:
* getValue - returns element.getText()
Arguments: See makeDefaultPo and makePos.
Would typically be used with by.binding.
`javascript
var ngpo = require('ngpo');
var els = {
name: {
locator: by.binding('client.name'),
po: ngpo.makeTextPo}
};
var pos = ngpo.makePos(els);
`
#### makeInputPo(elOrLoc, options)
Returns a Protractor ElementFinder for html `` with these appended functions:
* getValue - returns element.getText()
* enterValue(value) : returns `element.click().clear().sendKeys(value).sendKeys(protractor.Key.TAB)`
Arguments: See makeDefaultPo and makePos.
Example
`javascript
var ngpo = require('ngpo');
var els = {
nameInput: {
locator: by.model('client.name'),
po: ngpo.makeInputPo}
};
var clientPo = ngpo.makePos(els);
// test example
clientPo.nameInput.enterValue('franky');
expect(clientPo.nameInput.getValue()).toBe('franky');
`
#### makeDateInputPo(elOrLoc, options)
Returns a Protractor ElementFinder for html `` tags with these appended functions:
* getValue - See makeInputPo
* enterValue(value) - See makeInputPo
* getValueMmddyyyy - getValue() as string mm/dd/yyyy format
* getValueYyyymmdd - getValue() as string yyyy-mm-dd format
Arguments: See makeDefaultPo and makePos.
Example
`javascript
var ngpo = require('ngpo');
var els = {
dobInput: {
locator: by.model('client.dob'),
po: ngpo.makeDateInputPo}
};
var clientPo = ngpo.makePos(els);
// test example
clientPo.dobInput.enterValue('01/01/1939');
expect(clientPo.dobInput.getValue()).toBe('1939-01-01');
expect(clientPo.dobInput.getValueMmddyyyy()).toBe('01/01/1939');
`
#### makeButtonPo(elOrLoc, options)
Returns a Protractor ElementFinder with no appended functions.
Arguments: See makeDefaultPo and makePos.
Example
`javascript
var ngpo = require('ngpo');
var els = {
deleteCityButton: {
locator: by.id('delete-city-button'),
po: ngpo.makeButtonPo}
};
var clientPo = ngpo.makePos(els);
// test example
clientPo.deleteCityButton.click();
`
#### makeButtonWithPausePo(elOrLoc, options)
Returns a Protractor ElementFinder with this amended function.
- click() : sleeps for options.pause milleseconds after click()
`element.click().then(function() {pause(options.pause);});`
Arguments: See makeDefaultPo and makePos.
Original ElementFinder click() method is available via element.p.click().
Example
`javascript
var ngpo = require('ngpo');
var els = {
deleteHobbyButton: {
locator: by.id('delete-hobby-button'),
po: ngpo.makeButtonWithPausePo,
pause: 5000}
};
var clientPo = ngpo.makePos(els);
// test example
clientPo.deleteHobbyButton.click(); // pauses 5 seconds after click()
`
#### makeDdSelectPo(elOrLoc, options)
Returns a Protractor ElementFinder for html `` tags
with these appended functions :
* getValue - returns `element.$('option:checked').getText()`
* enterValue(value) : returns `element.click().sendKeys(value).sendKeys(protractor.Key.TAB)`
Arguments: See makeDefaultPo and makePos.
Example
`javascript
var ngpo = require('ngpo');
var els = {
nameInput: {
locator: by.model('client.name'),
po: ngpo.makeInputPo}
};
var clientPo = ngpo.makePos(els);
// test example
clientPo.nameInput.enterValue('franky');
expect(clientPo.nameInput.getValue()).toBe('franky');
`
#### makeParentPo(elOrLoc, options)
Returns a Protractor ElementFinder which can have sub-ElementFinders on it.
Arguments: See makeDefaultPo and makePos.
Example
`javascript
var ngpo = require('ngpo');
var els = {
request: {
locator: by.id('request'),
po: ngpo.makeParentPo,
els: {
rInput: {
locator: by.model('client.request'),
po: ngpo.makeInputPo},
rText: {
locator: by.binding('client.request'),
po: ngpo.makeTextPo},
}
},
};
var clientPo = ngpo.makePos(els);
// test example
clientPo.request.rInput.enterValue('be nice');
expect(clientPo.request.rInput.getValue()).toBe('be nice');
expect(clientPo.request.rText.getValue()).toBe('be nice');
`
#### makeListPo(elOrLoc, options)
Returns a Protractor element.all object with nested protractor ElementFinders. It has these appended functions:
* getRow(n)
* getRow(n).subPo.poFn()
* getCount
* getValue
Arguments: See makeDefaultPo and makePos.
Example
`javascript
var ngpo = require('ngpo');
var els = {
payments: {
locator: by.repeater('payment in payments'),
po: ngpo.makeListPo,
els: {
amountInput: {
locator: by.model('payment.amount'),
po: ngpo.makeInputPo},
amount: {
locator: by.binding('payment.amount'),
po: ngpo.makeTextPo},
}
};
var clientPo = ngpo.makePos(els);
// test example
expect(clientPo.payments.getCount()).toBe(1);
clientPo.payments.getRow(0).amountInput.enterValue(5);
expect(clientPo.payments.getRow(0).amountInput.getValue()).toBe('5');
expect(clientPo.payments.getRow(0).amount.getValue()).toBe('5');
`
#### How to Nest Page Objects
Example to nest the transportation page object into a client page object.
`javascript
// transportation.po.js
var ngpo = require('../lib/index.js');
var els = {
transportationInput: {
locator: by.model('client.transportation'),
po: ngpo.makeInputPo},
transportation: {
locator: by.binding('client.transportation'),
po: ngpo.makeTextPo},
};
var pos = ngpo.makePos(els);
module.exports = pos;
`
There are 2 ways to nest the above transportation page object.
`javascript
// client.po.js
var ngpo = require('ngpo');
var transPo = require('./transportation.po.js');
// (1) directly in the client po els object
var els = {
transportationParent: {
locator: by.id('trans-parent'),
po: ngpo.makeParentPo,
els: transPo.els},
};
// (2) append the transportation page objects elements directly to the client po object
var pos = ngpo.makePos(els);
pos = ngpo.makePos(transPo.els, pos);
`
The protractor tests would refer to these like this:
`javascript
// #1 above would be called using transportationParent:
clientPo.transportationParent.transportationInput.enterValue('strides');
expect(clientPo.transportationParent.transportationInput.getValue()).toBe('strides');
// #2 would allow the transportation page object elements to be called directly from the client po
clientPo.transportationInput.enterValue('unicycle');
expect(clientPo.transportationInput.getValue()).toBe('unicycle');
`
#### How to append custom functions to page object elements
Custom functions can be included in the els fns property object. Custom functions are called with the ElementFinder and the options object (see makeDefaultPo), so that you can refer to them in the custom function, and the arguments that you call the function with from the protractor script.
Example
`javascript
var els = {
hobbyInput: {
locator: by.model('client.hobby'),
po: ngpo.makeInputPo,
pause: 5000,
fns: {
getClasses: function(el, options) {return el.getAttribute('class');},
clickWithPause: function(el, options) {
return el.click().then(function() {browser.sleep(options.pause);})
}}
},
funnyInput: {
locator: by.model('client.funny'),
po: ngpo.makeInputPo,
fns: {
inputAddedVals: (funnyInputEl, options, val1, val2) => {
var addedVals = val1 + val2;
return funnyInputEl.enterValue(addedVals);
}
}
},
dobInput: {
locator: by.model('client.dob'),
po: ngpo.makeDateInputPo,
// override clear() fn with poFns.clearByBs b/c Protractor Issue #562
fns: {clear: ngpo.poFns.clearByBs}},
};
// test example
expect(clientPo.hobbyInput.getClasses()).toContain('yada');
clientPo.hobbyInput.clickWithPause(); // pauses 5 seconds after click()
clientPo.funnyInput.inputAddedVals(3,4)
.then(function(){
expect(clientPo.funnyInput.getValue()).toBe('7');
});
clientPo.dobInput.enterValue('01/02/1987')
.then(() => {
expect(clientPo.dobInput.getValue()).toBe('1987-01-02');
clientPo.dobInput.clear(); // using poFns.clearByBs
expect(clientPo.dobInput.getValue()).toBe('');
});
``