Use phantomjs + casperjs to implement automated browser testing

Source: Internet
Author: User
Tags require

Browser testing is different from unit testing of js code. The latter is generally the logic testing of code functions before release, and there are already many mature solutions in this regard,

Advantages of automated testing:

Reduce repetitive work. Let the machine automatically help us complete the required interactive operations and verify our page functions.
Automatic monitoring. By automatically returning to our page function, you can provide an alarm when the function fails and provide a reference for manual troubleshooting.

    
Phantomjs can be understood as an unbounded browser, which can drive the browsing behavior of its page through pipeline code, while the latter is some encapsulation of the former in the ease of use API.

Here we will demonstrate how to use casperjs to capture Baidu homepage

For the installation of these two things, it is very easy to read the official documentation. I will not repeat them here.

First create a js file baidu. js:

Var casper = require ('Casper '). create ();
Casper. start ();
Casper. thenOpen ('http: // www.baidu.com/', function (){
Casper.captureSelector('baidu.png ', 'html ');
});
Casper. run ();

The above code mainly involves three things:

Create a casperjs instance require ('Casper '). create (), which can be understood as a browser process

Open a page, such as casper. thenOpen (...);

Screenshot page image casper. captureSelector

Run

Casperjs baidu. js

Check the image results generated by this script.

Wait! Why is the image only X in size?

The reason is that I created a browser process to load the page, but did not specify which browser to load. Therefore, when creating a casper instance, you can specify the window size of the browser, or even impersonate the browser of the mobile phone by specifying the userAgent. For example, you can specify safari as iPhone 5 and set the window size:

Var casper = require ('Casper '). create ({
PageSettings :{

// Impersonate a browser
UserAgent: 'mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) version/7.0 Mobile/11A465 Safari/9537.53'
},

// Browser window size
ViewportSize :{
Width: 320,
Height: 568
    }
});

After we run it again, is it like this?


Simple application

In the preceding example, you can see how to use an unbounded browser to load a page and get a screenshot of the page.

We can know what the page looks like without opening a browser. So every time we run this casperjs script, we can see whether our page is normal through screenshots.

However, judging by the naked eye is definitely against the original intention of "automation", so we must use tools to help us analyze.

The simplest and most intuitive method is "pixel comparison", that is, compare two or multiple screenshots to each pixel or a certain range of regions one by one, in this way, the differences between images can be produced, as shown in the figure below:

In actual application, you can specify an image as the reference graph. If the screenshot is different, an error occurs on the online page.

The Pixel comparison tool is quite mature. Here is a very close solution to front-end development: Resemble. js.

Why is it close to the front end because it uses canvas. We know that each pixel of an image can be determined by RBGA (red, blue, green, alpha) values:


The main principle of Resemble. js is to draw the image to be compared to the canvas and read the image data of the pixel (or area) to be compared to determine the image difference.

To better integrate with phantomjs and casperjs, the author of Resemble. js also developed The Resemble. js-based encapsulation of phanw.ss.

Phanw.ss uses simple APIs for image comparison:

Phanw.ss. screenshot ("# CSS. selector1", screenshotName1 );
Phanw.ss. screenshot ("# CSS. selector2", screenshotName2 );
Phanw.ss. compareFiles (screenshotName1, screenshotName2 );

If the image to be compared is inconsistent, a comparison chart is generated, and the differences are marked with conspicuous colors, similar to the following:


Note:

The page screenshot comparison is inconsistent, and it does not prove that our page has an exception, such as an advertisement space. These areas with frequent changes may be different in each comparison, therefore, it is not appropriate to compare advertising spaces or other frequently changing positions. In practical applications, it is not recommended to compare screenshots on the entire page. This method is too simple and crude. We should conduct subdivision and comparison of each area of the page for fine-grained monitoring.

Cookie

Since it is a browser test, no cookie is involved, and casperjs does not encapsulate cookie operations, you can use phantomjs to directly "type" cookies:

Phantom. addCookie ({
Name: 'cookies ',
Value: 'value ',
Domain: '.xx.com ',
Path :'/',
Secure: false,
Httponly: false,
Expires: Date. now () + (1000*60*60*24*5)
});

In the previous appetizers, the pages we visited were not logged on. Here, we can manually implant the cookie value of the logon status of the Baidu account to achieve login access.

Open Baidu homepage in PC-side chrome, log on with your account, and copy the key cookie BDUSS value of Baidu account in developer tools


And hard code to your casperjs script:

Phantom. addCookie ({
Name: 'bduss ',
Value: 'Cookie value you copied ',
Domain: '.baidu.com ',
Path :'/',
Secure: false,
Httponly: false,
Expires: Date. now () + (1000*60*60*24*5)
});

The complete code is run here. Let's look at the result again.


Done! The user name already exists in the upper right corner, indicating that we have logged on!


Interaction

Simple screenshots and comparisons are far from meeting our testing requirements. For automation principles, implementing automated page interaction is king. Don't worry.

The previous section describes how to manually implant cookies for logon. The following describes how to implement the logon process of Baidu on the mobile phone.

First, preview the entire script login. js code. The following describes the entire process:

Create an instance. The configuration is basically the same as that in the appetizer. For the sake of speed, the instantiated configuration selects not to load the image.

2. Load the page
3. Capture the non-logon page:

Casper.captureSelector('1.png ', 'html ');

In this step, image 1.png is displayed, and there is no user name in the upper right corner (not logged on): unlogined
4. Read and output all current cookies

Var cookies = phantom. cookies;
For (var I = 0, len = cookies. length; I <len; I ++ ){
Console. log (cookies [I]. name + ':' + cookies [I]. value );
}

This step outputs the result to the command line: we can see that the current cookie does not have the key cookie BDUSS of the Baidu account.
5. Click "log on".

Casper. mouse. click ('# login ');

Casperjs (phantomjs) supports a wide range of mouse events that support complex interactions:

Click
Doubleclick
Rightclick
Down
Up
Move

Allows you to specify the CSS3 path of an operation target.
6. Click "log on" to go to a logon page with the username and password entered. For convenience, please wait 3 seconds until the logon page is loaded.

Casper. wait (3000 );

7. Capture the logon page

Casper.captureSelector('2.png ', 'html ');

8. Fill in the form

Casper. evaluate (function (){
Document. querySelector ('[name = username]'). value = '***';
Document. querySelector ('[name = password]'). value = '***';
});

Evaluate is a very useful method.
9. Intercept the login form
10. Click log on.
11. Waiting to jump back to the home page
12. The homepage page after logon is intercepted.
13. Read the cookies one by one and display them in the command line

Finally, run the test script casperjs login. js to get four screenshots, respectively recording the interaction effect of the key steps in the entire logon interaction process:


Not logged on

Logon page

Enter information


Logon successful

The difference between Figure 1 and Figure 4 is that the user name in the upper-right corner of Figure 4:



At the same time, the BDUSS cookie value after logon is also read in the command line:


Let's try again.

Actions in iframe

Phantomjs (casperjs) not only operates on the current page, but also switches the current context to iframe for operations, which makes the page test embedded in iframe much easier.

Operation Area

Phantomjs (casperjs) supports the use of CSS3 selector and XPath to operate on the target to be operated (click, screenshot, etc.), and can also be operated by specifying the region boundary, for example, you can specify x/y coordinates/width/height to click or take a screenshot:

Casper.capture('capture.png ',{
X: 200,
Y: 300,
Width: 200,
Height: 300
});

Limitations of interaction

In the real world web, some interactive functions are not mechanical operations. Sometimes, due to security or other factors, some page restrictions are imposed, requiring our interaction to be dynamically output according to some situations, this function is difficult to fully automate. For example, the above Baidu login function sometimes has a verification code:



At this time, it is very difficult to use machines to help us log on. Therefore, I will introduce how to manually implant cookies to achieve login.


Unit test

Through the previous introduction, phantomjs (casperjs) has been able to implement many automated functions. On this basis, it is very easy to implement unit testing.

Casperjs provides a relatively complete unit test API

In unit testing, each testsuite is packaged in a closure:

Casper. test. begin ('your testsuite ', 0, function (test ){
// Unit test code
});

For example, the following is a set of test cases to test whether the title and log location of the Baidu page are correct:

Casper. test. begin ('test demo', 0, function (test ){

Casper. start ();

Casper. thenOpen ('http: // www.baidu.com/', function (){

// Test whether the page title is correct
Casper. test. assertTitle ('Baidu review ', 'Page title ');

// Test the location information of the logo

// Obtain x/y/width/height
Var layout = casper. getElementBounds ('# logo ');
Layout = JSON. stringify (layout );

// Verify the compliance
Casper. test. assertEquals (layout, '{"height": 87, "left": 0, "top": 53, "width": 320 }', 'logo \'s boundary ');

});

Casper. run (function (){
Casper. test. done ();
});

});

Complete Code test. js is here

Run casperjs test. js

You can see the following output in the command line:



Both cases have passed!

Compared with the visual display of the preceding screenshots, unit testing provides us with more concise test results.

In addition, the test module of casperjs can also generate XML results after testing. For example, the results of the above example are as follows:

<? Xml version = "1.0" encoding = "UTF-8"?>
& Lt; testsuites time = "2.228" & gt;
<Testsuite name = "test demo" tests = "2" failures = "0" errors = "0" time = "2.228"
Timestamp = "2015-08-31T13: 30: 12.462Z" package = "test">
<Testcase name = "page title" classname = "test" time = "2.223">
</Testcase>
<Testcase name = "logo's boundary" classname = "test" time = "0.005">
</Testcase>
<System-out>
</System-out>
</Testsuite>
</Testsuites>

The XML results can be combined with alarm and other systems to implement various powerful automation functions.

Problem

Browser compatibility. After all, phantomjs (casperjs) provides an unbounded webkit kernel browser, so it cannot cover ie. Currently, the Gecko kernel's UI-free browser already has a solution called SlimerJS and supports the same APIs as phantomjs.

Device compatibility. In the case of a variety of mobile phones and other terminal devices, it is more difficult for the server to simulate all the hardware and software environments without an interface browser.



Phantomjs + Casperjs makes page capturing and interaction in the background very simple

Casperjs is based on Phantomjs, while Phantom JS is a WebKit for JavaScript APIs on the server side.

This is a combination of my thoughts on finding a background that comes with a browser kernel ". Therefore, when I found this thing, I began to get excited by myself. After some research, it was a pity that the background connection to websites and page interaction suddenly became very simple. Especially for webpage operations that require logon.

Therefore, I used it to write two small examples for some website login and clicking some links and buttons on the Internet. During the compilation process, let's just say, "we don't have to worry about Cookie any more if you want to know where to do it ~" Feeling ~

After reading this example, do comrades unconsciously think of some words, such as "sign-in" and "Daily logon?


Var casper = require ('Casper '). create ({
Verbose: true,
LogLevel: 'debug ',
PageSettings :{
LoadImages: false,
LoadPlugins: true,
UserAgent: 'mozilla/5.0 (Windows NT 6.1; rv: 17.0) Gecko/20100101 Firefox/123456'
    }
});
// Phantom. outputEncoding = "gbk ";
Casper. options. viewportSize = {width: 1680, height: 924 };
Casper. start ('http: // bulo.hujiang.com/app/login? Source = nbulo & returnurl =/home /');
Casper. waitForSelector ("form # myform input [name = 'txtusername']",
Function success (){
This. test. assertExists ("form input [name = 'txtusername']");
This. fill ("form ",{
'Txtusername': 'shixiaobao17 ',
'Txtpassword': '××××your password *****'
}, False );
This. click ("input # btnLogin ");
},
Function fail (){
This. test. assertExists ("form input [name = 'txtusername']");
});
 
Casper. waitFor (function check (){
Return this. getCurrentUrl (). indexOf ("bulo.hujiang.com/home")>-1;
}, Function then (){
Console. log ("logon successful !!!!!!!!!!!! ");
}). Then (function (){
Console. log ("perform other operations after logon !!!!!!!!!!!! ");
If (this. exists ("# btn_card_do ")){
This. click ("# btn_card_do ");
This. waitForSelector ("# my_hb_btn", function success (){
Console. log ("logging successful! ");
}, Function fail (){
Console. log ("logging failed! ");
});
} Else {
Console. log ("You have been stuck today! ");
    }
    
});
Casper. run (function () {this. test. renderResults (true );});


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.