Detailed description of a pixel comparison Service Based on casperjs and resemble. js,
Preface
This article shares a node service that provides pixel comparison between the design draft and the front-end page. It aims to complete an auxiliary test for the testing or front-end personnel. Believe me, in the pixel-level comparison, the restoration degree of the design draft on the webpage will be highlighted at once. I won't talk much about it below. Let's take a look at the detailed introduction.
Effect Preview
Prerequisites
The following two libraries are used as auxiliary tools:
- Casperjs: Based on PhantomJS. It provides a non-interface browser. In simple terms, you can use it to perform operations on the browser by simulating people in the form of code, which involves various mouse events and many other functions, this time, we mainly use the features that come with it.
- Resemble. js: image pixel comparison tool. The calling method is simply to pass in two graphs, return a synthetic diagram with comparison parameters such as the degree of difference. The basic idea is to convert an image into a canvas, get its image pixels, and then compare each pixel.
Therefore, we should already have the idea of accessing a website through casperjs to intercept a page, and then compare it with the design drawing to get the result.
Overall Thinking
We should be able to organize a rough process:
- Receiving design draft images and the website addresses and node information to be captured from the front-end page
- Save the design draft to the images folder
- Start the sub-process, start casperjs, and complete the interception of the target website
- After receiving the screenshot, request form.html to fill in the image address information and return it back to the server.
- The server obtains image information and compares the screenshot with the design draft through resemblejs.
- Result returned to front-end page
One of these problems may be noticed: Why can't the target website be directly transmitted back to the server in casperjs, instead, I chose to open a form page and submit information in the form of a form?
A: First of all, I don't know much about casperjs and node. I understand that casperjs is not a node module and runs in the operating system, I still haven't found out how to establish communication with the node service in casperjs. If you have any way, please let me know, because I really don't know casper! Secondly, because communication cannot be established, I can only go back to the next step. By using casper, I can quickly open a form page that I have written and fill in the image information and send it back to the server. In this way, I can fulfill my initial appeal. In this case, the from.html operation is performed.
Implementation Details
Implement a simple static Server
To return the index.html and form.html pages, you need to implement a super simple static server. The Code is as follows:
Const MIME_TYPE = {"css": "text/css", "gif": "image/gif", "html": "text/html", "ico ": "image/x-icon", "jpeg": "image/jpeg", "jpg": "image/jpg", "js": "text/javascript ", "json": "application/json", "pdf": "application/pdf", "png": "image/png", "svg ": "image/svg + xml", "swf": "application/x-shockwave-flash", "tiff": "image/tiff", "txt ": "text/plain", "wav": "audio/x-wav", "wma": "audio/x-ms-wma", "wm V ":" video/x-ms-wmv "," xml ":" text/xml "} function sendFile (filePath, res) {fs. open (filePath, 'r + ', function (err) {// open the file if (err) {send404 (res)} else {let ext = path according to the path. extname (filePath) ext = ext? Ext. slice (1): 'unknown 'let contentType = MIME_TYPE [ext] | "text/plain" // matches the file type fs. readFile (filePath, function (err, data) {if (err) {send500 (res)} else {res. writeHead (200, {'content-type': contentType}) res. end (data )}})}})}
Parse the form and store the image in the images folder
Const multiparty = require ('multiparty ') // parse the form let form = new multiparty. form () form. parse (req, function (err, fields, files) {let filename = files ['file'] [0]. originalFilename, targetPath = _ dirname + '/images/' + filename, if (filename) {fs. createReadStream (files ['file'] [0]. path ). pipe (fs. createWriteStream (targetPath ))...}})
You can create a readable stream to read the file content, and write it to the specified path through pipe to save the uploaded image.
Run casperjs
const { spawn } = require('child_process')spawn('casperjs', ['casper.js', filename, captureUrl, selector, id])casperjs.stdout.on('data', (data) => { ...})
Through spawn, you can create sub-processes to start casperjs, and you can also use exec.
Submit data to form.html
Const system = require ('system') const host = 'HTTP: // 10.2.45.110: 3033 'const casper = require ('casper '). create ({// browser window size viewportSize: {width: 1920, height: 4080}) const fileName = decodeURIComponent (system. args [4]) const url = decodeURIComponent (system. args [5]) const selector = decodeURIComponent (system. args [6]) const id = decodeURIComponent (system. args [7]) const time = new Date (). getTime () casper. start (url) casper. then (function () {console. log ('Please wait a while later ') this. captureSelector ('. /images/casper '+ id + time interval '.png', selector)}) casper. then (function () {casper. start (host + '/form.html', function () {this. fill ('form # contact-form', {'dir ':'. /images/casper '+ id + time interval '.png', 'point ':'. /images/'+ fileName, 'id': id}, true)}) casper. run ()
The code is still relatively simple. The main process is to open a page, input your operations in then, and finally execute run. In this process, I do not know how to communicate with the node service, so I chose to open another page .. For more information, see the official casperjs website!
Use resemble. js to compare pixels and return data
Function complete (data) {let imgName = 'diff '+ new Date (). getTime () pai'.png ', imgUrl, analysisTime = data. analysisTime, misMatchPercentage = data. misMatchPercentage, resultUrl = '. /images/'+ imgName fs. writeFileSync (resultUrl, data. getBuffer () imgObj = {...} let resEnd = resObj [id] // retrieve the initial res and return it to the page data resEnd. writeHead (200, {'content-type': 'application/json'}) resEnd. end (JSON. stringify (imgObj)} let result = resemble (diff ). compareTo (point ). ignoreColors (). onComplete (complete)
This involves a point, that is, the results I get now are returned to the initial request, and I have transitioned many times from the beginning to now, as a result, I cannot find my initial returned body res. After thinking for a long time, you can only temporarily use a set global object. After receiving the initial request, set the requester's ip address and timestamp to a unique id and save it as the key of the object, value is the current res. At the same time, the id is passed during the entire transfer process, and the first response body is returned by calling resObj [id. I don't think this method is the optimal solution, but since I cannot come up with a good method, I have .. If you have any new ideas, please be sure to inform us !!
Deployment
Install PhantomJS (osx)
Download: phantomjs-2.1.1-macosx.zip
Unzip path:/User/xxx/phantomjs-2.1.1-macosx
Add environment variable :~ /Add to the. bash_profile File
Export PATH = "$ PATH:/Users/xxx/phantomjs-2.1.1-macosx/bin"
Terminal input: phantomjs -- version
The version number is successfully installed.
Install casperjs
brew update && brew install casperjs
Install resemble. js
Cnpm I resemblejs // you do not need to install brew install pkg-config cairo libpng jpeg giflibcnpm I canvas/node to run canvas
Node service
git clone https://github.com/Aaaaaaaty/gui-auto-test.gitcd gui-auto-testcnpm icd pxdiffnodemon server.js
Open http: // localhost: 3033/index.html
The blog of the author of po is updated from time to time --
References
- Install PhantomJS
- Casperjs document
- Resemble. js document
Summary
The above is all the content of this article. I hope the content of this article has some reference and learning value for everyone's learning or work. If you have any questions, please leave a message to us, thank you for your support.