Created
July 26, 2012 20:52
-
-
Save wesleyhales/3184433 to your computer and use it in GitHub Desktop.
phantom script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var fs = require('fs'); | |
| var confess = { | |
| run: function () { | |
| var cliConfig = {}; | |
| confess.performancecache = this.clone(confess.performance); | |
| if (!this.processArgs(cliConfig, [ | |
| { | |
| name: 'url', | |
| def: 'http://google.com', | |
| req: true, | |
| desc: 'the URL of the app to cache' | |
| }, { | |
| name: 'task', | |
| def: 'performance', | |
| req: false, | |
| desc: 'the task to perform', | |
| oneof: ['performance', 'performancecache', 'filmstrip'] | |
| }, { | |
| name: 'configFile', | |
| def: 'config.json', | |
| req: false, | |
| desc: 'a local configuration file of further confess settings' | |
| } | |
| ])) { | |
| //phantom.exit(); | |
| return; | |
| } | |
| this.config = this.mergeConfig(cliConfig, cliConfig.configFile); | |
| var task = this[this.config.task]; | |
| this.load(this.config, task, this); | |
| }, | |
| performance: { | |
| resources: [], | |
| count1 : 100, | |
| count2 : 1, | |
| timer : 0, | |
| evalConsole : {}, | |
| evalConsoleErrors : [], | |
| onInitialized: function(page, config) { | |
| var pageecal = page.evaluate(function(startTime) { | |
| var now = new Date().getTime(); | |
| var _timer1=setInterval(function(){ | |
| if(/interactive/.test(document.readyState)){ | |
| clearInterval(_timer1); | |
| console.log('interactive-' + (new Date().getTime() - startTime)); | |
| } | |
| }, 10); | |
| var _timer2=setInterval(function(){ | |
| if(/loaded|complete/.test(document.readyState)){ | |
| clearInterval(_timer2); | |
| console.log('complete-' + (new Date().getTime() - startTime)); | |
| } | |
| }, 10); | |
| window.onload = function(){console.log('onload-' + (new Date().getTime() - startTime));}; | |
| window.onerror = function(message, url, linenumber) { | |
| console.log("jserror-JavaScript error: " + message + " on line " + linenumber + " for " + url); | |
| }; | |
| },this.performance.start); | |
| }, | |
| onLoadStarted: function (page, config) { | |
| if (!this.performance.start) { | |
| this.performance.start = new Date().getTime(); | |
| } | |
| }, | |
| onResourceRequested: function (page, config, request) { | |
| var now = new Date().getTime(); | |
| this.performance.resources[request.id] = { | |
| id: request.id, | |
| url: request.url, | |
| request: request, | |
| responses: {}, | |
| duration: '-', | |
| times: { | |
| request: now | |
| } | |
| }; | |
| if (!this.performance.start || now < this.performance.start) { | |
| this.performance.start = now; | |
| } | |
| }, | |
| onResourceReceived: function (page, config, response) { | |
| var now = new Date().getTime(), | |
| resource = this.performance.resources[response.id]; | |
| resource.responses[response.stage] = response; | |
| if (!resource.times[response.stage]) { | |
| resource.times[response.stage] = now; | |
| resource.duration = now - resource.times.request; | |
| } | |
| if (response.bodySize) { | |
| resource.size = response.bodySize; | |
| response.headers.forEach(function (header) { | |
| }); | |
| } else if (!resource.size) { | |
| response.headers.forEach(function (header) { | |
| if (header.name.toLowerCase()=='content-length' && header.value != 0) { | |
| //console.log('backup-------' + header.name + ':' + header.value); | |
| resource.size = parseInt(header.value); | |
| } | |
| }); | |
| } | |
| }, | |
| onLoadFinished: function (page, config, status) { | |
| var start = this.performance.start, | |
| finish = new Date().getTime(), | |
| resources = this.performance.resources, | |
| slowest, fastest, totalDuration = 0, | |
| largest, smallest, totalSize = 0, | |
| missingList = [], | |
| missingSize = false, | |
| elapsed = finish - start, | |
| now = new Date(); | |
| resources.forEach(function (resource) { | |
| if (!resource.times.start) { | |
| resource.times.start = resource.times.end; | |
| } | |
| if (!slowest || resource.duration > slowest.duration) { | |
| slowest = resource; | |
| } | |
| if (!fastest || resource.duration < fastest.duration) { | |
| fastest = resource; | |
| } | |
| totalDuration += resource.duration; | |
| if (resource.size) { | |
| if (!largest || resource.size > largest.size) { | |
| largest = resource; | |
| } | |
| if (!smallest || resource.size < smallest.size) { | |
| smallest = resource; | |
| } | |
| totalSize += resource.size; | |
| } else { | |
| resource.size = '-'; | |
| missingSize = true; | |
| missingList.push(resource.url); | |
| } | |
| }); | |
| if (config.verbose) { | |
| console.log(''); | |
| this.emitConfig(config, ''); | |
| } | |
| var report = {}; | |
| report.phantomCacheEnabled = phantom.args.indexOf('yes') >= 0 ? 'yes' : 'no'; | |
| report.taskName = config.task; | |
| report.domReadyStateInteractive = parseInt(this.performance.evalConsole.interactive); | |
| report.windowOnload = parseInt(this.performance.evalConsole.onload); | |
| report.domReadyStateComplete = parseInt(this.performance.evalConsole.complete); | |
| report.elapsedLoadTime = elapsed; | |
| report.numberOfResources = resources.length-1; | |
| report.totalResourcesTime = totalDuration; | |
| report.totalResourcesSize = (totalSize / 1000); | |
| report.nonReportingResources = missingList.length; | |
| report.timeStamp = now.getTime(); | |
| report.date = now.getDate() + "/" + now.getMonth() + "/" + now.getFullYear(); | |
| report.time = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(); | |
| report.errors = this.performance.evalConsoleErrors; | |
| //console.log(JSON.stringify(report)); | |
| console.log('Elapsed load time: ' + this.pad(elapsed, 6) + 'ms'); | |
| if(phantom.args.indexOf('csv') >= 0){ | |
| this.printToFile(config,report,'confess-report','csv',phantom.args.indexOf('wipe') >= 0); | |
| } | |
| if(phantom.args.indexOf('json') >= 0){ | |
| this.printToFile(config,report,'confess-report','json',phantom.args.indexOf('wipe') >= 0); | |
| } | |
| if (config.verbose) { | |
| console.log(''); | |
| var ths = this, | |
| length = 104, | |
| ratio = length / elapsed, | |
| bar; | |
| resources.forEach(function (resource) { | |
| bar = ths.repeat(' ', (resource.times.request - start) * ratio) + | |
| ths.repeat('-', (resource.times.start - resource.times.request) * ratio) + | |
| ths.repeat('=', (resource.times.end - resource.times.start) * ratio) | |
| ; | |
| bar = bar.substr(0, length) + ths.repeat(' ', length - bar.length); | |
| console.log(ths.pad(resource.id, 3) + '|' + bar + '|'); | |
| }); | |
| console.log(''); | |
| resources.forEach(function (resource) { | |
| console.log( | |
| ths.pad(resource.id, 3) + ': ' + | |
| ths.pad(resource.duration, 6) + 'ms; ' + | |
| ths.pad(resource.size, 7) + 'b; ' + | |
| ths.truncate(resource.url, 84) | |
| ); | |
| }); | |
| } | |
| } | |
| }, | |
| filmstrip: { | |
| onInitialized: function(page, config) { | |
| this.screenshot(new Date().getTime(),page); | |
| }, | |
| onLoadStarted: function (page, config) { | |
| if (!this.performance.start) { | |
| this.performance.start = new Date().getTime(); | |
| } | |
| this.screenshot(new Date().getTime(),page); | |
| }, | |
| onResourceRequested: function (page, config, request) { | |
| this.screenshot(new Date().getTime(),page); | |
| }, | |
| onResourceReceived: function (page, config, response) { | |
| this.screenshot(new Date().getTime(),page); | |
| }, | |
| onLoadFinished: function (page, config, status) { | |
| this.screenshot(new Date().getTime(),page); | |
| } | |
| }, | |
| getFinalUrl: function (page) { | |
| return page.evaluate(function () { | |
| return document.location.toString(); | |
| }); | |
| }, | |
| emitConfig: function (config, prefix) { | |
| console.log(prefix + 'Config:'); | |
| for (key in config) { | |
| if (config[key].constructor === Object) { | |
| if (key===config.task) { | |
| console.log(prefix + ' ' + key + ':'); | |
| for (key2 in config[key]) { | |
| console.log(prefix + ' ' + key2 + ': ' + config[key][key2]); | |
| } | |
| } | |
| } else { | |
| console.log(prefix + ' ' + key + ': ' + config[key]); | |
| } | |
| } | |
| }, | |
| load: function (config, task, scope) { | |
| var page = new WebPage(), | |
| pagetemp = new WebPage(), | |
| event; | |
| // if (config.consolePrefix) { | |
| // page.onConsoleMessage = function (msg, line, src) { | |
| // console.log(config.consolePrefix + '---+++ ' + msg + ' (' + src + ', #' + line + ')'); | |
| // } | |
| // } | |
| if (config.userAgent && config.userAgent != "default") { | |
| if (config.userAgentAliases[config.userAgent]) { | |
| config.userAgent = config.userAgentAliases[config.userAgent]; | |
| } | |
| page.settings.userAgent = config.userAgent; | |
| } | |
| ['onInitialized', 'onLoadStarted', 'onResourceRequested', 'onResourceReceived'] | |
| .forEach(function (event) { | |
| if (task[event]) { | |
| page[event] = function () { | |
| var args = [page, config], | |
| a, aL; | |
| for (a = 0, aL = arguments.length; a < aL; a++) { | |
| args.push(arguments[a]); | |
| } | |
| task[event].apply(scope, args); | |
| }; | |
| } | |
| }); | |
| if (task.onLoadFinished) { | |
| page.onLoadFinished = function (status) { | |
| if (config.wait) { | |
| setTimeout( | |
| function () { | |
| task.onLoadFinished.call(scope, page, config, status); | |
| }, | |
| config.wait | |
| ); | |
| } else { | |
| task.onLoadFinished.call(scope, page, config, status); | |
| } | |
| phantom.exit(); | |
| //page.release(); | |
| page = new WebPage(); | |
| doPageLoad(); | |
| }; | |
| } else { | |
| page.onLoadFinished = function (status) { | |
| phantom.exit(); | |
| }; | |
| } | |
| page.settings.localToRemoteUrlAccessEnabled = true; | |
| page.settings.webSecurityEnabled = false; | |
| page.onConsoleMessage = function (msg) { | |
| if (msg.indexOf('jserror-') >= 0){ | |
| confess.performance.evalConsoleErrors.push(msg.substring('jserror-'.length,msg.length)); | |
| }else{ | |
| if (msg.indexOf('interactive-') >= 0){ | |
| confess.performance.evalConsole.interactive = msg.substring('interactive-'.length,msg.length); | |
| } else if (msg.indexOf('complete-') >= 0){ | |
| confess.performance.evalConsole.complete = msg.substring('complete-'.length,msg.length); | |
| } else if (msg.indexOf('onload-') >= 0){ | |
| confess.performance.evalConsole.onload = msg.substring('onload-'.length,msg.length); | |
| } | |
| //confess.performance.evalConsole.push(msg); | |
| } | |
| }; | |
| page.onError = function (msg, trace) { | |
| //console.log("+++++ " + msg); | |
| trace.forEach(function(item) { | |
| confess.performance.evalConsoleErrors.push(msg + ':' + item.file + ':' + item.line); | |
| }) | |
| }; | |
| function doPageLoad(){ | |
| setTimeout(function(){page.open(config.url);},config.cacheWait); | |
| } | |
| if(config.task == 'performancecache'){ | |
| pagetemp.open(config.url,function(status) { | |
| if (status === 'success') { | |
| pagetemp.release(); | |
| doPageLoad(); | |
| } | |
| }); | |
| }else{ | |
| doPageLoad(); | |
| } | |
| }, | |
| processArgs: function (config, contract) { | |
| var a = 0; | |
| var ok = true; | |
| contract.forEach(function(argument) { | |
| if (a < phantom.args.length) { | |
| config[argument.name] = phantom.args[a]; | |
| } else { | |
| if (argument.req) { | |
| console.log('"' + argument.name + '" argument is required. This ' + argument.desc + '.'); | |
| ok = false; | |
| } else { | |
| config[argument.name] = argument.def; | |
| } | |
| } | |
| if (argument.oneof && argument.oneof.indexOf(config[argument.name])==-1) { | |
| console.log('"' + argument.name + '" argument must be one of: ' + argument.oneof.join(', ')); | |
| ok = false; | |
| } | |
| a++; | |
| }); | |
| return ok; | |
| }, | |
| mergeConfig: function (config, configFile) { | |
| if (!fs.exists(configFile)) { | |
| configFile = "config.json"; | |
| } | |
| var result = JSON.parse(fs.read(configFile)), | |
| key; | |
| for (key in config) { | |
| result[key] = config[key]; | |
| } | |
| return result; | |
| }, | |
| truncate: function (str, length) { | |
| length = length || 80; | |
| if (str.length <= length) { | |
| return str; | |
| } | |
| var half = length / 2; | |
| return str.substr(0, half-2) + '...' + str.substr(str.length-half+1); | |
| }, | |
| pad: function (str, length) { | |
| var padded = str.toString(); | |
| if (padded.length > length) { | |
| return this.pad(padded, length * 2); | |
| } | |
| return this.repeat(' ', length - padded.length) + padded; | |
| }, | |
| repeat: function (chr, length) { | |
| for (var str = '', l = 0; l < length; l++) { | |
| str += chr; | |
| } | |
| return str; | |
| }, | |
| clone: function(obj) { | |
| var target = {}; | |
| for (var i in obj) { | |
| if (obj.hasOwnProperty(i)) { | |
| target[i] = obj[i]; | |
| } | |
| } | |
| return target; | |
| }, | |
| timerStart: function () { | |
| return (new Date()).getTime(); | |
| }, | |
| timerEnd: function (start) { | |
| return ((new Date()).getTime() - start); | |
| }, | |
| worker: function(now,page){ | |
| var currentTime = now - this.performance.start; | |
| var ths = this; | |
| if((currentTime) >= this.performance.count1){ | |
| var worker = new Worker('file:///Users/wesleyhales/phantom-test/worker.js'); | |
| worker.addEventListener('message', function (event) { | |
| //getting errors after 3rd thread with... | |
| //_this.workerTask.callback(event); | |
| //mycallback(event); | |
| console.log('message' + event.data); | |
| }, false); | |
| worker.postMessage(page); | |
| this.performance.count2++; | |
| this.performance.count1 = currentTime + (this.performance.count2 * 100); | |
| } | |
| }, | |
| screenshot: function(now,page){ | |
| var start = this.timerStart(); | |
| var currentTime = now - this.performance.start; | |
| var ths = this; | |
| if((currentTime) >= this.performance.count1){ | |
| //var ashot = page.renderBase64(); | |
| page.render('filmstrip/screenshot' + this.performance.timer + '.png'); | |
| this.performance.count2++; | |
| this.performance.count1 = currentTime + (this.performance.count2 * 100); | |
| //subtract the time it took to render this image | |
| this.performance.timer = this.timerEnd(start) - this.performance.count1; | |
| } | |
| }, | |
| printToFile: function(config,report,filename,extension,createNew) { | |
| var f, myfile, | |
| keys = [], values = []; | |
| for(var key in report) | |
| { | |
| if(report.hasOwnProperty(key)) | |
| { | |
| keys.push(key); | |
| values.push(report[key]); | |
| } | |
| } | |
| myfile = filename + '.' + extension | |
| // if(config.task === 'performancecache'){ | |
| // myfile = filename + '-performancecache.' + extension | |
| // }else{ | |
| // myfile = filename + '-performance.' + extension | |
| // } | |
| if(!createNew && fs.exists(myfile)){ | |
| //file exists so append line | |
| try{ | |
| if(extension === 'json'){ | |
| var phantomLog = []; | |
| phantomLog.push(JSON.parse(fs.read(myfile))); | |
| phantomLog.push(report); | |
| fs.remove(myfile); | |
| f = fs.open(myfile, "w"); | |
| f.writeLine(JSON.stringify(phantomLog)); | |
| f.close(); | |
| }else{ | |
| f = fs.open(myfile, "a"); | |
| f.writeLine(values); | |
| f.close(); | |
| } | |
| } catch (e) { | |
| console.log("problem appending to file",e); | |
| } | |
| }else{ | |
| if(fs.exists(myfile)){ | |
| fs.remove(myfile); | |
| } | |
| //write the headers and first line | |
| try { | |
| f = fs.open(myfile, "w"); | |
| if(extension === 'json'){ | |
| f.writeLine(JSON.stringify(report)); | |
| }else{ | |
| f.writeLine(keys); | |
| f.writeLine(values); | |
| } | |
| f.close(); | |
| } catch (e) { | |
| console.log("problem writing to file",e); | |
| } | |
| } | |
| } | |
| }; | |
| confess.run(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment