-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Page Object API
Nightwatch v0.9.9
Page objects provide an additional layer of abstraction for test case creation. Page objects are defined in modules and parsed into factory functions that create page object instances. These factories are accessible through the page
reference within the command API (accessible through the "client" or "browser" object) using the name of the module that defines them.
var myPageObject = browser.page.MyPage(); // defined in MyPage.js module
For more information on general page object creation and usage, see: http://nightwatchjs.org/guide#page-objects
There are two flavors of page objects: enhanced and legacy. The current and recommended approach is through the enhanced model (available since Nightwatch 0.7). The legacy model continues to work, but can be considered deprecated and should be avoided when possible.
Unlike legacy page objects which are mostly simple abstractions of functionality, enhanced page objects benefit from being able to use a subset of the Nightwatch commands API. These commands supports element selectors which are named references to selectors defined within the page object module. Additionally, sections can be used to further divide page objects into smaller, dedicated parts.
Enhanced page object modules are identified through object exports having one or both of either the elements
and sections
properties. While legacy page objects modules can export a function or an object, enhanced page objects must export an object.
Name | Type | Description |
---|---|---|
commands |
Array | [Optional] A list of objects containing functions to represent methods added to the page object instance. Also see Enhanced Page Object Commands. |
elements |
Object|Array | [Required if not using sections ] An object, or array of objects, of named element definitions (see Enhanced Module Element Members) to be used as element selectors within element commands called from the page object. |
props |
Object|Function | [Optional] An object or a function returning an object representing a container for user variables. Props objects are copied directly into the props property of the page object instance. Values stored within the props object don't have to worry about possible collisions with command functions. |
sections |
Object | [Required if not using elements ] An object of named sections definitions (see Enhanced Module Section Members) defining the sections within the page object. |
url |
string|Function | [Optional] A url or function returning a url to be used in a url() command when the page's navigate() method is called. |
Element definitions are in the elements
object of the module root object. Keys in the user-defined properties in the elements
object represent the name of the Element object and its value the definition.
elements: {
<element-name>: <element-definition>
}
Name | Type | Description |
---|---|---|
locateStrategy |
string | [Optional] The locate strategy to be used with selector when finding the element within the DOM. This can be any of the following: 'class name', 'css selector', 'id', 'name', 'link text', 'partial link text', 'tag name', 'xpath'. The default is 'css selector'. |
selector |
string | [Required] The selector string used to find the element in the DOM. For elements, this string can be assigned directly to the element property as <element-definition> as shorthand for an element definition object only containing a selector value. |
Section definitions are in the sections
objects of the root module object and other sections (they can be nested). Keys in the user-defined properties in the sections
object represent the name of the Section object and its value the definition.
sections: {
<section-name>: <section-definition>
}
Name | Type | Description |
---|---|---|
commands |
Array | [Optional] Same as module root. |
elements |
Object|Array | [Optional] Same as module root. |
locateStrategy |
string | [Optional] Same as Element. |
props |
Object|Function | [Optional] Same as module root. |
sections |
Object | [Optional] Same as module root. |
selector |
string | [Required] Same as Element. |
// enhanced page object
module.exports = {
// can be string or function
url: function () {
return this.api.launchUrl;
},
elements: {
// shorthand, specifies selector
mySubmitButton: 'input[type=submit]'
// full
myTextInput: {
selector: 'input[type=text]',
locateStrategy: 'css selector'
}
},
commands: [
{
myCustomPause: function () {
this.api.pause(this.props.myPauseTime);
}
}
],
// object version (best considered immutable)
props: {
myPauseTime: 1000
},
sections: {
myFooterSection: {
selector: '#my-footer',
locateStrategy: 'css selector',
elements: {
myLogo: {
selector: '.my-logo',
locateStrategy: 'css selector'
}
},
commands: [
{
myMoveToLogo: function () {
this.moveToElement('@myLogo', this.props.myLogoX, this.props.myLogoY);
}
}
],
// function version (recommended)
props: function () {
return {
myLogoX: 10,
myLogoY: 10
};
},
sections: {
// additional, nested sections
}
}
}
};
Page object module definitions are used to define page object instances when their respective factory functions within the page
reference of the standard command API is called.
var myPageObject = browser.page.MyPage(); // defined in MyPage.js module
Every time a factory function like MyPage
above is called, a new instance of the page object is instantiated.
Name | Type | Description |
---|---|---|
api |
Object | A reference providing access to the full Nightwatch command API, usually known as "client" or "browser" in test cases. This is used to access those commands that are not part of the subset of commands within the page object API. |
client |
Object | [Internal] A reference to the Nightwatch instance (not to be confused with the "client" or "browser" object which contains the command API). |
commandLoader |
Function | [Internal] Used during page object construction to add commands to the page object API. |
elements |
Object | A map of Element objects (see Enhanced Element Instances) used by element selectors. |
name |
string | The name of the page object as defined by its module name (not including the extension). This is the same name used to access the page object factory from the page reference in the command API. |
props |
Object | A reference to props object assigned from the module definition. Note: this will be the same props object for all instances of the page object if defined as an object instance within the page object module. If you wish for each props object to be unique, define props in the module as a function that would return a new props object for each new page object instance. |
section |
Object | A map of Sections objects (see Enhanced Section Instances) defined for the page object. This will only contain sections within the page object module's root sections definition. Nested sections are accessible through their parent section's own section reference. |
url |
string|Function | The url value from the page object module, either a string or a function depending on how it was defined there. |
Navigates to the resolved url defined for the page object using the command API's url()
command. This command is generally used in place of the command API's url()
when working with page objects because the url
member of the page object is the user-defined url string or function and not the call used to navigate to a url.
Parameters:
Name | Type | Description |
---|---|---|
(none) | - | - |
[Internal] Navigates to the resolved url defined for the page object using the command api's url()
command.
Parameters:
Name | Type | Description |
---|---|---|
url |
string|Function | The url value to resolve into a url string. If this value is a string, it is returned. If a function, it is called and its value returned. Otherwise null is returned. |
A subset of commands from the standard Nightwatch command API is inherited by page objects. The general rule for identifying which of the native commands are available to Page instances is: Does the command accept a selector for the first argument? If it does, it should also be a page object command as well. Currently, this list includes (what are known as "Element commands"):
- clearValue
- click
- getAttribute
- getCssProperty
- getElementSize
- getLocation
- getLocationInView
- getTagName
- getText
- getValue
- isVisible
- moveToElement
- sendKeys
- setValue
- submitForm
- waitForElementNotPresent
- waitForElementNotVisible
- waitForElementPresent
- waitForElementVisible
As element commands - commands that find and operate on elements - they're added to the page object command api to allow support for element selectors (using @
). Other native commands that would not make use of element selectors would have to be called through the page object's api
reference.
Element instances encapsulate the definition used to handle element selectors. Generally you won't need to access them directly, instead referring to them using their @
-prefixed names for selector arguments, but they are available through a page object or section's elements
property.
Name | Type | Description |
---|---|---|
name |
string | The name of the element as defined by its key in the parent section or the page object's elements definition. This is the same name used with the @ prefix in selector arguments for page object commands that refer to the element. |
locateStrategy |
string | The locate strategy to be used with selector when finding the element within the DOM. |
parent |
Object | A reference to the parent object instance. This is the parent section or the page object that contained the definition for this object. |
selector |
string | The selector string used to find the element in the DOM. |
Page object section instances are accessed from the section
property of a page object instance (note that this is the singular version of "section" whereas the plural version, "sections", was used in the module definition). Sections are created automatically through the page object factory and are available directly as properties from the section
reference.
var myPageObject = browser.page.MyPage();
var mySection = myPageObject.section.MySection; // from a `sections: {}` block in page object
Name | Type | Description |
---|---|---|
api |
Object | Same as Page instances. |
client |
Object | [Internal] Same as Page instances. |
commandLoader |
Function | [Internal] Same as Page instances. |
elements |
Object | Same as Page instances. |
locateStrategy |
string | Same as Element instances. |
name |
string | The name of the section as defined by its key in the parent section or the page object's sections definition. This is the same name used to access the section instance from the section reference from the parent page object or section. |
props |
Object | Same as Page instances. |
section |
Object | Same as Page instances. |
selector |
string | Same as Element instances. |
parent |
Object | Same as Element instances. |
Page object commands are implemented differently from your standard, custom Nightwatch commands. Key differences include:
-
Access: Page object commands are defined within page object modules. They can be in the module root object within the
commands
list or within section definitions (also in acommands
), but only exist for the definition they're within. Page object commands in the module root commands are not available in child sections and section commands are not available in parent sections or the root page object. Custom Nightwatch commands are available in the standard Nightwatch command API (the "client" or "browser" object), every page object, and every page object section. -
Context: Page object command context (the value of
this
) is the page object (for sections its the section object). The page object command API is limited to the page object API (see Enhanced Page Object Instances). To access other commands, you must do so throughthis.api
, though those methods do not have access to the page object's element selectors (using@
) as they are called outside the context of the page object. - Execution: Page object commands are not called from within the command queue. Code in a page object command is executed immediately when the function is called. Custom Nightwatch command code is run when the command is executed in the command queue (while the test is running). Page object commands can be considered "methods" more than "commands".
-
Chaining: Page object commands must return a value for chaining. This can be whatever you want, but it's recommended you stick to
this
to allow your commands to be chained in the context of the page object instance. Custom Nightwatch commands inherently always return the current command context (you don't need to explicitly return anything yourself).- Nightwatch commands called from the standard command API returns the "browser" or "client" api object
- Nightwatch commands called from a page object returns the page object
- Nightwatch commands called from a page object section returns the section
Legacy page objects are far simpler than enhanced page objects. Legacy page objects simply act as an abstraction of functionality kept separate from other commands. They inherit no other Nightwatch commands, not even custom commands. They are limited to the definition you provide for them.
Legacy page object modules are defined either as an object or a function. Object definitions represent the object returned by the page object factory from the page
object (each factory call returning the same object). Function definitions are called in the context of a constructor (the function itself not being the constructor) used to create the object returned by the page object factory.
Legacy object page objects are simple objects. What you define is what you get.
// legacy page object as an object in MyLegacyPage.js
module.exports = {
// can contain anything you want;
// this is the object you get back when
// calling the page object factory function
myPauseMethod: function (browser) {
// browser (or client) is only available if
// you explicitly pass it in when calling
browser.pause(1000);
return this; // return for chaining
}
};
// test using legacy page object
module.exports = {
'legacy page object': function (browser) {
var myPageObject = browser.page.MyLegacyPage();
myPageObject.myPauseMethod(browser); // pauses for 1000 ms
}
};
Using functions with legacy page objects is a little more useful in that a) you get a new instance for each factory call and b) the function defined is called during page object construction with a reference to the "client" or "browser" command API object (allowing you to define methods that have an inherent reference to Nightwatch commands) along with anything else you pass into the factory call.
// legacy page object as a function in MyLegacyPage.js
// browser is automatic, anything following is from factory call
module.exports = function (browser, logoSelector) {
var myLogoX = 10;
var myLogoY = 10;
this.myMoveToLogo = function () {
browser.moveToElement(logoSelector, myLogoX, myLogoY);
}
// `this` is the context of a new object
// representing what is returned from the factory
// unless you explicitly return something else
};
// test using legacy page object from function
module.exports = {
'legacy page function': function (browser) {
var myPageObject = browser.page.MyPageLegacy('.my-logo');
myPageObject.myMoveToLogo();
browser.mouseButtonClick(1); // clicks '.my-logo'
}
};