本章內容翻譯自http://nightwatchjs.org/guide#page-objects。javascript
Page Objects方法是一種流行的模式,經過將web應用程序的頁面或頁面片斷包裝爲對象來編寫端到端測試。頁面對象的目的,是經過抽象出html的行爲,讓軟件客戶端能夠像人同樣的看見而且操做界面。關於Page Object,你能夠在這裏找到更詳細的介紹。css
html
從0.7版本開始,Nightwatch爲建立頁面對象提供了加強的、更強大的接口,與之前的支持相比有了顯著的改進。0.7以前建立的頁面對象仍將繼續工做,不過咱們建議升級到新版本。要使用新版本,Page Object必須包含 `elements` 或 `sections` 屬性。不然,會按照舊版作處理。
簡單地建立一個頁面對象,只須要用描述頁面的屬性建立一個對象就能夠了。每個頁面對象都應該屬於不一樣的文件, Nightwatch將讀取配置文件中page_objects
屬性定義的目錄。java
page_objects
也能夠是一個文件夾數組,讓你能夠根據業務邏輯將頁面對象分紅不一樣的組。web
你能夠添加一個 url
屬性來指定頁面的url。你能夠調用 navigate()
方法來跳轉到對應的界面。api
URL
一般是個字符串:數組
module.exports = {
url: 'http://google.com',
elements: {}
};
他也能夠是一個函數, 用來生成動態的連接。好比你想要支持不一樣的測試環境的時候這就頗有用。你能夠建立一個函數,他在頁面的上下文中被調用:app
module.exports = {
url: function() {
return this.api.launchUrl + '/login';
},
elements: {}
};
### 定義元素(elements)ide
多數狀況下你都會在你的頁面上定義元素,你的測試將會經過命令或者斷言來與他交互。使用elements
屬性可讓你的元素都定義在同一個地方。函數
Page Object 內部會自動等切換css和xpath,因此你不用在測試中手動調用 useXpath
或者 useCss
。默認的 locateStrategy
是css,但你仍能夠指定xpath:
module.exports = {
elements: {
searchBar: {
selector: 'input[type=text]'
},
submit: {
selector: '//[@name="q"]',
locateStrategy: 'xpath'
}
}
};
若是你的elements都是使用同一種默認選擇器策略的話,你可使用這種簡寫形式:
module.exports = {
elements: {
searchBar: 'input[type=text]'
}
};
我的提示:上面的簡寫,我本人在項目中試過了,不起做用,並且報的錯誤也莫名其妙。若是你在使用中發現錯誤,不要使用簡寫形式試試
在調用元素命令或者斷言的時候,elements
屬性可讓你使用 @
做爲前綴來引用定義的元素。
你也能夠定義一個元素對象的數組:
var sharedElements = {
mailLink: 'a[href*="mail.google.com"]'
};
module.exports = {
elements: [
sharedElements,
{ searchBar: 'input[type=text]' }
]
};
看一個包含 url
和 elements
屬性的例子:
module.exports = {
url: 'http://google.com',
elements: {
searchBar: {
selector: 'input[type=text]'
},
submit: {
selector: '//[@name="q"]',
locateStrategy: 'xpath'
}
}
};
測試文件能夠這麼寫:
module.exports = {
'Test': function (client) {
var google = client.page.google();
google.navigate()
.assert.title('Google')
.assert.visible('@searchBar')
.setValue('@searchBar', 'nightwatch')
.click('@submit');
client.end();
}
};
有時候將頁面劃分爲幾部分(Section)
也很是有用。Section有兩個好處:
Section
中的 elements
對應爲它在的DOM中的子元素使用 sections
屬性來定義:
module.exports = {
sections: {
menu: {
selector: '#gb',
elements: {
mail: {
selector: 'a[href="mail"]'
},
images: {
selector: 'a[href="imghp"]'
}
}
}
}
};
測試文件這麼寫:
module.exports = {
'Test': function (client) {
var google = client.page.google();
google.expect.section('@menu').to.be.visible;
var menuSection = google.section.menu;
menuSection.expect.element('@mail').to.be.visible;
menuSection.expect.element('@images').to.be.visible;
menuSection.click('@mail');
client.end();
}
};
注意:section上每個命令(command)和斷言(assertion,不是expect assertions)都返回其自身——鏈式返回。若是須要的話,你能夠爲複雜的DOM結構編寫嵌套的section。
一個嵌套section的例子:
module.exports = {
sections: {
menu: {
selector: '#gb',
elements: {
mail: {
selector: 'a[href="mail"]'
},
images: {
selector: 'a[href="imghp"]'
}
},
sections: {
apps: {
selector: 'div.gb_pc',
elements: {
myAccount: {
selector: '#gb192'
},
googlePlus: {
selector: '#gb119'
}
}
}
}
}
}
};
在測試文件中使用嵌套section:
module.exports = {
'Test': function (client) {
var google = client.page.google();
google.expect.section('@menu').to.be.visible;
var menuSection = google.section.menu;
var appSection = menuSection.section.apps;
menuSection.click('@appSection');
appSection.expect.element('@myAccount').to.be.visible;
appSection.expect.element('@googlePlus').to.be.visible;
client.end();
}
};
你能夠在page object
中使用 command
屬性來添加命令。這是一個封裝頁面業務邏輯的一個有用的方式。
Nightwatch 將會調用頁面上下文或者section的命令。客戶端的命令(好比 pause
)你可使用 this.api
來訪問。爲了鏈式調用,每一個命令函數都應該返回page對象或者section
在下面的案例中,這個命令用來封裝點擊提交按鈕的邏輯:
var googleCommands = {
submit: function() {
this.api.pause(1000);
return this.waitForElementVisible('@submitButton', 1000)
.click('@submitButton')
.waitForElementNotPresent('@submitButton');
}
};
module.exports = {
commands: [googleCommands],
elements: {
searchBar: {
selector: 'input[type=text]'
},
submitButton: {
selector: 'button[name=btnG]'
}
}
};
測試文件就簡單多了:
module.exports = {
'Test': function (client) {
var google = client.page.google();
google.setValue('@searchBar', 'nightwatch')
.submit();
client.end();
}
};