I am using Selenium + Mocha (in Node.js) to do some UI testing on a site. After each test, I want to capture a screen shot so that I can review/share the visible results.
However, after the basic UI changes are made (i.e. insert text and hit submit), there is an AJAX call + JavaScript animation that triggers after that I would like to be part of my screen shot.
The screenshots I'm getting appear to be in taken after the next step has already started. (So, the first test runs > trigger the screenshot > second test starts > screenshot is actually captured)
I've tried .sleep()
and timeouts -- however my use could have been wrong.
function takeScreenshot(name='out'){
driver.takeScreenshot().then(function(data){
var base64Data = data.replace(/^data:image\/png;base64,/,"")
fs.writeFile(`screenshots/${name}.png`, base64Data, 'base64', function(err) {
if(err) console.log(err);
});
});
}
describe('UI Tests', async function() {
before(async function() {
driver = await new Builder().forBrowser('chrome').build();
await driver.get('http://localhost:8000').then( async function(){ await getAssets(); });
/* search | submit | reset are declared in getAssets() */
});
after(async function() {
driver.quit();
});
afterEach(async function(){
step++;
driver.sleep(3000).then(
takeScreenshot(step)
);
});
describe('User Types/Modifies Input and Submits Query', async function() {
it('type in search + click submit', async function(){
search.sendKeys("Puppies and Kittens");
submit.click();
});
it('click the X icon to clear search', async function(){
reset.click();
});
});
});
In the above snippet, the screenshot for the first test ('type in search + click submit'
) would show the input field already cleared from the second test.
答案 0 :(得分:1)
发送到selenium的命令是异步的,这意味着函数将安排工作在将来的某个时刻运行,但会立即返回,以便代码继续运行。
在selenium-webdrivers案例中,函数返回" promise"这将在未来的某个时候解决。摩卡可以使用承诺等待结果。
Mocha使用测试的返回值来确定它是否应该等待解析的承诺。您可以使用await
或.then
控制承诺流程。
如果正在使用Promise A+代码,那么测试中您将始终拥有return someFormOfPromise
。
it(waits, function(){
return Promise.resolve(true)
.then(res => expect(res).to.be.true)
})
如果正在使用async
,则可以保证返回承诺但您必须await
任何异步或测试将继续
it(waits, async function(){
let res = await Promise.resolve(true)
expect(res).to.be.true
})
回调类似,但它们使用done
函数来指示测试继续进行。
it(waits, function(done){
someTrueCallback((err, res) => {
if (err) return done(err)
expect(res).to.be.true
done()
})
})
在发布的代码中有很多混合Promise A+和async
,甚至还有一个回调。选择一种方式并尽可能坚持下去,我&# 39; ll使用async
/ await
。
任何异步回调都可以转换为promises,因此从fs.writeFile
回调函数开始,将其转换为promise:
function writeFile(path, data, format){
return new Promise((resolve, reject)=>{
fs.writeFile(path, data, format, function(err){
if (err) return reject(err)
resolve(true)
})
})
}
幸运的是,这是非常标准的,Node.js在util.promisify
中有一个帮助,所以帮助者可以成为:
const writeFile = util.promisify(fs.writeFile)
function async takeScreenshot(name='out'){
let data = await driver.takeScreenshot()
var base64Data = data.replace(/^data:image\/png;base64,/,"")
return await writeFile(`screenshots/${name}.png`, base64Data, 'base64')
}
当await
可用时,无需使用.then
。
每当调用返回promise的函数时,如果要使用已解析的值,则可能需要await
或let res = await...
。
describe('UI Tests', function() {
before(async function() {
driver = await new Builder().forBrowser('chrome').build();
await driver.get('http://localhost:8000')
await getAssets()
/* search | submit | reset are declared in getAssets() */
});
after(async function() {
await driver.quit();
});
afterEach(async function(){
step++;
await takeScreenshot(step)
});
describe('User Types/Modifies Input and Submits Query', function() {
it('type in search + click submit', async function(){
await search.sendKeys("Puppies and Kittens");
await submit.click();
});
it('click the X icon to clear search', async function(){
await reset.click();
});
});
});