准备用 nightmare 写自动化测试. 遇到了一个解决不了的问题, 多方查找无果,尝试来 node 社区咨询下: 一个待测试的页面的 window 对象挂了一个方法,方法被调用会改变页面,并返回一个对象. 需求是, 用 nightmare 调用一次这个方法,然后截一次图. 我的实现代码如下:
var Nightmare = require('nightmare'),
nightmare = Nightmare();
nightmare.goto('http://127.0.0.1/demo');
nightmare
.wait(5000)
.run(function(){
nightmare.evaluate(function(){
return window.a.playNextFrame({toggle: true, pId: null})
})
.then(function(result){
console.log(result)
nightmare.screenshot('/test.png')
.end()
})
})
但是代码运行结果是: 只输出了 result, 并没有生成截图文件 但是按照这种方式,却可以正常生成图片,并打印标题:
nightmare.goto('http://127.0.0.1/demo')
.wait(5000)
.screenshot('/test.png')
.evaluate(function(){
return document.title;
})
.end()
.then(function(title){
console.log(title);
})
请教各位,问题出在哪里? 先谢过了
你的第一段代码, nightmare.goto(‘http://127.0.0.1/demo’) 应该要链式调用吧,还有要想执行代码后截图得用 inject,像下面这样
const Nightmare = require('nightmare');
const nightmare = Nightmare();
nightmare.goto('http://127.0.0.1/demo')
.wait(5000)
.inject('js', 'play.js')
.screenshot('/test.png')
.evaluate(function () {
return globalResult;
})
.end()
.then(function (result) {
console.log(result);
});
play.js
globalResult = window.a.playNextFrame({toggle: true, pId: null})
@IchiNiNiIchi 谢谢回复. 我在官方的api 文档里面看到这段 demo:
var selector = 'h1';
nightmare
.evaluate(function (selector) {
// now we're executing inside the browser scope.
return document.querySelector(selector).innerText;
}, selector) // <-- that's how you pass parameters from Node scope to browser scope
.then(function(text) {
// ...
})
所以我觉得 evaluate 沙盘里面应该可以直接调用预先挂到全局变量上的方法. 我原来的代码的确也调用到了.
@songabc 刚刚写了个小脚本试了一下,你说的对。另外nightmare 的 end 之后一定得调用 then 才会有截图。下面用百度的首页做例子,你可以照着自己改一下
const Nightmare = require('nightmare');
var nightmare = Nightmare();
nightmare.goto('https://www.baidu.com');
nightmare.wait(5000)
.evaluate(function () {
document.getElementById('su').value = 'Boom';
return 'Boom';
})
.then(function (result) {
console.log(result);
nightmare.screenshot('fun.png').end().then();
});
另外,如果不关心 evaluate 返回的值的话,可以直接 evaluate 之后直接 screenshot
const Nightmare = require('nightmare');
var nightmare = Nightmare();
nightmare.goto('https://www.baidu.com')
.wait(5000)
.evaluate(function () {
document.getElementById('su').value = 'Boom';
return 'Boom';
})
.screenshot('fun.png')
.end()
.then();
@IchiNiNiIchi 的确是你说的那样,需要在 end() 后面添加 then() 才能截图( 不明白为什么) 然后,如果我有进一步需求,需要根据 evaluate 返回的值判断是否调用. 我的代码是这样的:
nightmare.goto('http://127.0.0.1/demo')
.wait(5000)
.evaluate(function(){
return window.test()
})
.then(function(result){
if(result){
nightmare.screenshot('/test.png')
}
})
结果是,并没有生成截图但是result 有值.
@songabc 应该是之前调用的方法都是把要执行的东西放在一个容器里面,调用了 then 之后才真正地执行。 其实你又忘了加 then 了。
nightmare
.goto('http://127.0.0.1/demo')
.wait(5000)
.evaluate(function(){
return window.test()
})
.then(function(result){
if(result){
nightmare.screenshot('/test.png').end().then(); // SHOULD BE FIXED
}
});
@songabc 这是因为每一个 nightmare 实例都有一个操作队列,而这个操作队列保存着 nightmare 的一系列操作。而 nightmare 的每一个链式调用只是将操作保存到队列里面,并没有立刻执行操作。
例如下面这段代码:
nightmare
.goto('https://github.com')
.wait(1000)
.evaluate(function(){})
.end()
如果仅仅执行这段代码,在打开浏览窗口之后不会有任何操作结果。这是因为,这段代码是将两个操作 goto 和 wait 放到了操作队列中,但是并没有执行这两个操作。而 end 的作用是在执行完队列中所有的操作之后,关闭 electron 进程即浏览窗口会被关闭(end 也是一个操作)。由于没有队列里面的操作没有执行,所以浏览窗口也会一直打开。