diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a1537b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +node_modules diff --git a/.jshintrc b/.jshintrc index 39a8579..0f62563 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,19 +1,19 @@ { - "node": true, - "esnext": true, - "bitwise": true, - "camelcase": true, - "curly": true, - "eqeqeq": true, - "immed": true, - "indent": 4, - "newcap": true, - "noarg": true, - "quotmark": "single", - "regexp": true, - "undef": true, - "unused": true, - "strict": true, - "trailing": true, - "smarttabs": true + "node": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 4, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true } diff --git a/cli.js b/cli.js old mode 100644 new mode 100755 index 04e5478..03e2ab7 --- a/cli.js +++ b/cli.js @@ -5,72 +5,72 @@ var chalk = require('chalk'); var wraith = require('./index'); function showHelp() { - console.log('A responsive screenshot comparison tool.'); - console.log('Based on the Ruby version available at http://github.comm/BBC-News/wraith'); - console.log(''); - console.log(chalk.underline('Usage')); - console.log(' wraith --config '); - console.log(''); - console.log(chalk.underline('Example')); - console.log(' wraith --config chrome'); - console.log(''); + console.log('A responsive screenshot comparison tool.'); + console.log('Based on the Ruby version available at http://github.comm/BBC-News/wraith'); + console.log(''); + console.log(chalk.underline('Usage')); + console.log(' wraith --config '); + console.log(''); + console.log(chalk.underline('Example')); + console.log(' wraith --config chrome'); + console.log(''); } function getStdin(cb) { - var ret = ''; + var ret = ''; - process.stdin.resume(); - process.stdin.setEncoding('utf8'); + process.stdin.resume(); + process.stdin.setEncoding('utf8'); - process.stdin.on('data', function (data) { - ret += data; - }); + process.stdin.on('data', function (data) { + ret += data; + }); - process.stdin.on('end', function () { - cb(ret); - }); + process.stdin.on('end', function () { + cb(ret); + }); } function init(args) { - if (opts.help) { - return showHelp(); - } + if (opts.help) { + return showHelp(); + } - if (opts.version) { - return console.log(require('./package').version); - } + if (opts.version) { + return console.log(require('./package').version); + } - var config = args; - if( opts.config && args[0]) { - if (config.length === 0) { - console.error(chalk.yellow('You must specifiy a configuration file')); - return showHelp(); - } else { - return wraith.run(args[0]); - } - } + var config = args; + if (opts.config && args[0]) { + if (config.length === 0) { + console.error(chalk.yellow('You must specifiy a configuration file')); + return showHelp(); + } else { + return wraith.run(args[0]); + } + } - return showHelp(); + return showHelp(); } var opts = nopt({ - help: Boolean, - version: Boolean, - config: Boolean + help: Boolean, + version: Boolean, + config: Boolean }, { - h: '--help', - v: '--version', - c: '--config' + h: '--help', + v: '--version', + c: '--config' }); var args = opts.argv.remain; if (process.stdin.isTTY) { - init(args); + init(args); } else { - getStdin(function (data) { - [].push.apply(args, data.trim().split('\n')); - init(args); - }); + getStdin(function (data) { + [].push.apply(args, data.trim().split('\n')); + init(args); + }); } diff --git a/config/bbc.json b/config/bbc.json new file mode 100644 index 0000000..d7e89fb --- /dev/null +++ b/config/bbc.json @@ -0,0 +1,25 @@ +{ + "project": "Test", + "domains": { + "bbc.co.uk": "http://www.bbc.co.uk", + "live.bbc.co.uk": "http://www.live.bbc.co.uk" + }, + "engines": [ + "phantomjs" + ], + "sizes": [ + "320", + "768", + "1440" + ], + "outputDir": "bbc", + "paths": [ + "/", + "/news", + "/weather", + "/tv", + "/aboutthebbc" + ], + "fuzz": "20%", + "maxConnections": 20 +} diff --git a/config/chrome.json b/config/chrome.json deleted file mode 100644 index 22c20a4..0000000 --- a/config/chrome.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "project": "Test", - "domains": { - "bbc.co.uk": "http://www.bbc.co.uk", - "live.bbc.co.uk": "http://www.live.bbc.co.uk" - }, - "engines" : [ - "phantomjs" - ], - "sizes": [ - "320", - "768", - "1440" - ], - "paths": [ - "/", - "/news", - "/weather", - "/tv", - "/aboutthebbc" - ], - "outputDir": "bbc", - "fuzz": "20%", - "maxConnections": 20 -} \ No newline at end of file diff --git a/config/config.example.json b/config/config.example.json new file mode 100644 index 0000000..a5cbb33 --- /dev/null +++ b/config/config.example.json @@ -0,0 +1,47 @@ +{ + "#": "(Optional name for the project, if supplied it will be used within the generated gallery only)", + "project": "Test", + + "#": "Specify one or two domains", + "domains": { + "bbb.co.uk": "http://www.bbc.co.uk", + "live.bbc.co.uk": "http://live.bbc.co.uk" + }, + + "#": "Engines supported are phantomjs, slimerjs and triflejs but in theory any phantomjs based headless browser can be supported via a custom snap.js file", + "engines": [ + "phantomjs" + ], + + "#": "Specify as many sizes as you wish", + "sizes": [ + "320", + "768", + "1440" + ], + + "#": "(Defaults to 'shots' directory)", + "outputDir": "test/chrome/", + + "#": "You can choose to specify a list of paths to be used or you can crawl the site. If paths are provided they will take precedent and the spider file will be ignored.", + "paths": [ + "/", + "/news/", + "/news/local/", + "/news/england/york_and_north_yorkshire/", + "/weather/" + ], + + "#": "If no paths are specified then a site crawl will take place and the results will be save in the location specified within this option", + "#": "(Specify which file should be used for the spider txt file)", + "spider": "spider/test.txt", + + "#": "(Specify snap.js which is used to take the screenshots. Defaults to 'snap.js')", + "snap": "snap/test/chrome.js", + + "#": "(Adjusts the sensitivity of the image comparison)", + "fuzz": "20%", + + "#": "(Limit the amount of concurrent processes)", + "maxConnections": 20 +} diff --git a/config/defaults.json b/config/defaults.json new file mode 100644 index 0000000..2ff2b87 --- /dev/null +++ b/config/defaults.json @@ -0,0 +1,16 @@ +{ + "project": "", + "engines": [ + "phantomjs" + ], + "sizes": [ + "720" + ], + "outputDir": "shots/", + "paths": [ + "/" + ], + "snap": "snap.js", + "fuzz": "20%", + "maxConnections": 20 +} diff --git a/config/google.json b/config/google.json new file mode 100644 index 0000000..2c15cd4 --- /dev/null +++ b/config/google.json @@ -0,0 +1,21 @@ +{ + "project": "Google Test", + "domains": { + "usa": "http://www.google.com", + "canada": "http://www.google.ca" + }, + "engines": [ + "phantomjs" + ], + "sizes": [ + "768", + "1440" + ], + "outputDir": "test", + "paths": [ + "/", + "/404" + ], + "fuzz": "20%", + "maxConnections": 20 +} diff --git a/gallery.html b/gallery.html index 1a016d8..f259c66 100644 --- a/gallery.html +++ b/gallery.html @@ -1,70 +1,77 @@ - - - - Screenshots - {{project}} - - -
- -
-
-
-

Screenshots:

- -
-
-
- {{#images}} - {{#dir}} -
- -

/{{#resolve}}{{dir}}{{/resolve}}

-
- {{/dir}} -
-

{{size}}px

-
- - - -

{{#resolve}}{{base}}{{/resolve}}

-
-
- - - -

{{#resolve}}{{compare}}{{/resolve}}

-
-
- - - -

diff

-

{{#contents}}{{diff}}{{/contents}} bytes

-
-
- {{/images}} -
-
-
- - \ No newline at end of file + + + + Screenshots - {{project}} + + +
+ +
+
+
+

Screenshots:

+ +
+
+
+ {{#images}} + {{#dir}} +
+ + +

/{{#resolve}}{{dir}}{{/resolve}}

+
+ {{/dir}} +
+

{{size}}px

+ +
+ + + + +

{{#resolve}}{{base}}{{/resolve}}

+
+
+ + + + +

{{#resolve}}{{compare}}{{/resolve}}

+
+
+ + + + +

diff

+ +

{{#contents}}{{diff}}{{/contents}} bytes

+
+
+ {{/images}} +
+
+
+ + diff --git a/index.js b/index.js index 7c309f6..505d068 100644 --- a/index.js +++ b/index.js @@ -1,55 +1,45 @@ 'use strict'; -var fs = require('fs'), - wraith = require('./lib/wraith'), - spider = require('./lib/spider'); +var fs = require('fs'); +var wraith = require('./lib/wraith'); +var spider = require('./lib/spider'); +var path = require('path'); +var extend = require('util')._extend; module.exports.run = run; function run(configFile) { - var domains = [], - domainLabels = [], - outputFolder = '', - baseFolder = process.cwd() + '/'; - - var config = require(baseFolder + 'config/' + configFile + '.json'); - - outputFolder = typeof config.outputDir === 'undefined' ? baseFolder + 'shots/' : baseFolder + 'shots/' + config.outputDir; - - for(var domain in config.domains) { - domains.push(config.domains[domain].replace(/\/+$/, '')); - domainLabels.push(domain); - } - - if( !config.fuzz ) { - config.fuzz = '20%'; - } - - if( !config.maxConnections ) { - config.maxConnections = 20; - } - - if(config.snap) { - config.snap = baseFolder + config.snap; - } else { - config.snap = __dirname + '/snap.js'; - } - - var cb = function() { - console.log('Done'); - }; - - if( config.paths && config.paths.length > 0 ) { - wraith(config, config.engines, domains, config.sizes, domainLabels, outputFolder, cb); - } else if( config.spider ) { - config.spider = baseFolder + config.spider; - if (!fs.existsSync(config.spider)) { - spider(domains[0], config.spider, function() { - wraith(config, config.engines, domains, config.sizes, domainLabels, outputFolder, cb); - }); - } else { - wraith(config, config.engines, domains, config.sizes, domainLabels, outputFolder, cb); - } - } -} \ No newline at end of file + var domains = []; + var domainLabels = []; + var outputFolder = ''; + var baseFolder = process.cwd() + '/'; + + var defaults = require(path.join(baseFolder, "config/defaults.json")); + var config = require(path.join(baseFolder, configFile)); + extend(defaults, config); + + outputFolder = path.join(baseFolder, config.outputDir); + + for (var domain in config.domains) { + domains.push(config.domains[domain].replace(/\/+$/, '')); + domainLabels.push(domain); + } + + var cb = function () { + console.log('Done'); + }; + + if (config.paths && config.paths.length > 0) { + wraith(config, config.engines, domains, config.sizes, domainLabels, outputFolder, cb); + } else if (config.spider) { + config.spider = baseFolder + config.spider; + if (!fs.existsSync(config.spider)) { + spider(domains[0], config.spider, function () { + wraith(config, config.engines, domains, config.sizes, domainLabels, outputFolder, cb); + }); + } else { + wraith(config, config.engines, domains, config.sizes, domainLabels, outputFolder, cb); + } + } +} diff --git a/lib/gallery.js b/lib/gallery.js index aa4cdb9..fd82241 100644 --- a/lib/gallery.js +++ b/lib/gallery.js @@ -3,41 +3,44 @@ var fs = require('fs'); var helpers = require('./helpers'); var mustache = require('mustache'); +var path = require('path') module.exports.generate = generate; function generate(dirs, compareList, outputDir, project, cb) { - compareList = compareList.sort(helpers.sortByProp('sort')); - var template = __dirname + '/../gallery.html', - view = { - 'images' : compareList, - 'dirs': dirs.sort(), - 'project': project, - 'resolve': function() { - return function(text, render) { - var rendered = render(text); - return rendered.replace(///g, '/').replace(outputDir, '').replace(/^\//, ''); - }; - }, - 'contents': function() { - return function(text, render) { - var rendered = render(text); - var output = fs.readFileSync(rendered.replace(///g, '/').replace(/\/\//g,'/'),'utf8'); - return output ? output : 0; - }; - } - }; + compareList = compareList.sort(helpers.sortByProp('sort')); + var template = path.join(__dirname, '/../gallery.html'), + view = { + 'images': compareList, + 'dirs': dirs.sort(), + 'project': project, + 'resolve': function () { + return function (text, render) { + var rendered = render(text); + return rendered.replace(///g, '/').replace(outputDir, '').replace(/^\//, ''); + }; + }, + 'contents': function () { + return function (text, render) { + var rendered = render(text); + var output = fs.readFileSync(rendered.replace(///g, '/').replace(/\/\//g, '/'), 'utf8'); + return output ? output : 0; + }; + } + }; - fs.readFile(template, function (err, data) { - if (err) { throw err; } - var output = mustache.render(data.toString(), view); - fs.writeFile(outputDir + 'gallery.html', output, function(err) { - if(err) { - console.log(err); - } else { - console.log('Gallery generated'); - cb(); - } - }); - }); -} \ No newline at end of file + fs.readFile(template, function (err, data) { + if (err) { + throw err; + } + var output = mustache.render(data.toString(), view); + fs.writeFile(path.join(outputDir, 'gallery.html'), output, function (err) { + if (err) { + console.log(err); + } else { + console.log('Gallery generated'); + cb(); + } + }); + }); +} diff --git a/lib/helpers.js b/lib/helpers.js index 57c9250..861750e 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -4,26 +4,30 @@ var rimraf = require('rimraf'); module.exports.sortByProp = sortByProp; -function sortByProp(prop){ - return function(a,b){ - if( a[prop] > b[prop]){ - return 1; - } else if( a[prop] < b[prop] ) { - return -1; - } - return 0; - }; +function sortByProp(prop) { + return function (a, b) { + if (a[prop] > b[prop]) { + return 1; + } else if (a[prop] < b[prop]) { + return -1; + } + return 0; + }; } module.exports.emptyFolder = emptyFolder; function emptyFolder(folder, cb) { - if( typeof(folder) === 'undefined' ) { return false; } + if (typeof(folder) === 'undefined') { + return false; + } - rimraf(folder, function(err) { - if( err ) { throw err; } - cb(); - }); + rimraf(folder, function (err) { + if (err) { + throw err; + } + cb(); + }); - return true; -} \ No newline at end of file + return true; +} diff --git a/lib/screenshot.js b/lib/screenshot.js index aeab6f9..51151de 100644 --- a/lib/screenshot.js +++ b/lib/screenshot.js @@ -6,9 +6,9 @@ module.exports.compare = compare; module.exports.take = take; function take(engine, snapFile, url, size, output, callback) { - exec(engine + ' ' + snapFile + ' ' + url + ' ' + size + ' ' + output, callback); + exec(engine + ' ' + snapFile + ' ' + url + ' ' + size + ' ' + output, callback); } function compare(base, compare, output, info, fuzz, callback) { - exec('compare -quiet -fuzz ' + fuzz + ' -metric AE -highlight-color blue ' + base + ' ' + compare + ' ' + output + ' 2>' + info, callback); -} \ No newline at end of file + exec('compare -quiet -fuzz ' + fuzz + ' -metric AE -highlight-color blue ' + base + ' ' + compare + ' ' + output + ' 2>' + info, callback); +} diff --git a/lib/spider.js b/lib/spider.js index cc2a04e..5e8c327 100644 --- a/lib/spider.js +++ b/lib/spider.js @@ -1,54 +1,56 @@ 'use strict'; -var fs = require('fs'), - mkdirp = require('mkdirp'), - crawl = require('crawl'); +var fs = require('fs'); +var mkdirp = require('mkdirp'); +var crawl = require('crawl'); module.exports = spider; function spider(url, file, callback) { - console.log('Crawl of ' + url + ' started'); - - crawl.crawl(url, { headers: false, body: false }, function(err, pages) { - - if (err) { - console.error('An error occured', err); - return; - } - - var txt = '', - pagesLength = pages.length, - link = ''; - - for(var i = 0; i 0 ) { - - var folders = file.split('/'); - folders.pop(); - folders = folders.join('/'); - - mkdirp(folders, function (err) { - if (err) { throw err; } - fs.writeFile(file, txt, function(err) { - if(err) { - console.log(err); - } else { - console.log('Spider file saved to ' + file); - callback(); - } - }); - }); - } else { - console.log('No urls found'); - } - }); -} \ No newline at end of file + console.log('Crawl of ' + url + ' started'); + + crawl.crawl(url, {headers: false, body: false}, function (err, pages) { + + if (err) { + console.error('An error occured', err); + return; + } + + var txt = '', + pagesLength = pages.length, + link = ''; + + for (var i = 0; i < pagesLength; i++) { + link = pages[i].url; + var excPattern = new RegExp('.(css|js|jpg|jpeg|png|pdf|doc|xls|xlsx|ppt|txt|gif|swf|svg|ttf|otf|woff|json|xml)+$'); + if (link.indexOf(url) === 0 && !link.match(excPattern)) { + txt += link.replace(url, '') + '\n'; + } + } + txt = txt.trim(); + + if (txt.length > 0) { + + var folders = file.split('/'); + folders.pop(); + folders = folders.join('/'); + + mkdirp(folders, function (err) { + if (err) { + throw err; + } + fs.writeFile(file, txt, function (err) { + if (err) { + console.log(err); + } else { + console.log('Spider file saved to ' + file); + callback(); + } + }); + }); + } else { + console.log('No urls found'); + } + }); +} diff --git a/lib/wraith.js b/lib/wraith.js index f583bcc..33b7ea9 100644 --- a/lib/wraith.js +++ b/lib/wraith.js @@ -1,136 +1,139 @@ 'use strict'; -var fs = require('fs'), - async = require('async'), - mkdirp = require('mkdirp'), - gallery = require('./gallery'), - screenshot = require('./screenshot'), - helpers = require('./helpers'); +var fs = require('fs'); +var path = require('path'); +var async = require('async'); +var mkdirp = require('mkdirp'); +var gallery = require('./gallery'); +var screenshot = require('./screenshot'); +var helpers = require('./helpers'); module.exports = wraith; function wraith(config, engines, domains, sizes, domainLabels, outputFolder, cb) { - var imageUrls = [], - image = '', - folder = '', - dirs = [], - urls; - - if( typeof config.paths !== 'undefined' && config.paths.length > 0 ) { - urls = config.paths; - } else { - urls = fs.readFileSync(config.spider, 'utf8').split('\n'); - } - - if( urls.length > 0 ) { - - helpers.emptyFolder(outputFolder, function () { - - console.log('Cleaned up old folders and files'); - - var foldersQueue = async.queue(function(folder, callback) { - mkdirp(folder, function (err) { - if (err) { throw err; } - callback(); - }); - }); - - for(var url in urls) { - folder = outputFolder + urls[url].substring(1).replace(/\/+$/,'') + '/'; - foldersQueue.push(folder); - dirs.push(folder); - } - - foldersQueue.drain = function() { - console.log('New folders created'); - - var screenshotQueue = async.queue(function (task, callback) { - screenshot.take(task.engine, task.snapFile, task.url, task.size, task.output, callback); - }, config.maxConnections); - - var url, size; - - if( engines.length === 1 ) { - for(var domain in domains) { - for(url in urls) { - imageUrls.push(domains[domain] + urls[url]); - folder = outputFolder + urls[url].substring(1).replace(/\/+$/,'') + '/'; - for(size in sizes) { - image = folder + domainLabels[domain] + '_' + sizes[size] + '.png'; - screenshotQueue.push({ - engine: engines[0], - snapFile: config.snap, - url: domains[domain] + urls[url], - size: sizes[size], - output: image - }); - } - } - } - } else { - for(url in urls) { - for(var engine in engines) { - imageUrls.push(domains[0] + urls[url]); - folder = outputFolder + urls[url].substring(1).replace(/\/+$/,'') + '/'; - for(size in sizes) { - image = folder + engines[engine] + '_' + sizes[size] + '.png'; - screenshotQueue.push({ - engine: engines[engine], - snapFile: config.snap, - url: domains[0] + urls[url], - size: sizes[size], - output: image - }); - } - } - } - } - - screenshotQueue.drain = function() { - console.log('Screenshots done'); - - var compareQueue = async.queue(function(task, callback) { - screenshot.compare(task.base, task.compare, task.output, task.diff, task.fuzz, callback); - }, config.maxConnections); - - folder = ''; - var fileLabels = [], compareList = [], item; - - if( engines.length === 1 ) { - fileLabels = [domainLabels[0], domainLabels[1]]; - } else { - fileLabels = [engines[0], engines[1]]; - } - - for(var url in urls) { - var dir = urls[url].substring(1).replace(/\/+$/,'') + '/'; - folder = outputFolder + dir; - for(var size in sizes) { - item = { - 'dir': ( size > 0 ? false : folder), - 'sort': folder + size, - 'base': folder + fileLabels[0] + '_' + sizes[size] + '.png', - 'compare': folder + fileLabels[1] + '_' + sizes[size] + '.png', - 'output': folder + sizes[size] + '_diff.png', - 'diff': folder + sizes[size] + '_diff.txt', - 'fuzz': config.fuzz, - 'size': sizes[size] - }; - compareQueue.push(item); - compareList.push(item); - } - } - - compareQueue.drain = function(){ - console.log('Image comparison done'); - gallery.generate(dirs, compareList, outputFolder, config.project, cb); - }; - }; - }; - }); - } else { - console.log('No url(s) provided'); - return false; - } -} \ No newline at end of file + var imageUrls = [], + image = '', + folder = '', + dirs = [], + urls; + + if (typeof config.paths !== 'undefined' && config.paths.length > 0) { + urls = config.paths; + } else { + urls = fs.readFileSync(config.spider, 'utf8').split('\n'); + } + + if (urls.length > 0) { + + helpers.emptyFolder(outputFolder, function () { + + console.log('Cleaned up old folders and files'); + + var foldersQueue = async.queue(function (folder, callback) { + mkdirp(folder, function (err) { + if (err) { + throw err; + } + callback(); + }); + }); + + for (var url in urls) { + folder = path.join(outputFolder, urls[url].substring(1).replace(/\/+$/, '') + '/'); + foldersQueue.push(folder); + dirs.push(folder); + } + + foldersQueue.drain = function () { + console.log('New folders created'); + + var screenshotQueue = async.queue(function (task, callback) { + screenshot.take(task.engine, task.snapFile, task.url, task.size, task.output, callback); + }, config.maxConnections); + + var url, size; + + if (engines.length === 1) { + for (var domain in domains) { + for (url in urls) { + imageUrls.push(domains[domain] + urls[url]); + folder = path.join(outputFolder, urls[url].substring(1).replace(/\/+$/, '') + '/'); + for (size in sizes) { + image = folder + domainLabels[domain] + '_' + sizes[size] + '.png'; + screenshotQueue.push({ + engine: engines[0], + snapFile: config.snap, + url: domains[domain] + urls[url], + size: sizes[size], + output: image + }); + } + } + } + } else { + for (url in urls) { + for (var engine in engines) { + imageUrls.push(domains[0] + urls[url]); + folder = path.join(outputFolder, urls[url].substring(1).replace(/\/+$/, '') + '/'); + for (size in sizes) { + image = folder + engines[engine] + '_' + sizes[size] + '.png'; + screenshotQueue.push({ + engine: engines[engine], + snapFile: config.snap, + url: domains[0] + urls[url], + size: sizes[size], + output: image + }); + } + } + } + } + + screenshotQueue.drain = function () { + console.log('Screenshots done'); + + var compareQueue = async.queue(function (task, callback) { + screenshot.compare(task.base, task.compare, task.output, task.diff, task.fuzz, callback); + }, config.maxConnections); + + folder = ''; + var fileLabels = [], compareList = [], item; + + if (engines.length === 1) { + fileLabels = [domainLabels[0], domainLabels[1]]; + } else { + fileLabels = [engines[0], engines[1]]; + } + + for (var url in urls) { + var dir = urls[url].substring(1).replace(/\/+$/, '') + '/'; + folder = path.join(outputFolder, dir); + for (var size in sizes) { + item = { + 'dir': ( size > 0 ? false : folder), + 'sort': folder + size, + 'base': folder + fileLabels[0] + '_' + sizes[size] + '.png', + 'compare': folder + fileLabels[1] + '_' + sizes[size] + '.png', + 'output': folder + sizes[size] + '_diff.png', + 'diff': folder + sizes[size] + '_diff.txt', + 'fuzz': config.fuzz, + 'size': sizes[size] + }; + compareQueue.push(item); + compareList.push(item); + } + } + + compareQueue.drain = function () { + console.log('Image comparison done'); + gallery.generate(dirs, compareList, outputFolder, config.project, cb); + }; + }; + }; + }); + } else { + console.log('No url(s) provided'); + return false; + } +} diff --git a/package.json b/package.json index 998b66a..e28ea45 100644 --- a/package.json +++ b/package.json @@ -1,53 +1,68 @@ { - "name": "wraith", - "version": "1.0.0", - "description": "A responsive screenshot comparison tool. Based on the Ruby version available at http://github.comm/BBC-News/wraith", - "license": "MIT", - "repository": "jamesryanbell/node-wraith", - "bin": { - "wraith": "cli.js" - }, - "author": { - "name": "James Bell", - "email": "james@james-bell.co.uk", - "url": "http://james-bell.co.uk" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": {}, - "files": [ - "index.js", - "cli.js", - "lib/*", - "gallery.html", - "snap.js" - ], - "keywords": [ - "page", - "website", - "site", - "web", - "url", - "resolution", - "size", - "screenshot", - "screen", - "responsive", - "cli", - "wraith", - "phantomjs", - "triflejs", - "slimerjs" - ], - "dependencies": { - "chalk": "~0.4.0", - "nopt": "~2.1.2", - "crawl": "~0.3.1", - "async": "~0.2.10", - "mkdirp": "~0.3.5", - "mustache": "~0.8.1", - "rimraf": "~2.2.6" - }, - "devDependencies": {} + "name": "wraith", + "version": "1.0.2", + "description": "A responsive screenshot comparison tool. Based on the Ruby version available at http://github.comm/BBC-News/wraith", + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/rcline/node-wraith" + }, + "bin": { + "wraith": "cli.js" + }, + "author": { + "name": "James Bell", + "email": "james@james-bell.co.uk", + "url": "http://james-bell.co.uk" + }, + "engines": { + "node": ">=0.10.0" + }, + "scripts": {}, + "files": [ + "index.js", + "cli.js", + "lib/*", + "gallery.html", + "snap.js" + ], + "keywords": [ + "page", + "website", + "site", + "web", + "url", + "resolution", + "size", + "screenshot", + "screen", + "responsive", + "cli", + "wraith", + "phantomjs", + "triflejs", + "slimerjs" + ], + "dependencies": { + "chalk": "~0.4.0", + "nopt": "~2.1.2", + "crawl": "~0.3.1", + "async": "~0.2.10", + "mkdirp": "~0.3.5", + "mustache": "~0.8.1", + "rimraf": "~2.2.6" + }, + "devDependencies": {}, + "readme": "# Wraith\nA responsive screenshot comparison tool.\nBased on the Ruby version available at [http://github.com/BBC-News/wraith](http://github.com/BBC-News/wraith)\n\n## CLI app\n\n### Install\n\n```\n\tnpm install --global wraith\n```\n\n###Usage\n\n\tUsage:\n\twraith --config \n\n\tOptions:\n\t-h, --help\t\tOutput help information\n\t--v, --version\tOutput version information\n\n\tExamples:\n\twraith --config ./config/chrome.json\n\n### Configuration file\n\nWraith uses a json based configuration file that allows you specify a large number of options. You can create as many configurations files as you need and call them from the cli using the --config flag. These configuration files can live anywhere that is addressable by a local path and they are passed as an argument like this:\n\n wraith --config ./path/to/my_config.json\n\nBelow is an example configuration file:\n\n\t{\n\t\t\"project\": \"Test\", (Optional name for the project, if supplied it will be used within the generated gallery only)\n\n\t\tSpecify one or two domains\n\t\t\"domains\": {\n\t\t\t\"bbb.co.uk\": \"http://www.bbc.co.uk\",\n\t\t\t\"live.bbc.co.uk\": \"http://live.bbc.co.uk\"\n\t\t},\n\n\t\tEngines supported are phantomjs, slimerjs and triflejs but in theory any phantomjs based headless browser can be supported via a custom snap.js file\n\t\t\"engines\" : [\n\t\t\t\"phantomjs\"\n\t\t],\n\n\t\tSpecify as many sizes as you wish\n\t\t\"sizes\": [\n\t\t\t\"320\",\n\t\t\t\"768\",\n\t\t\t\"1440\"\n\t\t],\n\n\t\t\"outputDir\": \"test/chrome/\", (defaults to \"shots\")\n\n\t\tYou can choose to specfiy a list of paths to be used or you can crawl the site. If paths are provided they will take precident and the spider file will be ignored.\n\n\t\t\"paths\": [\n\t\t\t\"/\",\n\t\t\t\"/news/\",\n\t\t\t\"/news/local/\",\n\t\t\t\"/news/england/york_and_north_yorkshire/\",\n\t\t\t\"/weather/\"\n\t\t],\n\n\t\tIf no paths are specified then a site crawl will take place and the results will be save in the location specified within this option\n\t\t\"spider\": \"spider/test.txt\", (Specify which file should be used for the spider txt file)\n\n\t\t\"snap\": \"snap/test/chrome.js\", (Specify snap.js which is used to take the screenshots)\n\t\t\"fuzz\": \"20%\", (Adjusts the sensitivity of the image comparison)\n\t\t\"maxConnections\": 20 (Limit the amount of concurrent processes)\n\t}\n\n## External Dependencies\nWraith requires [phantomjs](http://phantomjs.org/) & [imagemagick](http://www.imagemagick.org/) to be installed. On OS X this can easily be done with `npm install phantomjs` and `brew install imagemagick`.\n\n## License\n\nMIT © [James Bell](http://james-bell.co.uk)\n", + "readmeFilename": "readme.md", + "bugs": { + "url": "https://github.com/rcline/node-wraith/issues" + }, + "homepage": "https://github.com/rcline/node-wraith", + "_id": "wraith@1.0.2", + "dist": { + "shasum": "6fe7dcbc35f8d4e3d5df72d796dd500ae8a84591" + }, + "_resolved": "git+https://github.com/rcline/node-wraith.git#96e70c3c85256859c240b99ffa648ddfec8870c1", + "_from": "wraith@git+https://github.com/rcline/node-wraith.git#master" } diff --git a/readme.md b/readme.md index ef407cd..7098fa2 100644 --- a/readme.md +++ b/readme.md @@ -20,55 +20,19 @@ Based on the Ruby version available at [http://github.com/BBC-News/wraith](http: --v, --version Output version information Examples: - wraith --config chrome + wraith --config ./config/chrome.json ### Configuration file -Wraith uses a json based configuration file that allows you specfify a large number of options. You can create as many configurations files as you need and call them from the cli using the --config flag. All congiguration files must be stored within the config folder. +Wraith uses a json based configuration file that allows you specify a large number of options. You can create as many configurations files as you need and call them from the cli using the --config flag. These configuration files can live anywhere that is addressable by a local path and they are passed as an argument like this: -Below is an example configuration file: + wraith --config ./path/to/my_config.json - { - "project": "Test", (Optional name for the project, if supplied it will be used within the generated gallery only) +Here is an example configuration file: [config.example.json](https://github.com/rcline/node-wraith/blob/master/config/config.example.json) - Specify one or two domains - "domains": { - "bbb.co.uk": "http://www.bbc.co.uk", - "live.bbc.co.uk": "http://live.bbc.co.uk" - }, - - Engines supported are phantomjs, slimerjs and triflejs but in theory any phantomjs based headless browser can be supported via a custom snap.js file - "engines" : [ - "phantomjs" - ], - - Specify as many sizes as you wish - "sizes": [ - "320", - "768", - "1440" - ], - - "outputDir": "test/chrome/", (Output directory within the /shots directory) - - You can choose to specfiy a list of paths to be used or you can crawl the site. If paths are provided they will take precident and the spider file will be ignored. - - "paths": [ - "/", - "/news/", - "/news/local/", - "/news/england/york_and_north_yorkshire/", - "/weather/" - ], - - If no paths are specified then a site crawl will take place and the results will be save in the location specified within this option - "spider": "spider/test.txt", (Specify which file should be used for the spider txt file) - - "snap": "snap/test/chrome.js", (Specify snap.js which is used to take the screenshots) - "fuzz": "20%", (Adjusts the sensitivity of the image comparison) - "maxConnections": 20 (Limit the amount of concurrent processes) - } +## External Dependencies +Wraith requires [phantomjs](http://phantomjs.org/) & [imagemagick](http://www.imagemagick.org/) to be installed. On OS X this can easily be done with `npm install phantomjs` and `brew install imagemagick`. ## License -MIT © [James Bell](http://james-bell.co.uk) \ No newline at end of file +MIT © [James Bell](http://james-bell.co.uk) diff --git a/snap.js b/snap.js index 65c1992..8be4811 100644 --- a/snap.js +++ b/snap.js @@ -14,8 +14,8 @@ var current_requests = 0; var last_request_timeout; var final_timeout; -page.viewportSize = { width: view_port_width, height: 2000}; -page.settings = { loadImages: true, javascriptEnabled: true }; +page.viewportSize = {width: view_port_width, height: 2000}; +page.settings = {loadImages: true, javascriptEnabled: true}; // If you want to use additional phantomjs commands, place them here //page.settings.userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.17'; @@ -40,55 +40,55 @@ page.settings = { loadImages: true, javascriptEnabled: true }; // 'domain': '.bbc.co.uk' // }); -page.onResourceRequested = function(req) { - current_requests += 1; +page.onResourceRequested = function (req) { + current_requests += 1; }; //TrifleJS only /*page.onLoadFinished = function(status) { - if (status == 'success') { - current_requests -= 1; - debounced_render(); - } -};*/ + if (status == 'success') { + current_requests -= 1; + debounced_render(); + } + };*/ //SlimerJS or PhantomJS -page.onResourceReceived = function(res) { - if (res.stage === 'end') { - current_requests -= 1; - debounced_render(); - } +page.onResourceReceived = function (res) { + if (res.stage === 'end') { + current_requests -= 1; + debounced_render(); + } }; -page.open(url, function(status) { - if (status !== 'success') { - console.log('Error with page ' + url); - phantom.exit(); - } else { - } +page.open(url, function (status) { + if (status !== 'success') { + console.log('Error with page ' + url); + phantom.exit(); + } else { + } }); function debounced_render() { - clearTimeout(last_request_timeout); - clearTimeout(final_timeout); - - // If there's no more ongoing resource requests, wait for 1 second before - // rendering, just in case the page kicks off another request - if (current_requests < 1) { - clearTimeout(final_timeout); - last_request_timeout = setTimeout(function() { - console.log('Snapping ' + url + ' at width ' + view_port_width); - page.render(image_name); - phantom.exit(); - }, 1000); - } - - // Sometimes, straggling requests never make it back, in which - // case, timeout after 5 seconds and render the page anyway - final_timeout = setTimeout(function() { - console.log('Snapping ' + url + ' at width ' + view_port_width); - page.render(image_name); - phantom.exit(); - }, 5000); -} \ No newline at end of file + clearTimeout(last_request_timeout); + clearTimeout(final_timeout); + + // If there's no more ongoing resource requests, wait for 1 second before + // rendering, just in case the page kicks off another request + if (current_requests < 1) { + clearTimeout(final_timeout); + last_request_timeout = setTimeout(function () { + console.log('Snapping ' + url + ' at width ' + view_port_width); + page.render(image_name); + phantom.exit(); + }, 1000); + } + + // Sometimes, straggling requests never make it back, in which + // case, timeout after 5 seconds and render the page anyway + final_timeout = setTimeout(function () { + console.log('Snapping ' + url + ' at width ' + view_port_width); + page.render(image_name); + phantom.exit(); + }, 5000); +}