mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Tests: Improve QUnit test logging and various cleanup on helpers.
This commit is contained in:
parent
f7053689bc
commit
e0429f44df
5 changed files with 215 additions and 194 deletions
|
@ -13,16 +13,7 @@
|
||||||
var gulp = require('gulp'),
|
var gulp = require('gulp'),
|
||||||
gulp_qunit = require('gulp-qunit'),
|
gulp_qunit = require('gulp-qunit'),
|
||||||
node_qunit = require('qunit'),
|
node_qunit = require('qunit'),
|
||||||
gutil = require('gulp-util'),
|
gutil = require('gulp-util');
|
||||||
extend = require('extend'),
|
|
||||||
minimist = require('minimist');
|
|
||||||
|
|
||||||
// Support simple command line options to pass on to test:node, to display
|
|
||||||
// errors selectively, e.g.:
|
|
||||||
// gulp test:node --assertions
|
|
||||||
var options = minimist(process.argv.slice(2), {
|
|
||||||
boolean: true
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test', ['test:browser']);
|
gulp.task('test', ['test:browser']);
|
||||||
|
|
||||||
|
@ -32,12 +23,11 @@ gulp.task('test:browser', ['minify:acorn'], function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test:node', ['minify:acorn'], function(callback) {
|
gulp.task('test:node', ['minify:acorn'], function(callback) {
|
||||||
var name = 'node-qunit';
|
|
||||||
node_qunit.setup({
|
|
||||||
log: extend({ errors: true }, options)
|
|
||||||
});
|
|
||||||
// Use the correct working directory for tests:
|
// Use the correct working directory for tests:
|
||||||
process.chdir('./test');
|
process.chdir('./test');
|
||||||
|
// Deactivate all logging since we're doing our own directly to gutil.log()
|
||||||
|
// from helpers.js
|
||||||
|
node_qunit.setup({ log: {} });
|
||||||
node_qunit.run({
|
node_qunit.run({
|
||||||
maxBlockDuration: 100 * 1000,
|
maxBlockDuration: 100 * 1000,
|
||||||
deps: [
|
deps: [
|
||||||
|
@ -55,24 +45,7 @@ gulp.task('test:node', ['minify:acorn'], function(callback) {
|
||||||
// for the loading, which was requested above.
|
// for the loading, which was requested above.
|
||||||
code: 'load.js'
|
code: 'load.js'
|
||||||
}, function(err, stats) {
|
}, function(err, stats) {
|
||||||
var result;
|
err = err || stats.failed > 0 && 'QUnit assertions failed';
|
||||||
if (err) {
|
callback(err && new gutil.PluginError('node-qunit', err));
|
||||||
result = new gutil.PluginError(name, err);
|
|
||||||
} else {
|
|
||||||
// Imitate the way gulp-qunit formats results and errors.
|
|
||||||
var color = gutil.colors[stats.failed > 0 ? 'red' : 'green'];
|
|
||||||
gutil.log('Took ' + stats.runtime + ' ms to run ' +
|
|
||||||
gutil.colors.blue(stats.assertions) + ' tests. ' +
|
|
||||||
color(stats.passed + ' passed, ' + stats.failed + ' failed.'));
|
|
||||||
if (stats.failed > 0) {
|
|
||||||
err = 'QUnit assertions failed';
|
|
||||||
gutil.log(name + ': ' + gutil.colors.red('✖ ') + err);
|
|
||||||
result = new gutil.PluginError(name, err);
|
|
||||||
} else {
|
|
||||||
gutil.log(name + ': ' + gutil.colors.green('✔ ') +
|
|
||||||
'QUnit assertions all passed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback(result);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
"gulp": "^3.9.0",
|
"gulp": "^3.9.0",
|
||||||
"gulp-cached": "^1.1.0",
|
"gulp-cached": "^1.1.0",
|
||||||
"gulp-jshint": "^2.0.0",
|
"gulp-jshint": "^2.0.0",
|
||||||
"gulp-prepro": "^2.1.0",
|
"gulp-prepro": "^2.2.0",
|
||||||
"gulp-qunit": "git://github.com/lehni/gulp-qunit.git#459c5603ceac460327a40dc89df6f19c786dc61b",
|
"gulp-qunit": "git://github.com/lehni/gulp-qunit.git#459c5603ceac460327a40dc89df6f19c786dc61b",
|
||||||
"gulp-rename": "^1.2.2",
|
"gulp-rename": "^1.2.2",
|
||||||
"gulp-rimraf": "^0.2.0",
|
"gulp-rimraf": "^0.2.0",
|
||||||
|
@ -56,8 +56,7 @@
|
||||||
"jshint": "2.8.x",
|
"jshint": "2.8.x",
|
||||||
"jshint-summary": "^0.4.0",
|
"jshint-summary": "^0.4.0",
|
||||||
"merge-stream": "^1.0.0",
|
"merge-stream": "^1.0.0",
|
||||||
"minimist": "^1.2.0",
|
"prepro": "^2.2.0",
|
||||||
"prepro": "^2.1.0",
|
|
||||||
"qunit": "^0.7.7",
|
"qunit": "^0.7.7",
|
||||||
"qunitjs": "^1.20.0",
|
"qunitjs": "^1.20.0",
|
||||||
"require-dir": "^0.3.0",
|
"require-dir": "^0.3.0",
|
||||||
|
|
358
test/helpers.js
358
test/helpers.js
|
@ -15,8 +15,52 @@ var isNode = typeof global === 'object',
|
||||||
|
|
||||||
if (isNode) {
|
if (isNode) {
|
||||||
root = global;
|
root = global;
|
||||||
// Resemble.js needs the Image constructor this global.
|
// Resemble.js needs the Image constructor global.
|
||||||
global.Image = paper.window.Image;
|
global.Image = paper.window.Image;
|
||||||
|
// Handle logging to gulp directly from here, imitating the way gulp-qunit
|
||||||
|
// logs and formats results and errors:
|
||||||
|
var gutil = require('gulp-util'),
|
||||||
|
colors = gutil.colors,
|
||||||
|
done = false;
|
||||||
|
QUnit.log(function(details) {
|
||||||
|
if (!details.result) {
|
||||||
|
var lines = [
|
||||||
|
colors.red('Test failed') + ': ' + details.module + ': '
|
||||||
|
+ details.name
|
||||||
|
];
|
||||||
|
var line = 'Failed assertion: ' + (details.message || '');
|
||||||
|
if (details.expected !== undefined) {
|
||||||
|
line += ', expected: ' + details.expected + ', but was: '
|
||||||
|
+ details.actual;
|
||||||
|
}
|
||||||
|
lines.push(line);
|
||||||
|
if (details.source) {
|
||||||
|
lines = lines.concat(details.source.split(/\r\n|\n|\r/mg));
|
||||||
|
}
|
||||||
|
lines.forEach(function(line) {
|
||||||
|
gutil.log(line);
|
||||||
|
});
|
||||||
|
} else if (false) {
|
||||||
|
gutil.log(colors.green('Test succeeded') + ': ' + details.module
|
||||||
|
+ ': ' + details.name +': ' + (details.message || ''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
QUnit.done(function(details) {
|
||||||
|
if (done)
|
||||||
|
return;
|
||||||
|
var color = colors[details.failed > 0 ? 'red' : 'green'];
|
||||||
|
gutil.log('Took ' + details.runtime + 'ms to run '
|
||||||
|
+ colors.blue(details.total) + ' tests. ' + color(details.passed
|
||||||
|
+ ' passed, ' + details.failed + ' failed.'));
|
||||||
|
if (details.failed > 0) {
|
||||||
|
gutil.log('node-qunit: ' + gutil.colors.red('✖')
|
||||||
|
+ ' QUnit assertions failed');
|
||||||
|
} else {
|
||||||
|
gutil.log('node-qunit: ' + gutil.colors.green('✔')
|
||||||
|
+ ' QUnit assertions all passed');
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
root = window;
|
root = window;
|
||||||
// This is only required when running in the browser:
|
// This is only required when running in the browser:
|
||||||
|
@ -26,20 +70,10 @@ if (isNode) {
|
||||||
// TODO: Ideally we should fix this in QUnit instead.
|
// TODO: Ideally we should fix this in QUnit instead.
|
||||||
delete window.history;
|
delete window.history;
|
||||||
window.history = {};
|
window.history = {};
|
||||||
|
|
||||||
QUnit.begin(function() {
|
QUnit.begin(function() {
|
||||||
if (QUnit.urlParams.hidepassed) {
|
if (QUnit.urlParams.hidepassed) {
|
||||||
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
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,50 +81,50 @@ if (isNode) {
|
||||||
if (!('Base' in root))
|
if (!('Base' in root))
|
||||||
paper.install(root);
|
paper.install(root);
|
||||||
|
|
||||||
|
// Override console.error, so that we can catch errors that are only logged to
|
||||||
|
// the console.
|
||||||
var errorHandler = console.error;
|
var errorHandler = console.error;
|
||||||
console.error = function() {
|
console.error = function() {
|
||||||
QUnit.pushFailure([].join.call(arguments, ' '), QUnit.config.current.stack);
|
QUnit.pushFailure([].join.call(arguments, ' '), QUnit.config.current.stack);
|
||||||
errorHandler.apply(this, arguments);
|
errorHandler.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QUnit.done(function(details) {
|
||||||
|
console.error = errorHandler;
|
||||||
|
});
|
||||||
|
|
||||||
|
var currentProject,
|
||||||
|
// In case we're stuck with an old QUnit, use a fake assert object with just
|
||||||
|
// the functions that we need:
|
||||||
|
// For now, a async() function returning a done() function:
|
||||||
|
fakeAssert = {
|
||||||
|
async: function() {
|
||||||
|
return function() {
|
||||||
|
QUnit.start();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// NOTE: In order to "export" all methods into the shared Prepro.js scope when
|
// NOTE: In order to "export" all methods into the shared Prepro.js scope when
|
||||||
// using node-qunit, we need to define global functions as:
|
// using node-qunit, we need to define global functions as:
|
||||||
// `var name = function() {}`. `function name() {}` does not work!
|
// `var name = function() {}`. `function name() {}` does not work!
|
||||||
|
|
||||||
var currentProject;
|
|
||||||
|
|
||||||
var test = function(testName, expected) {
|
var test = function(testName, expected) {
|
||||||
var parameters = expected.toString().match(/^\s*function[^\(]*\(([^\)]*)/)[1];
|
|
||||||
// If this is running on an older version of QUnit (e.g. node-qunit is stuck
|
// If this is running on an older version of QUnit (e.g. node-qunit is stuck
|
||||||
// with v1.10 for now), emulate the new assert.async() syntax through
|
// with v1.10 for now), emulate the new assert.async() syntax through
|
||||||
// QUnit.asyncTest() and QUnit.start();
|
// QUnit.asyncTest() and QUnit.start();
|
||||||
if (!QUnit.async && parameters === 'assert') {
|
var emulate = !QUnit.async && 'assert' ===
|
||||||
return QUnit.asyncTest(testName, function() {
|
// Get the parameter list from the passed function to see if we're
|
||||||
// Since tests may be asynchronous, remove the old project before
|
// expecting the assert object to do async...
|
||||||
// running the next test.
|
expected.toString().match(/^\s*function[^\(]*\(([^\)]*)/)[1];
|
||||||
if (currentProject)
|
return QUnit[emulate ? 'asyncTest' : 'test'](testName, function(assert) {
|
||||||
currentProject.remove();
|
// Since tests can be asynchronous, remove the old project before
|
||||||
currentProject = new Project();
|
// running the next test.
|
||||||
// Pass a fake assert object with just the functions that we need,
|
if (currentProject)
|
||||||
// so far a async() function returning a done() function:
|
currentProject.remove();
|
||||||
expected({
|
currentProject = new Project();
|
||||||
async: function() {
|
expected(emulate ? fakeAssert : assert);
|
||||||
return function() {
|
});
|
||||||
QUnit.start();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return QUnit.test(testName, function(assert) {
|
|
||||||
// Since tests may be asynchronous, remove the old project before
|
|
||||||
// running the next test.
|
|
||||||
if (currentProject)
|
|
||||||
currentProject.remove();
|
|
||||||
currentProject = new Project();
|
|
||||||
expected(assert);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Override equals to convert functions to message and execute them as tests()
|
// Override equals to convert functions to message and execute them as tests()
|
||||||
|
@ -140,33 +174,6 @@ var identicalAfterCloning = {
|
||||||
Symbol: true
|
Symbol: true
|
||||||
};
|
};
|
||||||
|
|
||||||
var getFunctionMessage = function(func) {
|
|
||||||
var message = func.toString().match(
|
|
||||||
/^\s*function[^\{]*\{([\s\S]*)\}\s*$/)[1]
|
|
||||||
.replace(/ /g, '')
|
|
||||||
.replace(/^\s+|\s+$/g, '');
|
|
||||||
if (/^return /.test(message)) {
|
|
||||||
message = message
|
|
||||||
.replace(/^return /, '')
|
|
||||||
.replace(/;$/, '');
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
};
|
|
||||||
|
|
||||||
var createSVG = function(str, attrs) {
|
|
||||||
if (attrs) {
|
|
||||||
// Similar to SVGExport's createElement / setAttributes.
|
|
||||||
var node = document.createElementNS('http://www.w3.org/2000/svg', str);
|
|
||||||
for (var key in attrs)
|
|
||||||
node.setAttribute(key, attrs[key]);
|
|
||||||
return node;
|
|
||||||
} else {
|
|
||||||
return new window.DOMParser().parseFromString(
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg">' + str + '</svg>',
|
|
||||||
'text/xml');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register a jsDump parser for Base.
|
// Register a jsDump parser for Base.
|
||||||
QUnit.jsDump.setParser('Base', function (obj, stack) {
|
QUnit.jsDump.setParser('Base', function (obj, stack) {
|
||||||
// Just compare the string representation of classes inheriting from Base,
|
// Just compare the string representation of classes inheriting from Base,
|
||||||
|
@ -191,8 +198,7 @@ var compareProperties = function(actual, expected, properties, message, options)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var compareItem = function(actual, expected, message, options, properties) {
|
var compareRasterized = function(actual, expected, message, options) {
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
function rasterize(item, group, resolution) {
|
function rasterize(item, group, resolution) {
|
||||||
var raster = null;
|
var raster = null;
|
||||||
|
@ -209,92 +215,104 @@ var compareItem = function(actual, expected, message, options, properties) {
|
||||||
+ '" src="' + raster.source + '">';
|
+ '" src="' + raster.source + '">';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.rasterize) {
|
// In order to properly compare pixel by pixel, we need to put each item
|
||||||
// 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
|
||||||
// into a group with a white background of the united dimensions of the
|
// bounds of both items before rasterizing.
|
||||||
// bounds of both items before rasterizing.
|
var resolution = options.rasterize === true ? 72 : options.rasterize,
|
||||||
var resolution = options.rasterize === true ? 72 : options.rasterize,
|
actualBounds = actual.strokeBounds,
|
||||||
actualBounds = actual.strokeBounds,
|
expecedBounds = expected.strokeBounds,
|
||||||
expecedBounds = expected.strokeBounds,
|
bounds = actualBounds.isEmpty()
|
||||||
bounds = actualBounds.isEmpty()
|
? expecedBounds
|
||||||
? expecedBounds
|
: expecedBounds.isEmpty()
|
||||||
: expecedBounds.isEmpty()
|
? actualBounds
|
||||||
? actualBounds
|
: actualBounds.unite(expecedBounds);
|
||||||
: actualBounds.unite(expecedBounds);
|
if (bounds.isEmpty()) {
|
||||||
if (bounds.isEmpty()) {
|
QUnit.push(true, 'empty', 'empty', message);
|
||||||
QUnit.push(true, 'empty', 'empty', message);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
var group = actual && expected && new Group({
|
|
||||||
insert: false,
|
|
||||||
children: [
|
|
||||||
new Shape.Rectangle({
|
|
||||||
rectangle: bounds,
|
|
||||||
fillColor: 'white'
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
actual = rasterize(actual, group, resolution),
|
|
||||||
expected = rasterize(expected, group, resolution);
|
|
||||||
if (!actual || !expected) {
|
|
||||||
QUnit.pushFailure('Unable to compare rasterized items: ' +
|
|
||||||
(!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,
|
|
||||||
index = QUnit.config.current.assertions.length + 1,
|
|
||||||
result;
|
|
||||||
resemble(actual.getImageData())
|
|
||||||
.compareTo(expected.getImageData())
|
|
||||||
// When working with imageData, this call is synchronous:
|
|
||||||
.onComplete(function(data) { result = data; });
|
|
||||||
var tolerance = (options.tolerance || 1e-4) * 100, // percentages...
|
|
||||||
fixed = ((1 / tolerance) + '').length - 1,
|
|
||||||
identical = result ? 100 - result.misMatchPercentage : 0,
|
|
||||||
reached = identical.toFixed(fixed),
|
|
||||||
hundred = (100).toFixed(fixed),
|
|
||||||
ok = reached == hundred;
|
|
||||||
QUnit.push(ok, reached + '% identical', hundred + '% identical',
|
|
||||||
message);
|
|
||||||
if (!ok && result && !isNode) {
|
|
||||||
// Get the right entry for this unit test and assertion, and
|
|
||||||
// replace the results with images
|
|
||||||
var entry = document.getElementById('qunit-test-output-' + id)
|
|
||||||
.querySelector('li:nth-child(' + (index) + ')'),
|
|
||||||
bounds = result.diffBounds;
|
|
||||||
entry.querySelector('.test-expected td').innerHTML =
|
|
||||||
getImageTag(expected);
|
|
||||||
entry.querySelector('.test-actual td').innerHTML =
|
|
||||||
getImageTag(actual);
|
|
||||||
entry.querySelector('.test-diff td').innerHTML = '<pre>' + text
|
|
||||||
+ '</pre><br>'
|
|
||||||
+ '<img src="' + result.getImageDataUrl() + '">';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (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.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);
|
|
||||||
}
|
}
|
||||||
|
var group = actual && expected && new Group({
|
||||||
|
insert: false,
|
||||||
|
children: [
|
||||||
|
new Shape.Rectangle({
|
||||||
|
rectangle: bounds,
|
||||||
|
fillColor: 'white'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
actual = rasterize(actual, group, resolution),
|
||||||
|
expected = rasterize(expected, group, resolution);
|
||||||
|
if (!actual || !expected) {
|
||||||
|
QUnit.pushFailure('Unable to compare rasterized items: ' +
|
||||||
|
(!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,
|
||||||
|
index = QUnit.config.current.assertions.length + 1,
|
||||||
|
result;
|
||||||
|
if (!resemble._setup) {
|
||||||
|
resemble._setup = true;
|
||||||
|
resemble.outputSettings({
|
||||||
|
errorColor: { red: 255, green: 51, blue: 0 },
|
||||||
|
errorType: 'flat',
|
||||||
|
transparency: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resemble(actual.getImageData())
|
||||||
|
.compareTo(expected.getImageData())
|
||||||
|
// When working with imageData, this call is synchronous:
|
||||||
|
.onComplete(function(data) { result = data; });
|
||||||
|
var tolerance = (options.tolerance || 1e-4) * 100, // percentages...
|
||||||
|
fixed = ((1 / tolerance) + '').length - 1,
|
||||||
|
identical = result ? 100 - result.misMatchPercentage : 0,
|
||||||
|
reached = identical.toFixed(fixed),
|
||||||
|
hundred = (100).toFixed(fixed),
|
||||||
|
ok = reached == hundred;
|
||||||
|
QUnit.push(ok, reached + '% identical', hundred + '% identical',
|
||||||
|
message);
|
||||||
|
if (!ok && result && !isNode) {
|
||||||
|
// Get the right entry for this unit test and assertion, and
|
||||||
|
// replace the results with images
|
||||||
|
var entry = document.getElementById('qunit-test-output-' + id)
|
||||||
|
.querySelector('li:nth-child(' + (index) + ')'),
|
||||||
|
bounds = result.diffBounds;
|
||||||
|
entry.querySelector('.test-expected td').innerHTML =
|
||||||
|
getImageTag(expected);
|
||||||
|
entry.querySelector('.test-actual td').innerHTML =
|
||||||
|
getImageTag(actual);
|
||||||
|
entry.querySelector('.test-diff td').innerHTML = '<pre>' + text
|
||||||
|
+ '</pre><br>'
|
||||||
|
+ '<img src="' + result.getImageDataUrl() + '">';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var compareItem = function(actual, expected, message, options, properties) {
|
||||||
|
options = options || {};
|
||||||
|
if (options.rasterize) {
|
||||||
|
return compareRasterized(actual, expected, message, options);
|
||||||
|
}
|
||||||
|
if (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.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
|
// A list of comparator functions, based on `expected` type. See equals() for
|
||||||
|
@ -453,3 +471,33 @@ var comparators = {
|
||||||
message, options);
|
message, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Some other helpers:
|
||||||
|
|
||||||
|
var getFunctionMessage = function(func) {
|
||||||
|
var message = func.toString().match(
|
||||||
|
/^\s*function[^\{]*\{([\s\S]*)\}\s*$/)[1]
|
||||||
|
.replace(/ /g, '')
|
||||||
|
.replace(/^\s+|\s+$/g, '');
|
||||||
|
if (/^return /.test(message)) {
|
||||||
|
message = message
|
||||||
|
.replace(/^return /, '')
|
||||||
|
.replace(/;$/, '');
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createSVG = function(str, attrs) {
|
||||||
|
if (attrs) {
|
||||||
|
// Similar to SVGExport's createElement / setAttributes.
|
||||||
|
var node = document.createElementNS('http://www.w3.org/2000/svg', str);
|
||||||
|
for (var key in attrs)
|
||||||
|
node.setAttribute(key, attrs[key]);
|
||||||
|
return node;
|
||||||
|
} else {
|
||||||
|
return new window.DOMParser().parseFromString(
|
||||||
|
'<svg xmlns="http://www.w3.org/2000/svg">' + str + '</svg>',
|
||||||
|
'text/xml');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,5 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*#*/ include('helpers.js');
|
/*#*/ include('helpers.js');
|
||||||
|
// We need to load resemble.js after helpers.js, since for Node, helpers makes
|
||||||
|
// sure window, document and Image are made global first.
|
||||||
/*#*/ include('../node_modules/resemblejs/resemble.js', { namespace: 'resemble' });
|
/*#*/ include('../node_modules/resemblejs/resemble.js', { namespace: 'resemble' });
|
||||||
/*#*/ include('tests/load.js');
|
/*#*/ include('tests/load.js');
|
||||||
|
|
|
@ -115,8 +115,7 @@ test('Import SVG polyline', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Import complex CompoundPath and clone', function() {
|
test('Import complex CompoundPath and clone', function() {
|
||||||
var svg = createSVG('<path fill="red" d="M4,14h20v-2H4V14z M15,26h7v-2h-7V26z M15,22h9v-2h-9V22z M15,18h9v-2h-9V18z M4,26h9V16H4V26z M28,10V6H0v22c0,0,0,4,4,4 h25c0,0,3-0.062,3-4V10H28z M4,30c-2,0-2-2-2-2V8h24v20c0,0.921,0.284,1.558,0.676,2H4z"/>;');
|
var svg = createSVG('<path fill="red" d="M4,14h20v-2H4V14z M15,26h7v-2h-7V26z M15,22h9v-2h-9V22z M15,18h9v-2h-9V18z M4,26h9V16H4V26z M28,10V6H0v22c0,0,0,4,4,4 h25c0,0,3-0.062,3-4V10H28z M4,30c-2,0-2-2-2-2V8h24v20c0,0.921,0.284,1.558,0.676,2H4z"/>');
|
||||||
var item = paper.project.importSVG(svg.firstChild);
|
var item = paper.project.importSVG(svg);
|
||||||
equals(item.clone(), item, null, { cloned: true });
|
equals(item.clone(), item, null, { cloned: true });
|
||||||
return;
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue