编写测试
官方推荐首选使用CSS选择器模型来定位页面上的元素,Nightwatch会让编写E2E自动化测试非常容易。
在项目中为测试文件创建一个单独的文件夹。例如:tests文件夹,这样它里面的每一个文件都会加载执行,一个基本的测试是这样的:
module.exports = {
'Demo test Google' : function (browser) {
browser
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('#main', 'Night Watch')
.end();
}
};
当你想要关闭的测试时,请记住调用.end()方法,这样可以Selenium会话正确地关闭。
如果你想让一个测试文件中包含多个测试步骤,你可以这样写:
module.exports = {
'step one' : function (browser) {
browser
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('button[name=btnG]', 1000)
},
'step two' : function (browser) {
browser
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('#main', 'Night Watch')
.end();
}
};
也可以使用这种格式写:
this.demoTestGoogle = function (browser) {
browser
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('#main', 'The Night Watch')
.end();
};
使用Xpath选择器
Nightwatch同样支持xpath选择器。如果想把定位策略从css选择器切换到xpath选择器,你需要调用useXpath()方法,切换回CSS调用useCss()方法。如果你想把xpath作为默认,可以在test settings(通常是nightwatch.conf.js文件)中设置"use_xpath": true。
this.demoTestGoogle = function (browser) {
browser
.useXpath() // every selector now must be xpath
.click("//tr[@data-recordid]/span[text()='Search Text']")
.useCss() // we're back to CSS now
.setValue('input[type=text]', 'nightwatch')
};
BDD 期望断言
Nightwatch在v0.7版本之后引入了新的BDD方式的断言库(什么是BDD可以查百科这里不多介绍),它极大地提高了断言的灵活性和可读性。
expect断言是使用Chai框架中的Expect一个子集,请看这里的例子:
module.exports = {
'Demo test Google' : function (client) {
client
.url('http://google.no')
.pause(1000);
// expect element to be present in 1000ms
client.expect.element('body').to.be.present.before(1000);
// expect element <#lst-ib> to have css property 'display'
client.expect.element('#lst-ib').to.have.css('display');
// expect element to have attribute 'class' which contains text 'vasq'
client.expect.element('body').to.have.attribute('class').which.contains('vasq');
// expect element <#lst-ib> to be an input tag
client.expect.element('#lst-ib').to.be.an('input');
// expect element <#lst-ib> to be visible
client.expect.element('#lst-ib').to.be.visible;
client.end();
}
};
expect接口提供一个更加灵活和流畅的语言,在现有的assert接口上有了显著的改进。惟一的缺点是不能再对断言进行链锁了,此时还不支持自定义消息。
对于expect断言的完整列表,请参考API docs。
使用before[Each] and after[Each]
Nightwatch提供了标准的before / after 和 beforeEach / afterEach 钩子在测试代码中使用。
before 和 after 会在test suit的开始之前和结束之后运行。
beforeEach 和 afterEach 会在每个testcase(test step)开始之前和结束之后运行。
例子:
module.exports = {
before : function(browser) {
console.log('Setting up...');
},
after : function(browser) {
console.log('Closing down...');
},
beforeEach : function(browser) {
},
afterEach : function() {
},
'step one' : function (browser) {
browser
// ...
},
'step two' : function (browser) {
browser
// ...
.end();
}
};
在上面的例子中方法调用的顺序如下:before(), beforeEach(), "step one", afterEach(), beforeEach(), "step two", afterEach(), after()
对于向后兼容的原因,afterEach钩子只能在它的异步形式中接收brower对象——afterEach(brower, done){..}
异步before[Each] and after[Each]
所有的before[Each]和after[Each]方法都可以执行异步操作,在这种情况下,他们将作为第二参数传递的回调。
在异步操作完成时,在最后一步必须调用done方法,不调用它将会导致超时错误。
beforeEach & afterEach 例子:
module.exports = {
beforeEach: function(browser, done) {
// performing an async operation
setTimeout(function() {
// finished async duties
done();
}, 100);
},
afterEach: function(browser, done) {
// performing an async operation
setTimeout(function() {
// finished async duties
done();
}, 200);
}
};
done来控制调用超时
默认情况下,完成的调用超时设置为10秒(单元测试2秒)。在某些情况下,这可能是不够的,为了避免了超时错误,你可以通过在外部全局文件中定义一个asyncHookTimeout属性(以毫秒为单位)来控制超时时间 (请参阅下面的外部全局变量的详细信息)。
例如,请参考所提供的globalsModule一个样例示例。
明确失败的测试
简单的调用done的Error参数可以让一个test hook有意去失败。例如:
module.exports = {
afterEach: function(browser, done) {
// performing an async operation
performAsync(function(err) {
if (err) {
done(err);
}
// ...
});
}
};
外部全局变量
大多数情况下,在外部文件中定义全局变量更有用,在globals_path属性中指定,而不是在nightwatch.json中定义。
你可以根据需要覆盖每个环境的全局变量,假设你的测试在本地运行,并且在远程服务器上运行。大多数时候,你需要一些不同的设置。
全局Hooks
在每组测试套件的全局范围内和范围之外可以使用同一套hooks。更多细节,请参见下面的示例。在全局钩子的情况下,beforeEach和afterEach 引用了一个测试套件(即测试文件),在测试套件之前和之后运行。
全局设置
有许多全局变量在进行测试设置,并且可以控制测试执行。在globalsModule样本中有详细信息。例如:
module.exports = {
'default' : {
isLocal : true,
},
'integration' : {
isLocal : false
},
// External before hook is ran at the beginning of the tests run, before creating the Selenium session
before: function(done) {
// run this only for the local-env
if (this.isLocal) {
// start the local server
App.startServer(function() {
// server listening
done();
});
} else {
done();
}
},
// External after hook is ran at the very end of the tests run, after closing the Selenium session
after: function(done) {
// run this only for the local-env
if (this.isLocal) {
// start the local server
App.stopServer(function() {
// shutting down
done();
});
} else {
done();
}
},
// This will be run before each test suite is started
beforeEach: function(browser, done) {
// getting the session info
browser.status(function(result) {
console.log(result.value);
done();
});
},
// This will be run after each test suite is finished
afterEach: function(browser, done) {
console.log(browser.currentTest);
done();
}
};