mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Implement item comparison through rasterization and resemble.js diffing, directly integrated into QUnit.
And start using it for boolean operation unit tests.
This commit is contained in:
parent
2596b81616
commit
a1fcaabed6
5 changed files with 92 additions and 22 deletions
|
@ -27,6 +27,7 @@
|
||||||
"straps": "~1.7.2",
|
"straps": "~1.7.2",
|
||||||
"acorn": "~0.5.0",
|
"acorn": "~0.5.0",
|
||||||
"qunit": "~1.20.0",
|
"qunit": "~1.20.0",
|
||||||
|
"resemblejs": "~2.0.1",
|
||||||
"stats.js": "r14"
|
"stats.js": "r14"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
|
@ -1564,6 +1564,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
* raster.scale(5);
|
* raster.scale(5);
|
||||||
*/
|
*/
|
||||||
rasterize: function(resolution, insert) {
|
rasterize: function(resolution, insert) {
|
||||||
|
// TODO: Switch to options object for more descriptive call signature.
|
||||||
var bounds = this.getStrokeBounds(),
|
var bounds = this.getStrokeBounds(),
|
||||||
scale = (resolution || this.getView().getResolution()) / 72,
|
scale = (resolution || this.getView().getResolution()) / 72,
|
||||||
// Floor top-left corner and ceil bottom-right corner, to never
|
// Floor top-left corner and ceil bottom-right corner, to never
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<title>Paper.js Tests</title>
|
<title>Paper.js Tests</title>
|
||||||
<link rel="stylesheet" href="../bower_components/qunit/qunit/qunit.css">
|
<link rel="stylesheet" href="../bower_components/qunit/qunit/qunit.css">
|
||||||
<script type="text/javascript" src="../bower_components/qunit/qunit/qunit.js"></script>
|
<script type="text/javascript" src="../bower_components/qunit/qunit/qunit.js"></script>
|
||||||
|
<script type="text/javascript" src="../bower_components/resemblejs/resemble.js"></script>
|
||||||
<script type="text/javascript" src="js/helpers.js"></script>
|
<script type="text/javascript" src="js/helpers.js"></script>
|
||||||
<script type="text/javascript" src="../src/load.js"></script>
|
<script type="text/javascript" src="../src/load.js"></script>
|
||||||
<script type="text/javascript" src="tests/load.js"></script>
|
<script type="text/javascript" src="tests/load.js"></script>
|
||||||
|
|
|
@ -21,6 +21,15 @@ QUnit.begin(function() {
|
||||||
QUnit.config.hidepassed = true;
|
QUnit.config.hidepassed = true;
|
||||||
document.getElementById('qunit-tests').className += ' hidepass';
|
document.getElementById('qunit-tests').className += ' hidepass';
|
||||||
}
|
}
|
||||||
|
resemble.outputSettings({
|
||||||
|
errorColor: {
|
||||||
|
red: 255,
|
||||||
|
green: 51,
|
||||||
|
blue: 0
|
||||||
|
},
|
||||||
|
errorType: 'flat',
|
||||||
|
transparency: 1
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register a jsDump parser for Base.
|
// Register a jsDump parser for Base.
|
||||||
|
@ -48,12 +57,56 @@ function compareProperties(actual, expected, properties, message, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareItem(actual, expected, message, options, properties) {
|
function compareItem(actual, expected, message, options, properties) {
|
||||||
|
|
||||||
|
function getImageTag(raster) {
|
||||||
|
return '<img width="' + raster.with + '" height="' + raster.height
|
||||||
|
+ '" src="'+ raster.source + '">'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options && options.rasterize) {
|
||||||
|
var resolution = options.rasterize == true ? 72 : options.rasterize;
|
||||||
|
var raster1 = actual && actual.rasterize(resolution, false),
|
||||||
|
raster2 = expected && expected.rasterize(resolution, false);
|
||||||
|
if (!raster1 || !raster2) {
|
||||||
|
QUnit.pushFailure('Unable to compare rasterized items: ' +
|
||||||
|
(!raster1 ? 'actual' : 'expected') + ' item is null',
|
||||||
|
QUnit.stack(2));
|
||||||
|
} else {
|
||||||
|
// Use resemble.js to compare the two rasterized items.
|
||||||
|
var id = QUnit.config.current.testId,
|
||||||
|
result;
|
||||||
|
resemble(raster1.getImageData())
|
||||||
|
.compareTo(raster2.getImageData())
|
||||||
|
// When working with imageData, this call is synchronous:
|
||||||
|
.onComplete(function(data) { result = data; });
|
||||||
|
var identical = result ? 100 - result.misMatchPercentage : 0,
|
||||||
|
ok = identical == 100.0;
|
||||||
|
QUnit.push(ok, identical.toFixed(1) + '% identical',
|
||||||
|
'100.0% identical', message);
|
||||||
|
if (!ok && result) {
|
||||||
|
var output = document.getElementById('qunit-test-output-' + id),
|
||||||
|
bounds = result.diffBounds;
|
||||||
|
output.querySelector('.test-expected td').innerHTML =
|
||||||
|
getImageTag(raster1);
|
||||||
|
var el = output.querySelector('.test-actual td');
|
||||||
|
el.innerHTML = getImageTag(raster2) + '<br>' +
|
||||||
|
el.innerHTML.replace(/<\/?pre>|"/g, '');
|
||||||
|
output.querySelector('.test-diff td').innerHTML =
|
||||||
|
getImageTag({
|
||||||
|
source: result.getImageDataUrl(),
|
||||||
|
width: bounds.right - bounds.left,
|
||||||
|
height: bounds.bottom - bounds.top
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (options && options.cloned)
|
if (options && options.cloned)
|
||||||
QUnit.notStrictEqual(actual.id, 'not ' + expected.id, message + '.id');
|
QUnit.notStrictEqual(actual.id, expected.id,
|
||||||
|
'not ' + message + '.id');
|
||||||
QUnit.strictEqual(actual.constructor, expected.constructor,
|
QUnit.strictEqual(actual.constructor, expected.constructor,
|
||||||
message + '.constructor');
|
message + '.constructor');
|
||||||
|
// When item is cloned and has a name, the name will be versioned:
|
||||||
equals(actual.name,
|
equals(actual.name,
|
||||||
// When item was cloned and had a name, the name will be versioned
|
|
||||||
options && options.cloned && expected.name
|
options && options.cloned && expected.name
|
||||||
? expected.name + ' 1' : expected.name,
|
? expected.name + ' 1' : expected.name,
|
||||||
message + '.name');
|
message + '.name');
|
||||||
|
@ -64,10 +117,11 @@ function compareItem(actual, expected, message, options, properties) {
|
||||||
if (properties)
|
if (properties)
|
||||||
compareProperties(actual, expected, properties, message, options);
|
compareProperties(actual, expected, properties, message, options);
|
||||||
// Style
|
// Style
|
||||||
compareProperties(actual.style, expected.style, ['fillColor', 'strokeColor',
|
compareProperties(actual.style, expected.style, ['fillColor',
|
||||||
'strokeCap', 'strokeJoin', 'dashArray', 'dashOffset', 'miterLimit',
|
'strokeColor', 'strokeCap', 'strokeJoin', 'dashArray',
|
||||||
'fontSize', 'font', 'leading', 'justification'],
|
'dashOffset', 'miterLimit', 'fontSize', 'font', 'leading',
|
||||||
message + '.style', options);
|
'justification'], message + '.style', options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A list of comparator functions, based on `expected` type. See equals() for
|
// A list of comparator functions, based on `expected` type. See equals() for
|
||||||
|
|
|
@ -27,7 +27,14 @@ test('path.unite(); #609', function() {
|
||||||
path2.closePath();
|
path2.closePath();
|
||||||
|
|
||||||
var result = path1.unite(path2);
|
var result = path1.unite(path2);
|
||||||
equals(result.pathData, 'M150,150c0,27.61424 -22.38576,50 -50,50c-27.61424,0 -50,-22.38576 -50,-50c0,-27.61424 22.38576,-50 50,-50c27.61424,0 50,22.38576 50,50z', 'result.pathData');
|
result.fillColor = 'blue';
|
||||||
|
|
||||||
|
var expected = new Path({
|
||||||
|
pathData: 'M150,150c0,27.61424 -22.38576,50 -50,50c-27.61424,0 -50,-22.38576 -50,-50c0,-27.61424 22.38576,-50 50,-50c27.61424,0 50,22.38576 50,50z',
|
||||||
|
fillColor: 'blue'
|
||||||
|
});
|
||||||
|
|
||||||
|
equals(result, expected, 'path1.unite(path2);', { rasterize: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ring.subtract(square); #610', function() {
|
test('ring.subtract(square); #610', function() {
|
||||||
|
@ -50,6 +57,12 @@ test('ring.subtract(square); #610', function() {
|
||||||
|
|
||||||
var ring = outer.subtract(inner);
|
var ring = outer.subtract(inner);
|
||||||
var result = ring.subtract(square);
|
var result = ring.subtract(square);
|
||||||
|
result.fillColor = 'blue';
|
||||||
|
|
||||||
equals(result.pathData, 'M-132,0c0,-69.53737 53.7698,-126.51614 122,-131.62689l0,32.12064c-50.53323,5.01724 -90,47.65277 -90,99.50625c0,51.85348 39.46677,94.489 90,99.50625l0,32.12064c-68.2302,-5.11075 -122,-62.08951 -122,-131.62689z');
|
var expected = new Path({
|
||||||
|
pathData: 'M-132,0c0,-69.53737 53.7698,-126.51614 122,-131.62689l0,32.12064c-50.53323,5.01724 -90,47.65277 -90,99.50625c0,51.85348 39.46677,94.489 90,99.50625l0,32.12064c-68.2302,-5.11075 -122,-62.08951 -122,-131.62689z',
|
||||||
|
fillColor: 'blue'
|
||||||
|
});
|
||||||
|
|
||||||
|
equals(result, expected, 'ring.subtract(square);', { rasterize: true });
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue