自动化测试工具小记:node + SpookyJS + CasperJS + PhantomJS

概述

这是一个跨度很广的小记哦,使用node作为脚本,涵盖了三个工具:PhantomJS、CasperJS、SpookyJS。目前网上相关的资料比较少,请关注乱炖,我会断断续续更新。

那这三个工具有什么用呢,网上比较专业的说法是:“前端自动化测试工具”,通俗点来说就是一个“没有UI界面的终端浏览器”;如果完整的来看,他应该是NSCP(我个人写的简称,即:node + SpookyJS + CasperJS + PhantomJS)

注意哦,NSCP和传统的CURL不一样的地方在于:

  • CURL是发起一个URL请求,单项的;而NSCP则是一个真正的网页请求,请求整个网页及网页包含的所有资源
  • 效率来说,CURL远远比NSCP要快的多
  • CURL更适合爬数据,NSCP更多是对于“无界的浏览网页”

那这个工具有什么用呢?举几个简单例子:

  • 网页快照(截图)
  • 前端自动化测试
  • 其他…

PhantomJS

OK,说了这么多,那怎么了解NSCP呢?在分享之前必须先了解PhantomJS。CasperJS和SpookyJS都是在PhantomJS基础上拓展的工具。PhantomJS是一个无界的终端浏览器,他能够访问并测试指定网页。

安装方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Mac brew 安装
brew install phantomjs
 
# Npm 安装
npm install phantomjs
 
# CentOS 编译安装
sudo yum install gcc gcc -c++ make git openssl-devel freetype-devel fontconfig-devel
git clone git: //github .com /ariya/phantomjs .git
 
cd phantomjs
git checkout 1.9
 
. /build .sh

简单的例子

将下面保存为simple.js文件

1
2
3
4
5
6
7
8
9
console.log( 'Loading a web page' );
 
var page = require( 'webpage' ).create();
var url = 'http://levi.cg.am/' ;
 
page.open(url, function (status) {
     // Page is loaded!
     phantom.exit();
});

终端执行命令

1
phantomjs simple.js

更多示例见:http://phantomjs.org/examples/

有人说PhantomJS是node,这样理解不是很正确,PhantomJS是一个运行JS调用API接口的工具,允许通过npm方式下载安装并以模块方式存在node中。但是PhantomJS中是不支持node方法的哦,具体差异见官方文档!

同类的软件

挺多的,这里我只列举一个SlimerJS。SlimerJS与PhantomJS不同之处在于,PhantomJS是基于webkit内核的,而SlimerJS是基于Gecko(firefox),SlimerJS和PhantomJS语法很接近,不重复说明,具体见官网

http://www.slimerjs.org/index.html

在PHP中使用PhantomJS

方法一:通过exec

1
2
<?php
exec ( 'phantomjs simple.js' );

方法二:PHP PhantomJS

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
require '../vendor/autoload.php' ;
use JonnyW\PhantomJs\Client;
 
$client = Client::getInstance();
$request  = $client ->getMessageFactory()->createRequest();
$response = $client ->getMessageFactory()->createResponse();
 
$request ->setMethod( 'GET' );
$request ->setUrl( 'http://google.com' );
 
$client ->send( $request , $response );
var_dump( $response );

安装方法及使用见官方git:
https://github.com/jonnnnyw/php-phantomjs

CasperJS

通过上面提供的PhantomJS示例并了解后,你可能会发现一些问题,比如你要请求一系列网址,并且在一个请求之后,执行另一个请求。使用PhantomJS可能会像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var page = require( 'webpage' ).create();             //新建一个页面
page.open(url1, function (status) {                  //导航到第一个URL
     if (status == "fail" ) phantom.exit();           //如果发生错误,退出程序
     page.open(url2, function (status) {              //否则在页面加载完成的回调函数中继续导航到第二个URL,依次类推
         if (status == "fail" ) phantom.exit();
         page.open(url3, function (status) {
             if (status == "fail" ) phantom.exit();
             page.open(url4, function (status) {
                 if (status == "fail" ) phantom.exit();
                 // 我可以停下来了吗?
             });
         });
     });
});

是不是很恐怖,而CasperJS的目的就在于更方便的操作PhantomJS。CasperJS是一个开源的,用JavaScript编写的,基于PhantomJS的导航脚本和测试工具,它简化了定义一个完成的导航操作所需的步骤,还提供了很有用的函数封装、方法、和语法糖、它可以完成下面这些常见任务:

  • 定义 & 排序浏览器导航步骤
  • 填充 & 提交表单
  • 点击 & 跟踪链接
  • 捕获网页截图 (还可以截取某一区域)
  • 在远程DOM上进行断言测试
  • 记录事件
  • 下载资源,包括二进制文件
  • 编写功能测试套件,结果保存为JUnit XML文件
  • 抓取网页内容

CasperJS使用更方便的API解决了这种异步操作的问题:

1
2
3
4
5
6
7
8
var casper = require( 'casper' ).create();           //新建一个页面
 
casper.start(url1);                                //添加第一个URL
casper.thenOpen(url2);                             //添加第二个URL,依次类推
casper.thenOpen(url3);
casper.thenOpen(url4);
 
casper.run();                                      //开始导航

终端执行文件

1
casperjs simple.js

更多示例见官方文档:

http://casperjs.readthedocs.org/en/latest/index.html

注意哦:CasperJS使用的是casper的方法,PhantonJS使用的是phantom的方法;他们有各自的使用方法,不可以用混淆执行

安装方法

目前我只在本地开发环境安装,安装方法如下:

1
brew install casperjs --devel

注意哦:目前PhantomJS的版本是1.9.2,正式版是不支持的,请安装开发版

SpookyJS

通过上面描述,应该了解到:

  • PhantomJS,一个无界的终端浏览器
  • CasperJS,一个改善PhantomJS操作的工具

而SpookyJS有什么用途呢?前面说了PhantonJS和CasperJS是可以作为模块进行npm安装在node中,但是执行的方法却是通过各自的bin文件,诸如:

1
2
phantomjs simple.js
casperjs simple.js

而SpookyJS则是一个驱动器,在node下能够正常使用PhantonJS和CasperJS,这就是我定义的NSCP (node + SpookyJS + CasperJS + PhantomJS)。你可以简单将其理解为:

  • node:脚本语言
  • Spooky:驱动器
  • CasperJS:工具
  • PhantomJS:无界浏览器

安装方法

既然SpookyJS作为node的驱动器,那么也需要通过node进行安装:

1
npm install spooky

SpookyJS需要依赖的环境

  • Node.js >= 0.8
  • PhantomJS >= 1.9
  • CasperJS >= 1.0

简单示例

保存为hello.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
try {
     var Spooky = require( 'spooky' );
} catch (e) {
     var Spooky = require( '../lib/spooky' );
}
 
var spooky = new Spooky({
         child: {
             transport: 'http'
         },
         casper: {
             logLevel: 'debug' ,
             verbose: true
         }
     }, function (err) {
         if (err) {
             e = new Error( 'Failed to initialize SpookyJS' );
             e.details = err;
             throw e;
         }
 
         spooky.start(
             'http://en.wikipedia.org/wiki/Spooky_the_Tuff_Little_Ghost' );
         spooky.then( function () {
             this .emit( 'hello' , 'Hello, from ' + this .evaluate( function () {
                 return document.title;
             }));
         });
         spooky.run();
     });
 
spooky.on( 'error' , function (e, stack) {
     console.error(e);
 
     if (stack) {
         console.log(stack);
     }
});
 
/*
// Uncomment this block to see all of the things Casper has to say.
// There are a lot.
// He has opinions.
spooky.on('console', function (line) {
     console.log(line);
});
*/
 
spooky.on( 'hello' , function (greeting) {
     console.log(greeting);
});
 
spooky.on( 'log' , function (log) {
     if (log.space === 'remote' ) {
         console.log(log.message.replace(/ \- .*/, '' ));
     }
});

通过node执行脚本

1
node hello.js

更多内容请见官方git:

https://github.com/WaterfallEngineering/SpookyJS

需要注意的几个地方

通过SpookyJS配置PhantomJS和CasperJS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var spooky = new Spooky({
     child: {
         transport: 'http'
     },
     casper: {
         logLevel: 'debug' ,
         verbose: true ,
         viewportSize: {
             width: 1440, height: 768
         },
         pageSettings: {
             outputEncoding: 'gbk'
         }
     }
}, function (err) {});

phantom和casper不同的方法调用

1
2
3
4
5
6
7
8
9
10
11
12
spooky.start( 'http://example.com/the-page.html' );
 
spooky.then( function () {
     // 这里是CasperJS的方法
});
 
spooky.thenEvaluate( function () {
     // 这里是PhantomJS的方法
})
 
// this function (and the three spooky calls above) runs in Spooky's environment
spooky.run();

变量作用域

SpookyJS的作用域和js不一样哦,具体看下面几个来自官方的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var x = 'spooky' ;
spooky.start( 'http://example.com/the-page.html' );
 
spooky.then( function () {
     var y = 'casper' ;
     console.log( 'x:' , x); // -> x: undefined
});
 
spooky.thenEvaluate( function () {
     console.log( 'x:' , x); // -> x: undefined
     console.log( 'y:' , y); // -> y: undefined
});
 
spooky.run();

而PhantomJS的方法中可以通过传递一个对象过去

1
2
3
4
5
6
7
8
var x = 'spooky' ;
 
// spooky.thenEvaluate accepts an options argument (just like Casper)
spooky.thenEvaluate( function (x) {
     console.log( 'x:' , x); // -> x: spooky
}, {
     x: x
});

而CasperJS的方法中需要将变量作为数组对象,以参数传过去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var x = 'spooky' ;
var y = 'kooky' ;
 
// spooky.then accepts a function tuple
spooky.then([{
     x: x
}, function () {
     console.log( 'x:' , x); // -> x: spooky
}]);
 
// spooky.thenEvaluate accepts both a function tuple and an argument hash
spooky.thenEvaluate([{
     y: y
}, function (x) {
     console.log( 'x:' , x); // -> x: spooky
     console.log( 'y:' , y); // -> y: kooky
}], {
     x: x
});

全局和局部变量

1
2
3
4
5
6
7
8
9
10
var x = 'spooky' ;
 
spooky.then([{
     x: x
}, function () {
     x = 'casper' ;
     console.log( 'x:' , x); // -> x: casper
}]);
 
console.log( 'x:' , x); // -> x: spooky

一个混合的使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spooky.start( 'http://example.com/the-page.html' );
 
var x = 'spooky' ;
spooky.then([{
     x: x
}, function () {
     var y = 'casper' ;
     var z = this .evaluate( function (x, y) {
         console.log( 'x:' , x); // -> x: spooky
         console.log( 'y:' , y); // -> y: casper
 
         return [x, y, 'and the-page.html' ].join( ', ' );
     }, {
         x: x,
         y: y
     });
 
     console.log( 'z:' , z); // -> z: spooky, casper, and the-page.html
}]);
 
spooky.run();

那两个不同的方法之间,如何传递变量呢?来一个非官方的例子,同样来自github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
spooky.then( function () {
     window.pageCount = 0;
});
 
spooky.waitFor( function () {
     var isLastPage = ! this .exists( '#next' );
 
     if (!isLastPage) {
         window.pageCount++;
         this .click( '#next' );
     }
 
     return isLastPage;
});
 
spooky.then( function () {
     this .emit( 'console' , 'Page count: ' + window.pageCount);
});

是不是有点不太好理解,如果你了解PHP的话,可以将其当作PHP闭包中的ues去看待。如果仍旧不懂,你可以给我留言哦

不允许使用中文

这个真的是官方、非官方都没有说明的,无论你是不是utf-8,在SpookyJS构造方法中都不允许使用中文

1
2
3
4
5
6
7
8
9
10
11
12
var spooky = new Spooky({
     // 此处省略...
}, function () {
     spooky.then( function () {
         // 这样是不可以的哦
         var name = '中文' ;
     }
});
 
spooky.on( 'test' , function (log) {
     console.log( '但是这里是可以用中文的哦!' );
});

好在JS中有一个原生的方法 decodeURIComponent,可以这样

1
2
3
4
5
6
7
8
9
10
11
12
13
var spooky = new Spooky({
     // 此处省略...
}, function () {
     spooky.then( function () {
         var name = this .evaluate( function () {
             return window.decodeURIComponent( '%E4%B8%AD%E6%96%87' );
         });
     }
});
 
spooky.on( 'test' , function (log) {
     console.log( '但是这里是可以用中文的哦!' );
});

当然也可以使用base64,目前还没测。原因,我找了很多资料,唯一有个相关的说法是CasperJS不支持大于8b的字符

转载自:http://levi.cg.am/archives/3648

你可能感兴趣的:(+,+,+,phantomjs,casperjs,SpookyJS,自动化测试工具小记:node)