jsharmony-tutorials
Version:
jsHarmony Tutorials
277 lines (247 loc) • 10.5 kB
JavaScript
/*
Copyright 2017 apHarmony
This file is part of jsHarmony.
jsHarmony is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jsHarmony is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this package. If not, see <http://www.gnu.org/licenses/>.
*/
var ejs = require('ejs');
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var async = require('async');
var HelperFS = require('jsharmony/HelperFS');
var Helper = require('jsharmony/Helper');
module.exports = exports = {};
/*******************
| SCREENSHOTS |
*******************/
exports.DEFAULT_SCREENSHOT_SIZE = [950, 700];
exports.HEADLESS = true;
exports.generateScreenshots = function(options,callback){
var _this = this;
var jsh = _this.jsh;
_this.options = _.extend({
screenshot_folder: path.join('public','screenshots'),
targetTests: null
}, options);
var browserParams = { ignoreHTTPSErrors: true, ignoreDefaultArgs: [ '--hide-scrollbars' ] };
if(!exports.HEADLESS) browserParams.headless = false;
jsh.Extensions.report.getPuppeteer(function(err, puppeteer){
if(err) return jsh.Log.error(err);
puppeteer.launch(browserParams).then(function(browser){
HelperFS.funcRecursive(_this.tutfolder,function(filepath, relativepath, file_cb){
//For each File
fs.readFile(filepath, 'utf8', function(err, txt){
if(err) return file_cb(err);
var screenshots = [];
try{
ejs.render(txt, {
req: null,
getScreenshot: function(url, desc, params){ screenshots.push( { url: url, desc: desc, params: params } ); },
instance: '',
_: _
});
}
catch(ex){ return file_cb(ex); }
async.eachLimit(screenshots, 1, function(screenshot, screenshot_cb){
_this.generateScreenshot(browser, screenshot.url, screenshot.desc, screenshot.params, screenshot_cb);
}, function(err){
if(err){ jsh.Log.error(err); }
return file_cb();
});
});
},undefined,undefined,function(err){
if(err){ jsh.Log.error(err); }
browser.close();
return callback();
});
}).catch(function(err){ jsh.Log.error(err); });
});
}
exports.generateScreenshot = function(browser, url, desc, params, callback){
var _this = this;
var jsh = _this.jsh;
if(!url || (url[0] != '/')) url = '/' + url;
var fname = this.getScreenshotFilename(url, desc, params);
var fpath = _this.options.screenshot_folder;
if(!path.isAbsolute(fpath)) fpath = path.join(_this.basepath, fpath);
fpath = path.join(fpath, fname);
//Do not generate screenshot if image already exists
if(fs.existsSync(fpath)) return callback();
if(_this.options.targetTests){
if(!_.includes(_this.options.targetTests, fname)) return callback();
}
var origParams = params||{};
params = _.extend({
x: 0,
y: 0,
width: _this.DEFAULT_SCREENSHOT_SIZE[0],
height: null,
trim: true,
resize: null, //{ width: xxx, height: yyy }
postClip: null, //{ x: 0, y: 0, width: xxx, height: yyy }
cropToSelector: null, //Selector
onload: null,
waitBeforeScreenshot: (exports.HEADLESS ? 150 : 1500)
}, params);
if(!params.browserWidth) params.browserWidth = params.x + params.width;
if(!params.browserHeight) params.browserHeight = _this.DEFAULT_SCREENSHOT_SIZE[1];
if(!params.onload) params.onload = function(){ return new Promise(function(resolve){ return resolve(); }); };
var base_onload = params.onload;
params.onload = function(){
return new Promise(function(resolve){
if(!window.jshInstance){ return base_onload().then(resolve); }
var startTime = new Date().getTime();
jshInstance.XExt.waitUntil(
function(){ return jshInstance.init_complete; },
function(){
if(jshInstance) jshInstance.XWindowResize();
return base_onload().then(resolve);
},
function(f){ if ((new Date().getTime() - startTime) > 5000) { f(); return false; } }
);
});
}
params.onload = Helper.ReplaceAll(params.onload.toString(), 'base_onload', '(' + base_onload.toString() + ')');
eval('params.onload = ' + params.onload + ';');
var getPageInfo = function(selector){
document.querySelector('html').style.overflow = 'hidden';
return new Promise(function(resolve){
var pageSize = {
pageWidth: document.body.scrollWidth,
pageHeight: document.body.scrollHeight,
};
if(!selector) return resolve(pageSize);
if(!jshInstance) return resolve(pageSize);
var $ = jshInstance.$;
pageSize = {
pageWidth: $(document).width(),
pageHeight: $(document).height(),
}
var jobjs = $(selector);
if(!jobjs.length) return resolve(pageSize);
var startpos = null;
var endpos = null;
for(var i=0;i<jobjs.length;i++){
var jobj = $(jobjs[i]);
var offset = jobj.offset();
var offStart = { left: offset.left - 1, top: offset.top - 1 };
var offEnd = { left: offset.left + 1 + jobj.outerWidth(), top: offset.top + 1 + jobj.outerHeight() };
if(!startpos) startpos = offStart;
if(offStart.left < startpos.left) startpos.left = offStart.left;
if(offStart.top < startpos.top) startpos.top = offStart.top;
if(!endpos) endpos = offEnd;
if(offEnd.left > endpos.left) endpos.left = offEnd.left;
if(offEnd.top > endpos.top) endpos.top = offEnd.top;
}
return resolve({
cropRectangle: {
x: startpos.left,
y: startpos.top,
width: endpos.left - startpos.left,
height: endpos.top - startpos.top,
},
pageWidth: pageSize.width,
pageHeight: pageSize.height,
});
});
}
browser.newPage().then(function (page) {
var port = jsh.Servers['default'].servers[0].address().port;
var fullurl = 'http://localhost:'+port+url;
console.log(_this.basepath + '/public/screenshots/'+fname);
page.setViewport({ width: params.browserWidth, height: params.browserHeight }).then(function(){
page.goto(fullurl, { waitUntil: 'networkidle0' }).then(function(){
page.evaluate(params.onload).then(function(){
page.evaluate(getPageInfo, params.cropToSelector).then(function(pageInfo){
//Apply height clipping using cropRectangle
if(!pageInfo.cropRectangle){
if(params.height){
pageInfo.cropRectangle = {
x: params.x,
y: params.y,
width: (origParams.width ? origParams.width : pageInfo.pageWidth),
height: params.height
};
}
}
var takeScreenshot = function(){
setTimeout(function(){
var screenshotParams = { path: fpath, type: 'png' };
if(pageInfo.cropRectangle) params.postClip = pageInfo.cropRectangle;
screenshotParams.fullPage = true;
page.screenshot(screenshotParams).then(function(){
_this.processScreenshot(fpath, params, function(err){
if(err) jsh.Log.error(err);
page.close().then(function () {
return callback();
}).catch(function (err) { jsh.Log.error(err); });
});
}).catch(function (err) { jsh.Log.error(err); });
}, params.waitBeforeScreenshot);
}
if(params.beforeScreenshot){
params.beforeScreenshot(jsh, page, takeScreenshot, pageInfo.cropRectangle);
}
else takeScreenshot();
}).catch(function (err) { jsh.Log.error(err); });
}).catch(function (err) { jsh.Log.error(err); });
}).catch(function (err) { jsh.Log.error(err); });
}).catch(function (err) { jsh.Log.error(err); });
}).catch(function (err) { jsh.Log.error(err); });
}
exports.processScreenshot = function(fpath, params, callback){
var _this = this;
var jsh = _this.jsh;
async.waterfall([
function(img_cb){
if(!params.postClip && !params.trim) return img_cb();
var cropParams = [null, null, { resize: false }];
if(params.postClip){
cropParams[0] = params.postClip.width;
cropParams[1] = params.postClip.height;
cropParams[2].x = params.postClip.x;
cropParams[2].y = params.postClip.y;
}
if(params.trim) cropParams[2].trim = true;
jsh.Extensions.image.crop(fpath, fpath, cropParams, 'png', img_cb);
},
function(img_cb){
if(!params.resize) return img_cb();
var resizeParams = [params.resize.width||null, params.resize.height||null];
jsh.Extensions.image.resize(fpath, fpath, resizeParams, 'png', img_cb);
},
], function(err){
return callback(err);
});
}
exports.getScreenshot = function(url, desc, params){
var fname = this.getScreenshotFilename(url, desc, params);
return '<img class="screenshot" src="/screenshots/' + fname + '" />';
}
exports.getScreenshotFilename = function(url, desc, params){
if(!params) params = {};
//Generate file name
var fname = url || '';
if(fname && (fname[0]=='/')) fname = fname.substr(1);
if(fname.length > 150){
fname = fname.substr(0,150);
}
fname = fname + '____' + desc;
if(params.width) fname += '_' + params.width;
if(params.height) fname += '_' + params.height;
fname = fname.toString().replace(/[^a-zA-Z0-9]+/g, '_');
fname = fname.replace(/\_+/g,'_');
if(fname[0]=='_') fname = fname.substr(1);
if(fname[fname.length-1]=='_') fname = fname.substr(0,fname.length-1);
fname += '.png';
return fname;
}