mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-28 17:02:24 -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",
|
||||
"acorn": "~0.5.0",
|
||||
"qunit": "~1.20.0",
|
||||
"resemblejs": "~2.0.1",
|
||||
"stats.js": "r14"
|
||||
},
|
||||
"keywords": [
|
||||
|
|
|
@ -1564,6 +1564,7 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
|||
* raster.scale(5);
|
||||
*/
|
||||
rasterize: function(resolution, insert) {
|
||||
// TODO: Switch to options object for more descriptive call signature.
|
||||
var bounds = this.getStrokeBounds(),
|
||||
scale = (resolution || this.getView().getResolution()) / 72,
|
||||
// Floor top-left corner and ceil bottom-right corner, to never
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<title>Paper.js Tests</title>
|
||||
<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/resemblejs/resemble.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="tests/load.js"></script>
|
||||
|
|
|
@ -21,6 +21,15 @@ QUnit.begin(function() {
|
|||
QUnit.config.hidepassed = true;
|
||||
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.
|
||||
|
@ -48,26 +57,71 @@ function compareProperties(actual, expected, properties, message, options) {
|
|||
}
|
||||
|
||||
function compareItem(actual, expected, message, options, properties) {
|
||||
if (options && options.cloned)
|
||||
QUnit.notStrictEqual(actual.id, 'not ' + expected.id, message + '.id');
|
||||
QUnit.strictEqual(actual.constructor, expected.constructor,
|
||||
message + '.constructor');
|
||||
equals(actual.name,
|
||||
// When item was cloned and had a name, the name will be versioned
|
||||
options && options.cloned && expected.name
|
||||
? expected.name + ' 1' : expected.name,
|
||||
message + '.name');
|
||||
compareProperties(actual, expected, ['children', 'bounds', 'position',
|
||||
'matrix', 'data', 'opacity', 'locked', 'visible', 'blendMode',
|
||||
'selected', 'fullySelected', 'clipMask', 'guide'],
|
||||
message, options);
|
||||
if (properties)
|
||||
compareProperties(actual, expected, properties, message, options);
|
||||
// Style
|
||||
compareProperties(actual.style, expected.style, ['fillColor', 'strokeColor',
|
||||
'strokeCap', 'strokeJoin', 'dashArray', 'dashOffset', 'miterLimit',
|
||||
'fontSize', 'font', 'leading', 'justification'],
|
||||
message + '.style', options);
|
||||
|
||||
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)
|
||||
QUnit.notStrictEqual(actual.id, expected.id,
|
||||
'not ' + message + '.id');
|
||||
QUnit.strictEqual(actual.constructor, expected.constructor,
|
||||
message + '.constructor');
|
||||
// When item is cloned and has a name, the name will be versioned:
|
||||
equals(actual.name,
|
||||
options && options.cloned && expected.name
|
||||
? expected.name + ' 1' : expected.name,
|
||||
message + '.name');
|
||||
compareProperties(actual, expected, ['children', 'bounds', 'position',
|
||||
'matrix', 'data', 'opacity', 'locked', 'visible', 'blendMode',
|
||||
'selected', 'fullySelected', 'clipMask', 'guide'],
|
||||
message, options);
|
||||
if (properties)
|
||||
compareProperties(actual, expected, properties, message, options);
|
||||
// Style
|
||||
compareProperties(actual.style, expected.style, ['fillColor',
|
||||
'strokeColor', 'strokeCap', 'strokeJoin', 'dashArray',
|
||||
'dashOffset', 'miterLimit', 'fontSize', 'font', 'leading',
|
||||
'justification'], message + '.style', options);
|
||||
}
|
||||
}
|
||||
|
||||
// A list of comparator functions, based on `expected` type. See equals() for
|
||||
|
|
|
@ -27,7 +27,14 @@ test('path.unite(); #609', function() {
|
|||
path2.closePath();
|
||||
|
||||
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() {
|
||||
|
@ -50,6 +57,12 @@ test('ring.subtract(square); #610', function() {
|
|||
|
||||
var ring = outer.subtract(inner);
|
||||
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