Skip to content

Commit 35e3024

Browse files
committed
Add UprightDiff support and render pages serially
* Render pages one after the other, rather than sending navigation commands immediately, to prevent Phantom navigating away from the page being viewed before the screenshot is done. This is not too inefficient since images are cached between the two views. * Add a configurable delay between the page load event and the screenshot, to allow scripts to run on load. * Start Phantom in debug mode, since that gives lots of useful output. * Allow UprightDiff to be used, instead of resemble
1 parent b176280 commit 35e3024

File tree

4 files changed

+83
-26
lines changed

4 files changed

+83
-26
lines changed

bin/gen.visual_diff.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ if (opts !== null) {
3030
if (!err) {
3131
// analysis stats
3232
console.error("STATS: " + JSON.stringify(data));
33-
34-
// Save the base64 data
35-
var png_data = data.getImageDataUrl("").replace(/^data:image\/png;base64,/, '');
36-
var png_buffer = new Buffer(png_data, 'base64');
37-
fs.writeFileSync(opts.diffFile, png_buffer);
3833
}
3934
});
4035
}

diffserver/diffserver.settings.js.example

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,19 @@ if (typeof module === 'object') {
2727
stylesYamlFile: '../lib/parsoid.custom_styles.yaml',
2828
injectJQuery: true,
2929
},
30+
31+
// Engine for image diffs, may be resemble or uprightdiff
32+
diffEngine: 'resemble',
33+
3034
// resemblejs options
31-
outputSettings: {
35+
resembleSettings: {
3236
errorType: 'movement', // Better error display for making sense of diffs
3337
largeImageThreshold: 0 // Cleaner diff without the skipped pixels grid
3438
},
39+
40+
// UprightDiff options
41+
uprightDiffSettings: {
42+
binary: '/usr/bin/uprightdiff'
43+
},
3544
};
3645
}

lib/differ.js

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
'use strict';
22

3-
var p = require('phantom');
3+
var phantom = require('phantom');
44
var resemble = require('resemble').resemble;
55
var fs = require('fs');
66
var yaml = require('libyaml');
77
var Util = require('./differ.utils.js').Util;
8+
var child_process = require('child_process');
89

910
// Export the differ module
1011
var VisualDiffer = {};
@@ -18,10 +19,11 @@ function testCompletion(browser, cb, opts) {
1819
if (html1.err || html2.err) {
1920
browser.exit();
2021
cb(html1.err || html2.err);
21-
}
22-
if (html1.done && html2.done) {
22+
} else if (html1.done && html2.done) {
2323
browser.exit();
2424
cb();
25+
} else {
26+
cb();
2527
}
2628
}
2729

@@ -86,6 +88,7 @@ VisualDiffer.takeScreenShot = function(browser, logger, cb, opts, htmlOpts) {
8688
}
8789

8890
// Save the screenshot
91+
console.log("Rendering", htmlOpts.screenShot);
8992
page.render(htmlOpts.screenShot, function() {
9093
logger(htmlOpts.name + ' done!');
9194
htmlOpts.done = true;
@@ -97,11 +100,17 @@ VisualDiffer.takeScreenShot = function(browser, logger, cb, opts, htmlOpts) {
97100
);
98101
};
99102

100-
if (htmlOpts.injectJQuery) {
101-
page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', processPage);
102-
} else {
103-
processPage();
104-
}
103+
setTimeout(
104+
function() {
105+
if (htmlOpts.injectJQuery) {
106+
page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js', processPage);
107+
} else {
108+
processPage();
109+
}
110+
},
111+
opts.screenShotDelay
112+
);
113+
105114
});
106115
});
107116
};
@@ -128,12 +137,17 @@ VisualDiffer.takeScreenshots = function(opts, logger, cb) {
128137
// Phantom doesn't like protocols in its proxy ips
129138
// But, node.js request wants http:// proxies ... so dance around all that.
130139
var proxy = (process.env.HTTP_PROXY_IP_AND_PORT || '').replace(/^https?:\/\//, '');
131-
p.create('--ssl-protocol=TLSv1', '--proxy=' + proxy, function (browser) {
132-
// HTML1 screenshot
133-
self.takeScreenShot(browser, logger, cb, opts, opts.html1);
140+
phantom.create('--debug=true', '--ssl-protocol=TLSv1', '--proxy=' + proxy, function (browser) {
141+
function ss1(cb1) {
142+
// HTML1 screenshot
143+
self.takeScreenShot(browser, logger, cb1, opts, opts.html1);
144+
}
134145

135-
// HTML2 screenshot
136-
self.takeScreenShot(browser, logger, cb, opts, opts.html2);
146+
function ss2() {
147+
// HTML2 screenshot
148+
self.takeScreenShot(browser, logger, cb, opts, opts.html2);
149+
}
150+
ss1(ss2);
137151
});
138152
};
139153

@@ -146,14 +160,45 @@ VisualDiffer.genVisualDiff = function(opts, logger, cb) {
146160
if (logger) {
147161
logger('--screenshotting done--');
148162
}
149-
if (opts.outputSettings) {
150-
resemble.outputSettings(opts.outputSettings);
163+
if (opts.diffEngine == "uprightdiff") {
164+
VisualDiffer.compareWithUprightDiff(opts, logger, cb);
165+
} else {
166+
VisualDiffer.compareWithResemble(opts, logger, cb);
151167
}
152-
resemble(opts.html1.screenShot).compareTo(opts.html2.screenShot).
153-
ignoreAntialiasing(). // <-- muy importante
154-
onComplete(function(data){
155-
cb(null, data);
156-
});
157168
}
158169
});
159170
};
171+
172+
VisualDiffer.compareWithResemble = function(opts, logger, cb) {
173+
if (opts.outputSettings) {
174+
resemble.outputSettings(opts.outputSettings);
175+
}
176+
177+
178+
resemble(opts.html1.screenShot).compareTo(opts.html2.screenShot).
179+
ignoreAntialiasing(). // <-- muy importante
180+
onComplete(function(data){
181+
var png_data = data.getImageDataUrl("").replace(/^data:image\/png;base64,/, '');
182+
var png_buffer = new Buffer(png_data, 'base64');
183+
fs.writeFileSync(opts.diffFile, png_buffer);
184+
cb(null, data);
185+
});
186+
};
187+
188+
VisualDiffer.compareWithUprightDiff = function(opts, logger, cb) {
189+
child_process.execFile('/usr/local/bin/uprightdiff',
190+
[
191+
'--format=json',
192+
opts.html1.screenShot, opts.html2.screenShot, opts.diffFile
193+
],
194+
function (error, stdout, stderr) {
195+
if (error && error.code !== 0) {
196+
error.stderr = stderr;
197+
logger("UprightDiff exited with error: " + JSON.stringify(error));
198+
cb(error, null);
199+
} else {
200+
cb(null, JSON.parse(stdout));
201+
}
202+
}
203+
);
204+
};

lib/differ.utils.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,14 @@ var standardOpts = {
138138
description: 'flat OR movement (Pass-through option to resemble.js -- see resemblejs options)',
139139
'default': "movement",
140140
},
141+
'diffEngine': {
142+
description: "The diff engine to use, may be resemble or uprightdiff",
143+
'default': 'resemble',
144+
},
145+
'screenShotDelay': {
146+
description: "The amount of time (in seconds) to wait after the page load event before capturing a screenshot",
147+
'default': 2,
148+
},
141149
};
142150

143151

0 commit comments

Comments
 (0)