From 4c84c3dad54fc939d16e72a981995eca855aefc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= <juerg@scratchdisk.com> Date: Wed, 27 Jan 2016 19:57:07 +0100 Subject: [PATCH] Tests: Start getting QUnit tests to work on Node.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Work in progress… --- .travis.yml | 3 +- gulp/tasks/test.js | 67 ++++++++- gulp/utils/error.js | 2 +- package.json | 8 +- src/load.js | 2 +- test/{js => }/helpers.js | 213 +++++++++++++++++----------- test/index.html | 9 +- test/load.js | 15 ++ test/tests/Color.js | 5 +- test/tests/CompoundPath.js | 2 +- test/tests/Curve.js | 2 +- test/tests/CurveLocation.js | 2 +- test/tests/Emitter.js | 8 +- test/tests/Group.js | 2 +- test/tests/HitResult.js | 2 +- test/tests/Item.js | 2 +- test/tests/Item_Bounds.js | 4 +- test/tests/Item_Cloning.js | 2 + test/tests/Item_Getting.js | 21 +-- test/tests/Item_Order.js | 2 + test/tests/JSON.js | 2 +- test/tests/Layer.js | 2 +- test/tests/Matrix.js | 3 +- test/tests/Path.js | 2 +- test/tests/PathItem_Contains.js | 2 +- test/tests/Path_Boolean.js | 7 +- test/tests/Path_Bounds.js | 2 +- test/tests/Path_Curves.js | 2 +- test/tests/Path_Drawing_Commands.js | 2 +- test/tests/Path_Intersections.js | 2 +- test/tests/Path_Length.js | 2 +- test/tests/Path_Shapes.js | 2 +- test/tests/PlacedSymbol.js | 2 +- test/tests/Point.js | 5 +- test/tests/Project.js | 2 +- test/tests/Raster.js | 59 +++++--- test/tests/Rectangle.js | 2 +- test/tests/SVGExport.js | 2 +- test/tests/SVGImport.js | 11 +- test/tests/Segment.js | 3 +- test/tests/Shape.js | 2 +- test/tests/Size.js | 3 +- test/tests/Style.js | 2 +- test/tests/TextItem.js | 2 +- 44 files changed, 322 insertions(+), 176 deletions(-) rename test/{js => }/helpers.js (79%) create mode 100644 test/load.js diff --git a/.travis.yml b/.travis.yml index a45680a9..31bc6300 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,5 @@ addons: script: - npm run lint - gulp minify - - gulp test + - gulp test:browser + - gulp test:node diff --git a/gulp/tasks/test.js b/gulp/tasks/test.js index a2ecec31..1c1934ae 100644 --- a/gulp/tasks/test.js +++ b/gulp/tasks/test.js @@ -11,9 +11,68 @@ */ var gulp = require('gulp'), - qunit = require('gulp-qunit'); + gulp_qunit = require('gulp-qunit'), + node_qunit = require('qunit'), + gutil = require('gulp-util'), + extend = require('extend'), + minimist = require('minimist'); -gulp.task('test', function() { - return gulp.src('test/index.html') - .pipe(qunit({ timeout: 20, noGlobals: true })); +// 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:browser', ['minify:acorn'], function() { + return gulp.src('test/index.html') + .pipe(gulp_qunit({ timeout: 20, noGlobals: true })); +}); + +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: + process.chdir('./test'); + node_qunit.run({ + maxBlockDuration: 100 * 1000, + deps: [ + // To dynamically load the tests files from the sources, we need to + // require Prepro.js first. Since we need a sub-module, we have to + // use relative addresses: require('prepro/lib/node') does not work + // because of the way node-qunit handles relative addresses. + '../node_modules/prepro/lib/node.js', + // Note that loading dist/paper-full.js also works in combination + // with `gulp load`, in which case Prepro.js is present and handles + // the loading transparently. + { path: '../dist/paper-full.js', namespace: 'paper' } + ], + // Now load the actual test files through test/load.js, using Prepro.js + // for the loading, which was requested above. + code: 'load.js' + }, function(err, stats) { + var result; + if (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); + }); }); diff --git a/gulp/utils/error.js b/gulp/utils/error.js index 3a404256..c9f0f8a4 100644 --- a/gulp/utils/error.js +++ b/gulp/utils/error.js @@ -18,7 +18,7 @@ gulp.on('error', function(err) { var msg = err.toString(); if (msg === '[object Object]') msg = err; - gutil.log(ERROR, err); + gutil.log(ERROR, msg); if (err.stack) gutil.log(ERROR, err.stack); this.emit('end'); diff --git a/package.json b/package.json index 1a9c3730..03728cf4 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "README.md" ], "engines": { - "node": ">=0.8.0 <5.0.0" + "node": ">=0.8.0 <6.0.0" }, "dependencies": { "jsdom": "git://github.com/lehni/jsdom.git#3d55789d0f4d55392721b1e22890837fde472375", @@ -42,7 +42,7 @@ "gulp": "^3.9.0", "gulp-cached": "^1.1.0", "gulp-jshint": "^2.0.0", - "gulp-prepro": "^2.0.0", + "gulp-prepro": "^2.1.0", "gulp-qunit": "git://github.com/lehni/gulp-qunit.git#459c5603ceac460327a40dc89df6f19c786dc61b", "gulp-rename": "^1.2.2", "gulp-rimraf": "^0.2.0", @@ -56,7 +56,9 @@ "jshint": "2.8.x", "jshint-summary": "^0.4.0", "merge-stream": "^1.0.0", - "prepro": "^2.0.0", + "minimist": "^1.2.0", + "prepro": "^2.1.0", + "qunit": "^0.7.7", "qunitjs": "^1.20.0", "require-dir": "^0.3.0", "resemblejs": "^2.1.0", diff --git a/src/load.js b/src/load.js index d5334e4b..89f90da6 100644 --- a/src/load.js +++ b/src/load.js @@ -45,7 +45,7 @@ if (typeof window === 'object') { } } else { // Node.js based loading through Prepro.js: - var prepro = require('prepro/lib/node.js'), + var prepro = require('prepro/lib/node'), // Load the default browser-based options for further amendments. // Step out and back into src, in case this is loaded from // dist/paper-node.js diff --git a/test/js/helpers.js b/test/helpers.js similarity index 79% rename from test/js/helpers.js rename to test/helpers.js index 181ecf93..446808be 100644 --- a/test/js/helpers.js +++ b/test/helpers.js @@ -10,26 +10,42 @@ * All rights reserved. */ -// Until window.history.pushState() works when running locally, we need to trick -// qunit into thinking that the feature is not present. This appears to work... -// TODO: Ideally we should fix this in QUnit instead. -delete window.history; -window.history = {}; +var isNode = typeof global === 'object', + root; -QUnit.begin(function() { - if (QUnit.urlParams.hidepassed) { - document.getElementById('qunit-tests').className += ' hidepass'; - } - resemble.outputSettings({ - errorColor: { - red: 255, - green: 51, - blue: 0 - }, - errorType: 'flat', - transparency: 1 +if (isNode) { + root = global; + // Resemble.js needs the Image constructor this global. + global.Image = paper.window.Image; +} else { + root = window; + // This is only required when running in the browser: + // Until window.history.pushState() works when running locally, we need to + // trick qunit into thinking that the feature is not present. This appears + // to work... + // TODO: Ideally we should fix this in QUnit instead. + delete window.history; + window.history = {}; + + QUnit.begin(function() { + if (QUnit.urlParams.hidepassed) { + document.getElementById('qunit-tests').className += ' hidepass'; + } + resemble.outputSettings({ + errorColor: { + red: 255, + green: 51, + blue: 0 + }, + errorType: 'flat', + transparency: 1 + }); }); -}); +} + +// The unit-tests expect the paper classes to be global. +if (!('Base' in root)) + paper.install(root); var errorHandler = console.error; console.error = function() { @@ -37,8 +53,48 @@ console.error = function() { errorHandler.apply(this, arguments); }; +// NOTE: In order to "export" all methods into the shared Prepro.js scope when +// using node-qunit, we need to define global functions as: +// `var name = function() {}`. `function name() {}` does not work! + +var currentProject; + +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 + // with v1.10 for now), emulate the new assert.async() syntax through + // QUnit.asyncTest() and QUnit.start(); + if (!QUnit.async && parameters === 'assert') { + return QUnit.asyncTest(testName, function() { + // Since tests may be asynchronous, remove the old project before + // running the next test. + if (currentProject) + currentProject.remove(); + currentProject = new Project(); + // Pass a fake assert object with just the functions that we need, + // so far a async() function returning a done() function: + expected({ + async: function() { + 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() -function equals(actual, expected, message, options) { +var equals = function(actual, expected, message, options) { // Allow the use of functions for actual, which will get called and their // source content extracted for readable reports. if (typeof actual === 'function') { @@ -55,7 +111,7 @@ function equals(actual, expected, message, options) { || type === 'boolean' && 'Boolean' || type === 'undefined' && 'Undefined' || Array.isArray(expected) && 'Array' - || expected instanceof Element && 'Element' // handle DOM Elements + || expected instanceof window.Element && 'Element' // handle DOM Elements || (cls = expected && expected._class) // check _class 2nd last || type === 'object' && 'Object'; // Object as catch-all var comparator = type && comparators[type]; @@ -76,7 +132,40 @@ function equals(actual, expected, message, options) { actual, identical ? expected : 'not ' + expected, message + ': identical after cloning'); } -} +}; + +// A list of classes that should be identical after their owners were cloned. +var identicalAfterCloning = { + Gradient: 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. QUnit.jsDump.setParser('Base', function (obj, stack) { @@ -95,14 +184,15 @@ QUnit.jsDump.setParser('object', function (obj, stack) { : objectParser).call(this, obj, stack); }); -function compareProperties(actual, expected, properties, message, options) { +var compareProperties = function(actual, expected, properties, message, options) { for (var i = 0, l = properties.length; i < l; i++) { var key = properties[i]; equals(actual[key], expected[key], message + '.' + key, options); } -} +}; -function compareItem(actual, expected, message, options, properties) { +var compareItem = function(actual, expected, message, options, properties) { + options = options || {}; function rasterize(item, group, resolution) { var raster = null; @@ -119,7 +209,7 @@ function compareItem(actual, expected, message, options, properties) { + '" src="' + raster.source + '">'; } - if (options && options.rasterize) { + if (options.rasterize) { // 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. @@ -159,11 +249,15 @@ function compareItem(actual, expected, message, options, properties) { .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, - text = identical.toFixed(2) + '% identical'; - QUnit.push(ok, text, '100.00% identical', message); - if (!ok && result) { + 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) @@ -179,14 +273,14 @@ function compareItem(actual, expected, message, options, properties) { } } } else { - if (options && options.cloned) + 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 && options.cloned && expected.name + options.cloned && expected.name ? expected.name + ' 1' : expected.name, message + '.name'); compareProperties(actual, expected, ['children', 'bounds', 'position', @@ -201,7 +295,7 @@ function compareItem(actual, expected, message, options, properties) { 'dashOffset', 'miterLimit', 'fontSize', 'font', 'leading', 'justification'], message + '.style', options); } -} +}; // A list of comparator functions, based on `expected` type. See equals() for // an explanation of how the type is determined. @@ -359,56 +453,3 @@ var comparators = { message, options); } }; - -// A list of classes that should be identical after their owners were cloned. -var identicalAfterCloning = { - Gradient: true, - Symbol: true -}; - -function getFunctionMessage(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; -} - -function test(testName, expected) { - return QUnit.test(testName, function() { - var project = new Project(); - expected(); - project.remove(); - }); -} - -function asyncTest(testName, expected) { - return QUnit.asyncTest(testName, function() { - var project = new Project(); - expected(function() { - project.remove(); - QUnit.start(); - }); - }); -} - -// SVG - -function createSVG(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'); - } -} diff --git a/test/index.html b/test/index.html index c5a88307..3fc6d7b1 100644 --- a/test/index.html +++ b/test/index.html @@ -3,11 +3,10 @@ <head> <title>Paper.js Tests</title> <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css"> - <script type="text/javascript" src="../node_modules/qunitjs/qunit/qunit.js"></script> - <script type="text/javascript" src="../node_modules/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> + <script src="../node_modules/qunitjs/qunit/qunit.js"></script> + <script src="../dist/paper-full.js"></script> + <script src="../node_modules/prepro/lib/browser.js"></script> + <script src="load.js"></script> </head> <body> <h1 id="qunit-header">QUnit Test Suite</h1> diff --git a/test/load.js b/test/load.js new file mode 100644 index 00000000..2a1f3379 --- /dev/null +++ b/test/load.js @@ -0,0 +1,15 @@ +/* + * Paper.js - The Swiss Army Knife of Vector Graphics Scripting. + * http://paperjs.org/ + * + * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey + * http://scratchdisk.com/ & http://jonathanpuckey.com/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * All rights reserved. + */ + +/*#*/ include('helpers.js'); +/*#*/ include('../node_modules/resemblejs/resemble.js', { namespace: 'resemble' }); +/*#*/ include('tests/load.js'); diff --git a/test/tests/Color.js b/test/tests/Color.js index 3467d23a..5467399d 100644 --- a/test/tests/Color.js +++ b/test/tests/Color.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Color'); +QUnit.module('Color'); test('Set named color', function() { var path = new Path(); @@ -222,6 +222,3 @@ test('Color#divide', function() { var color = new Color(1, 1, 1); equals(color.divide(4), new Color([0.25, 0.25, 0.25])); }); - - - diff --git a/test/tests/CompoundPath.js b/test/tests/CompoundPath.js index fb2c346d..78cc876a 100644 --- a/test/tests/CompoundPath.js +++ b/test/tests/CompoundPath.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Compound Path'); +QUnit.module('Compound Path'); test('moveTo / lineTo', function() { var path = new CompoundPath(); diff --git a/test/tests/Curve.js b/test/tests/Curve.js index f9cd433c..48b16e5b 100644 --- a/test/tests/Curve.js +++ b/test/tests/Curve.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Curve'); +QUnit.module('Curve'); test('Curve#getParameterOf()', function() { // For issue #708: diff --git a/test/tests/CurveLocation.js b/test/tests/CurveLocation.js index d1dc201a..fa3b06c2 100644 --- a/test/tests/CurveLocation.js +++ b/test/tests/CurveLocation.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('CurveLocation'); +QUnit.module('CurveLocation'); test('CurveLocation#offset', function() { var path = new Path(); diff --git a/test/tests/Emitter.js b/test/tests/Emitter.js index ec745a2c..cef93fb9 100644 --- a/test/tests/Emitter.js +++ b/test/tests/Emitter.js @@ -10,10 +10,10 @@ * All rights reserved. */ -module('Emitter'); +QUnit.module('Emitter'); test('on()', function() { - var emitter = new Base(Emitter), + var emitter = new Item(), installed; // fake event type registration emitter._eventTypes = {mousemove: {install: function(){ installed = true;} } }; @@ -37,7 +37,7 @@ test('on()', function() { }); test('off()', function() { - var emitter = new Base(Emitter), + var emitter = new Item(), uninstalled, called = 0, handler = function () {called++}, handler2 = function () {}; @@ -68,7 +68,7 @@ test('off()', function() { }); test('emit()', function() { - var emitter = new Base(Emitter), + var emitter = new Item(), called, handler = function (e) {called = e}; // fake event type registration diff --git a/test/tests/Group.js b/test/tests/Group.js index 2c208e28..fdc72e6a 100644 --- a/test/tests/Group.js +++ b/test/tests/Group.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Group'); +QUnit.module('Group'); test('new Group()', function() { var group = new Group(); diff --git a/test/tests/HitResult.js b/test/tests/HitResult.js index d692e180..52f5d34f 100644 --- a/test/tests/HitResult.js +++ b/test/tests/HitResult.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('HitResult'); +QUnit.module('HitResult'); test('Hit-testing options', function() { var defaultOptions = { diff --git a/test/tests/Item.js b/test/tests/Item.js index 25485509..3e52abaf 100644 --- a/test/tests/Item.js +++ b/test/tests/Item.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Item'); +QUnit.module('Item'); test('copyTo(project)', function() { var project = paper.project; diff --git a/test/tests/Item_Bounds.js b/test/tests/Item_Bounds.js index 0991383c..8e375544 100644 --- a/test/tests/Item_Bounds.js +++ b/test/tests/Item_Bounds.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Item Bounds'); +QUnit.module('Item Bounds'); test('item.bounds caching', function() { var circle = new Path.Circle(new Point(100, 100), 50); @@ -94,5 +94,5 @@ test('text.bounds', function() { var text = new PointText(new Point(50, 100)); text.fillColor = 'black'; text.content = 'This is a test'; - equals(text.bounds, new Rectangle(50, 89.2, 67, 14.4), 'text.bounds', { tolerance: 0.5 }); + equals(text.bounds, new Rectangle(50, 89.2, 67, 14.4), 'text.bounds', { tolerance: 1 }); }); diff --git a/test/tests/Item_Cloning.js b/test/tests/Item_Cloning.js index 9afdd094..c9009546 100644 --- a/test/tests/Item_Cloning.js +++ b/test/tests/Item_Cloning.js @@ -10,6 +10,8 @@ * All rights reserved. */ +QUnit.module('Item Cloning'); + function cloneAndCompare(item) { var copy = item.clone(); equals(function() { diff --git a/test/tests/Item_Getting.js b/test/tests/Item_Getting.js index 7cc2efa5..ec8c8912 100644 --- a/test/tests/Item_Getting.js +++ b/test/tests/Item_Getting.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Getting and Matching Items'); +QUnit.module('Getting and Matching Items'); test('Item#getItems()', function() { var group = new Group([new Path({ selected: true }), new Raster()]); @@ -72,14 +72,14 @@ test('Project#getItems()', function() { className: 'Group' }); equals(function() { - return matches.length == 1 && matches[0] === group + return matches.length == 1 && matches[0] === group; }, true); var matches = paper.project.getItems({ type: 'group' }); equals(function() { - return matches.length == 1 && matches[0] === group + return matches.length == 1 && matches[0] === group; }, true); var raster = new Raster(); @@ -87,7 +87,7 @@ test('Project#getItems()', function() { class: Raster }); equals(function() { - return matches.length == 1 && matches[0] === raster + return matches.length == 1 && matches[0] === raster; }, true); equals(function() { @@ -120,7 +120,7 @@ test('Project#getItems() with compare function', function() { var items = paper.project.getItems({ opacity: function(value) { - return value < 1 + return value < 1; } }); equals(function() { @@ -162,23 +162,26 @@ test('Project#getItems() with color', function() { }); test('Project#getItems() with regex function', function() { - var decoyPath = new Path({ + var layer = paper.project.activeLayer; + var stopPath = new Path({ name: 'stop' }); - var decoyPath2 = new Path({ + var pausePath = new Path({ name: 'pause' }); - var path = new Path({ + var startPath = new Path({ name: 'starting' }); var items = paper.project.getItems({ name: /^start/g }); + + // console.log(paper.project.activeLayer); equals(function() { - return items.length == 1 && items[0] == path; + return items.length == 1 && items[0] == startPath; }, true); equals(function() { diff --git a/test/tests/Item_Order.js b/test/tests/Item_Order.js index af3b2f83..94b06eed 100644 --- a/test/tests/Item_Order.js +++ b/test/tests/Item_Order.js @@ -10,6 +10,8 @@ * All rights reserved. */ +QUnit.module('Item Order'); + test('Item Order', function() { var line = new Path(); line.add([0, 0], [100, 100]); diff --git a/test/tests/JSON.js b/test/tests/JSON.js index d41e9e39..bb93faba 100644 --- a/test/tests/JSON.js +++ b/test/tests/JSON.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('JSON'); +QUnit.module('JSON'); function testExportImportJSON(project) { // Use higher precision than in comparissons, for bounds diff --git a/test/tests/Layer.js b/test/tests/Layer.js index 6b89b4e8..ff1330b5 100644 --- a/test/tests/Layer.js +++ b/test/tests/Layer.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Layer'); +QUnit.module('Layer'); test('previousSibling / nextSibling', function() { var project = paper.project; diff --git a/test/tests/Matrix.js b/test/tests/Matrix.js index 90c61253..9b5871be 100644 --- a/test/tests/Matrix.js +++ b/test/tests/Matrix.js @@ -10,7 +10,8 @@ * All rights reserved. */ -module('Matrix'); +QUnit.module('Matrix'); + test('Decomposition: rotate()', function() { function testAngle(a, ea) { var m = new Matrix().rotate(a), diff --git a/test/tests/Path.js b/test/tests/Path.js index 4e80ea59..b6a034bd 100644 --- a/test/tests/Path.js +++ b/test/tests/Path.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Path'); +QUnit.module('Path'); test('path.join(path)', function() { var path = new Path(); diff --git a/test/tests/PathItem_Contains.js b/test/tests/PathItem_Contains.js index deae04a9..cc9e9de6 100644 --- a/test/tests/PathItem_Contains.js +++ b/test/tests/PathItem_Contains.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('PathItem Contains'); +QUnit.module('PathItem Contains'); function testPoint(item, point, inside, message) { equals(item.contains(point), inside, message || ('The point ' + point diff --git a/test/tests/Path_Boolean.js b/test/tests/Path_Boolean.js index 384e4637..ac40c21c 100644 --- a/test/tests/Path_Boolean.js +++ b/test/tests/Path_Boolean.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Path Boolean Operations'); +QUnit.module('Path Boolean Operations'); function createPath(str) { var ctor = (str.match(/z/gi) || []).length > 1 ? CompoundPath : Path; @@ -30,7 +30,7 @@ function compareBoolean(actual, expected, message, options) { strokeColor: 'black', fillColor: expected.closed ? 'yellow' : null }; - equals(actual, expected, message, options || { rasterize: true }); + equals(actual, expected, message, Base.set({ rasterize: true }, options)); } test('#541', function() { @@ -884,7 +884,8 @@ test('Isolated edge-cases from @iconexperience\'s boolean-test suite', function( closed: true }); compareBoolean(function() { return path1.unite(); }, - 'M428.65987,123.24313c0,0 18.24445,159.97772 20.21157,166.76806c-3.05664,-6.18082 -73.53131,-139.25432 -73.53131,-139.25432z M448.97323,290.23336c0,0 0,0 0,0c0.22704,0.04317 -0.06896,-0.00471 0,0c-0.02659,-0.00506 -0.06063,-0.08007 -0.1018,-0.22217c0.07286,0.14733 0.10741,0.22256 0.1018,0.22217z'); + 'M428.65987,123.24313c0,0 18.24445,159.97772 20.21157,166.76806c-3.05664,-6.18082 -73.53131,-139.25432 -73.53131,-139.25432z M448.97323,290.23336c0,0 0,0 0,0c0.22704,0.04317 -0.06896,-0.00471 0,0c-0.02659,-0.00506 -0.06063,-0.08007 -0.1018,-0.22217c0.07286,0.14733 0.10741,0.22256 0.1018,0.22217z', + null, { tolerance: 1e-3 }); // #784#issuecomment-168605018 var path1 = new CompoundPath(); diff --git a/test/tests/Path_Bounds.js b/test/tests/Path_Bounds.js index b2456387..6a51e9f2 100644 --- a/test/tests/Path_Bounds.js +++ b/test/tests/Path_Bounds.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Path Bounds'); +QUnit.module('Path Bounds'); test('path.bounds', function() { var path = new Path([ diff --git a/test/tests/Path_Curves.js b/test/tests/Path_Curves.js index ec10ff8a..2ead8045 100644 --- a/test/tests/Path_Curves.js +++ b/test/tests/Path_Curves.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Path Curves'); +QUnit.module('Path Curves'); test('path.curves synchronisation', function() { var path = new Path(); diff --git a/test/tests/Path_Drawing_Commands.js b/test/tests/Path_Drawing_Commands.js index f73a9e60..af1c68300 100644 --- a/test/tests/Path_Drawing_Commands.js +++ b/test/tests/Path_Drawing_Commands.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Path Drawing Commands'); +QUnit.module('Path Drawing Commands'); test('path.lineTo(point);', function() { var path = new Path(); diff --git a/test/tests/Path_Intersections.js b/test/tests/Path_Intersections.js index 99f963e3..2d3b7a0d 100644 --- a/test/tests/Path_Intersections.js +++ b/test/tests/Path_Intersections.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Path Intersections'); +QUnit.module('Path Intersections'); function testIntersection(intersections, results) { equals(intersections.length, results.length, 'intersections.length'); diff --git a/test/tests/Path_Length.js b/test/tests/Path_Length.js index 26a2b663..fb77b4f9 100644 --- a/test/tests/Path_Length.js +++ b/test/tests/Path_Length.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Path Length'); +QUnit.module('Path Length'); test('path.length', function() { var path = new Path([ diff --git a/test/tests/Path_Shapes.js b/test/tests/Path_Shapes.js index c56b2930..bcd9abde 100644 --- a/test/tests/Path_Shapes.js +++ b/test/tests/Path_Shapes.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Predefined Path Shapes'); +QUnit.module('Predefined Path Shapes'); test('new Path.Rectangle([50, 50], [100, 100])', function() { var path = new Path.Rectangle([50, 50], [100, 100]); diff --git a/test/tests/PlacedSymbol.js b/test/tests/PlacedSymbol.js index 1aff4fd6..466b7523 100644 --- a/test/tests/PlacedSymbol.js +++ b/test/tests/PlacedSymbol.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Symbol & Placed Symbol'); +QUnit.module('Symbol & Placed Symbol'); test('placedSymbol bounds', function() { var path = new Path.Circle([50, 50], 50); diff --git a/test/tests/Point.js b/test/tests/Point.js index befd61f9..71a4e94d 100644 --- a/test/tests/Point.js +++ b/test/tests/Point.js @@ -10,7 +10,8 @@ * All rights reserved. */ -module('Point'); +QUnit.module('Point'); + test('new Point(10, 20)', function() { var point = new Point(10, 20); equals(point.x, 10, 'point.x'); @@ -44,8 +45,6 @@ test('new Point({ angle: 45, length: 20})', function() { equals(point, new Point(15.32089, 12.85575)); }); -module('Point vector operations'); - test('normalize(length)', function() { var point = new Point(0, 10).normalize(20); equals(point, new Point(0, 20)); diff --git a/test/tests/Project.js b/test/tests/Project.js index ef842e4d..ca970d01 100644 --- a/test/tests/Project.js +++ b/test/tests/Project.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Project'); +QUnit.module('Project'); test('activate()', function() { var project = new Project(); diff --git a/test/tests/Raster.js b/test/tests/Raster.js index 5cdeaa71..05c23d0b 100644 --- a/test/tests/Raster.js +++ b/test/tests/Raster.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Raster'); +QUnit.module('Raster'); test('Create a raster without a source and check its size', function() { var raster = new Raster(); @@ -23,23 +23,34 @@ test('Create a raster without a source and set its size', function() { equals(raster.size, new Size(640, 480), true); }); -asyncTest('Create a raster from a url', function(callback) { +test('Create a raster from a url', function(assert) { + var done = assert.async(); var raster = new Raster('assets/paper-js.gif'); raster.onLoad = function() { equals(raster.size, new Size(146, 146), true); - callback(); + done(); + }; + raster.onError = function(event) { + pushFailure(event.event); + done(); }; }); -asyncTest('Create a raster from a data url', function(callback) { +test('Create a raster from a data url', function(assert) { + var done = assert.async(); var raster = new Raster('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABlJREFUeNpi+s/AwPCfgYmR4f9/hv8AAQYAHiAFAS8Lwy8AAAAASUVORK5CYII='); raster.onLoad = function() { equals(raster.size, new Size(2, 2), true); - callback(); + done(); + }; + raster.onError = function(event) { + pushFailure(event.event); + done(); }; }); -asyncTest('Create a raster from a dom image', function(callback) { +test('Create a raster from a dom image', function(assert) { + var done = assert.async(); var img = document.createElement('img'); img.src = 'assets/paper-js.gif'; document.body.appendChild(img); @@ -48,19 +59,19 @@ asyncTest('Create a raster from a dom image', function(callback) { var raster = new Raster(img); equals(raster.size, new Size(146, 146), true); document.body.removeChild(img); - callback(); + done(); } }); }); -test('Create a raster from a canvas', function(callback) { - var canvas = CanvasProvider.getCanvas(30, 20); +test('Create a raster from a canvas', function() { + var canvas = paper.createCanvas(30, 20); var raster = new Raster(canvas); equals(raster.size, new Size(30, 20), true); - CanvasProvider.release(canvas); }); -asyncTest('Create a raster from a dom id', function(callback) { +test('Create a raster from a dom id', function(assert) { + var done = assert.async(); var img = document.createElement('img'); img.src = 'assets/paper-js.gif'; img.id = 'testimage'; @@ -70,12 +81,13 @@ asyncTest('Create a raster from a dom id', function(callback) { var raster = new Raster('testimage'); equals(raster.size, new Size(146, 146), true); document.body.removeChild(img); - callback(); + done(); } }); }); -asyncTest('Raster#getPixel / setPixel', function(callback) { +test('Raster#getPixel / setPixel', function(assert) { + var done = assert.async(); var raster = new Raster('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABlJREFUeNpi+s/AwPCfgYmR4f9/hv8AAQYAHiAFAS8Lwy8AAAAASUVORK5CYII='); raster.onLoad = function() { equals(raster.getPixel(0, 0), new Color(1, 0, 0, 1)); @@ -86,12 +98,17 @@ asyncTest('Raster#getPixel / setPixel', function(callback) { // Alpha var color = new Color(1, 1, 0, 0.50196); raster.setPixel([0, 0], color); - equals(raster.getPixel([0, 0]), color, 'alpha'); - callback(); + equals(raster.getPixel([0, 0]), color, 'alpha', { tolerance: 1e-2 }); + done(); + }; + raster.onError = function(event) { + pushFailure(event.event); + done(); }; }); -asyncTest('Raster#getSubCanvas', function(callback) { +test('Raster#getSubCanvas', function(assert) { + var done = assert.async(); var raster = new Raster('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABlJREFUeNpi+s/AwPCfgYmR4f9/hv8AAQYAHiAFAS8Lwy8AAAAASUVORK5CYII='); raster.onLoad = function() { var canvas = raster.getSubCanvas(new Rectangle({ @@ -114,7 +131,11 @@ asyncTest('Raster#getSubCanvas', function(callback) { equals(function() { return Base.equals(Array.prototype.slice.call(ctx.getImageData(0, 0, 1, 2).data), expected); }, true); - callback(); + done(); + }; + raster.onError = function(event) { + pushFailure(event.event); + done(); }; }); @@ -132,7 +153,7 @@ test('Raster#getAverageColor(path)', function() { var raster = paper.project.activeLayer.rasterize(72); circle.scale(0.8); equals(raster.getAverageColor(circle), circle.fillColor, null, - { tolerance: 10e-4 }); + { tolerance: 1e-3 }); }); test('Raster#getAverageColor(path) with compound path', function() { @@ -155,5 +176,5 @@ test('Raster#getAverageColor(path) with compound path', function() { path.scale(0.8); path2.scale(1.2); equals(raster.getAverageColor(compoundPath), new Color(1, 0, 0), null, - { tolerance: 10e-4 }); + { tolerance: 1e-3 }); }); diff --git a/test/tests/Rectangle.js b/test/tests/Rectangle.js index 933c8033..fc7e19a5 100644 --- a/test/tests/Rectangle.js +++ b/test/tests/Rectangle.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Rectangle'); +QUnit.module('Rectangle'); test('new Rectangle(new Point(10, 20), new Size(30, 40));', function() { var rect = new Rectangle(new Point(10, 20), new Size(30, 40)); diff --git a/test/tests/SVGExport.js b/test/tests/SVGExport.js index 212e6c39..7de9a373 100644 --- a/test/tests/SVGExport.js +++ b/test/tests/SVGExport.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('SVGExport'); +QUnit.module('SVGExport'); test('Export SVG line', function() { var attrs = { diff --git a/test/tests/SVGImport.js b/test/tests/SVGImport.js index 0f8ea5b3..90f6a5d7 100644 --- a/test/tests/SVGImport.js +++ b/test/tests/SVGImport.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('SVGImport'); +QUnit.module('SVGImport'); test('Import SVG line', function() { var attrs = { @@ -59,7 +59,7 @@ test('Import SVG ellipse', function() { cy: 80, rx: 100, ry: 50 - } + }; var imported = paper.project.importSVG(createSVG('ellipse', attrs), { expandShapes: true }); var path = new Path.Ellipse({ @@ -74,7 +74,7 @@ test('Import SVG circle', function() { cx: 100, cy: 80, r: 50 - } + }; var imported = paper.project.importSVG(createSVG('circle', attrs), { expandShapes: true }); var path = new Path.Circle({ @@ -115,7 +115,8 @@ test('Import SVG polyline', function() { }); test('Import complex CompoundPath and clone', function() { - var svg = createSVG('<path id="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.getElementById('path')); + 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); equals(item.clone(), item, null, { cloned: true }); + return; }); diff --git a/test/tests/Segment.js b/test/tests/Segment.js index 4877d403..24ce21e9 100644 --- a/test/tests/Segment.js +++ b/test/tests/Segment.js @@ -10,7 +10,8 @@ * All rights reserved. */ -module('Segment'); +QUnit.module('Segment'); + test('new Segment(point)', function() { var segment = new Segment(new Point(10, 10)); equals(segment.toString(), '{ point: { x: 10, y: 10 } }'); diff --git a/test/tests/Shape.js b/test/tests/Shape.js index 6ed45ec0..cc5b59fd 100644 --- a/test/tests/Shape.js +++ b/test/tests/Shape.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Shape'); +QUnit.module('Shape'); test('shape.toPath().toShape()', function() { var shapes = { diff --git a/test/tests/Size.js b/test/tests/Size.js index 52f8be18..bb953a7d 100644 --- a/test/tests/Size.js +++ b/test/tests/Size.js @@ -10,7 +10,8 @@ * All rights reserved. */ -module('Size'); +QUnit.module('Size'); + test('new Size(10, 20)', function() { var size = new Size(10, 20); equals(size.toString(), '{ width: 10, height: 20 }'); diff --git a/test/tests/Style.js b/test/tests/Style.js index 779e94c0..d3d53002 100644 --- a/test/tests/Style.js +++ b/test/tests/Style.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('Style'); +QUnit.module('Style'); test('style defaults', function() { var path = new Path(); diff --git a/test/tests/TextItem.js b/test/tests/TextItem.js index 1c76a4d1..69b4f876 100644 --- a/test/tests/TextItem.js +++ b/test/tests/TextItem.js @@ -10,7 +10,7 @@ * All rights reserved. */ -module('TextItem'); +QUnit.module('TextItem'); test('PointText', function() { var text = new PointText({