diff --git a/test/js/helpers.js b/test/js/helpers.js index 9981f272..e4cc2872 100644 --- a/test/js/helpers.js +++ b/test/js/helpers.js @@ -17,8 +17,7 @@ delete window.history; window.history = {}; QUnit.begin(function() { - if (/hidepassed/.test(document.location.href)) { - QUnit.config.hidepassed = true; + if (QUnit.urlParams.hidepassed) { document.getElementById('qunit-tests').className += ' hidepass'; } resemble.outputSettings({ @@ -63,33 +62,55 @@ function compareItem(actual, expected, message, options, properties) { + '" src="'+ raster.source + '">' } + function rasterize(item, group, resolution) { + var raster = null; + if (group) { + group.addChild(item); + raster = group.rasterize(resolution, false); + item.remove(); + } + return raster; + } + 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) { + // In order to properly compare pixel by pixel, we need to put each item + // into a group with a white background of the united dimensions of the + // bounds of both items before rasterizing. + var resolution = options.rasterize == true ? 72 : options.rasterize, + group = actual && expected && new Group({ + insert: false, + children: [ + new Shape.Rectangle({ + rectangle: actual.bounds.unite(expected.bounds), + fillColor: 'white' + }) + ] + }), + actual = rasterize(actual, group, resolution), + expected = rasterize(expected, group, resolution); + if (!actual || !expected) { QUnit.pushFailure('Unable to compare rasterized items: ' + - (!raster1 ? 'actual' : 'expected') + ' item is null', + (!actual ? '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()) + resemble(actual.getImageData()) + .compareTo(expected.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); + ok = identical == 100; + QUnit.push(ok, identical.toFixed(2) + '% identical', + '100.00% identical', message); if (!ok && result) { var output = document.getElementById('qunit-test-output-' + id), bounds = result.diffBounds; output.querySelector('.test-expected td').innerHTML = - getImageTag(raster1); + getImageTag(expected); var el = output.querySelector('.test-actual td'); - el.innerHTML = getImageTag(raster2) + '
' + + el.innerHTML = getImageTag(actual) + '
' + el.innerHTML.replace(/<\/?pre>|"/g, ''); output.querySelector('.test-diff td').innerHTML = getImageTag({ diff --git a/test/tests/Path_Boolean.js b/test/tests/Path_Boolean.js index dcaf5127..312735b1 100644 --- a/test/tests/Path_Boolean.js +++ b/test/tests/Path_Boolean.js @@ -66,3 +66,77 @@ test('ring.subtract(square); #610', function() { equals(result, expected, 'ring.subtract(square);', { rasterize: true }); }); + +test('circle.subtract(arc); #719', function() { + // https://github.com/paperjs/paper.js/issues/719 + var radius = 50; + var circle = new Path.Circle([0, 0], radius); + circle.fillColor = 'blue'; + var arc = new Path.Arc([0, -radius], [radius, 0], [0, radius]) + arc.fillColor = 'blue'; + arc.closed = true; + arc.pivot = arc.bounds.leftCenter; + + var result = circle.subtract(arc); + // Rotate the arc by 180 to receive the expected shape to compare against + arc.rotate(180); + + equals(result, arc, 'circle.subtract(arc);', { rasterize: true }); +}); + +test('compoundPath.intersect(rect);', function() { + var compoundPath = new CompoundPath(); + compoundPath.addChild(new Path.Rectangle(new Point(140, 10), [100, 300])); + compoundPath.addChild(new Path.Rectangle(new Point(150, 80), [50, 80])); + compoundPath.fillColor = 'blue'; + var rect = new Path.Rectangle(new Point(50, 50), [100, 150]); + var result = compoundPath.intersect(rect); + + var expected = new Path({ + pathData: 'M140,50l10,0l0,150l-10,0z', + fillColor: 'blue' + }); + + equals(result, expected, 'compoundPath.intersect(rect);', { rasterize: true }); +}); + +test('multiple exclusions', function() { + var shape0 = new Path.Rectangle({ + insert: false, + point: [304, 226], + size: [328, 328], + fillColor: 'blue' + }); + var shape1 = new Path({ + insert: false, + segments: [ + [213.5, 239], + [476.5, 279], + [716, 233.5], + [469, 74] + ], + closed: true + }); + var res1 = shape0.exclude(shape1); + var shape2 = new Path.Rectangle({ + insert: false, + point: [174, 128], + size: [309, 251] + }); + var res2 = res1.exclude(shape2); + // shape3 + var shape3 = new Path.Rectangle({ + insert: false, + point: [318, 148], + size: [302, 302] + }); + // exclude res2 & shape3 + var result = res2.exclude(shape3); + + var expected = new CompoundPath({ + pathData: 'M304,554l0,-175l14,0l0,71l302,0l0,-198.262l12,-2.27975l0,304.54175z M318,379l165,0l0,-101.23486l137,-26.02714l0,-25.738l-137,0l0,-78l-128.58788,0l-36.41212,23.51468l0,54.48532l165,0l0,51.76514l-6.5,1.23486l-158.5,-24.10646z M174,379l0,-251l211.38182,0l-30.9697,20l-36.41212,0l0,23.51468l-104.5,67.48532l90.5,13.76426l0,-26.76426l14,0l0,28.89354l-14,-2.12928l0,126.23574z M385.38182,128l83.61818,-54l114.59561,74l-100.59561,0l0,-20z M583.59561,148l36.40439,23.5081l0,-23.5081z M620,171.5081l96,61.9919l-84,15.95825l0,-23.45825l-12,0z', + fillColor: 'blue' + }); + + equals(result, expected, 'res2.exclude(shape3);', { rasterize: true }); +})