diff --git a/.travis.yml b/.travis.yml index acde58d1..262cf0c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,8 @@ jobs: fast_finish: true allow_failures: - env: LAUNCHER=Node CANFAIL=TRUE + - env: LAUNCHER=Firefox CANFAIL=TRUE + - env: LAUNCHER=Chrome CANFAIL=TRUE include: - stage: Linting and Building env: STEP=LINT @@ -70,8 +72,15 @@ jobs: node_js: "4" - stage: Visual Tests node_js: "8" - env: LAUNCHER=Node CANFAIL=TRUE script: npm run test:visual + - stage: Visual Tests + env: LAUNCHER=Chrome CANFAIL=TRUE + install: npm install testem@1.18.4 qunit@2.4.1 + script: npm run build:fast && testem ci --port 8080 -f testem-visual.json -l $LAUNCHER + - stage: Visual Tests + env: LAUNCHER=Firefox CANFAIL=TRUE + install: npm install testem@1.18.4 qunit@2.4.1 + script: npm run build:fast && testem ci --port 8080 -f testem-visual.json -l $LAUNCHER script: 'npm run build:fast && testem ci --port 8080 -f testem.json -l $LAUNCHER' diff --git a/package.json b/package.json index 58b4ca60..0cb9b659 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "export_tests_to_site": "cp test/unit/*.js ../fabricjs.com/test/unit", "all": "npm run build && npm run test && npm run lint && npm run lint_tests && npm run export_dist_to_site && npm run export_tests_to_site", "testem": "testem .", + "testem:visual": "testem --file testem-visual.json", "testem:ci": "testem ci" }, "optionalDependencies": { diff --git a/test-visual.js b/test-visual.js deleted file mode 100644 index b381d942..00000000 --- a/test-visual.js +++ /dev/null @@ -1,28 +0,0 @@ -var testrunner = require('node-qunit'); - -testrunner.options.log.summary = true; -testrunner.options.log.tests = false; -testrunner.options.log.assertions = false; -testrunner.options.log.coverage = false; - -testrunner.options.coverage = true; -testrunner.options.maxBlockDuration = 120000; - -testrunner.run({ - deps: './test/fixtures/test_script.js', - code: './dist/fabric.js', - tests: [ - './test/visual/svg_import.js', - ], - // tests: ['./test/unit/object_clipPath.js',], -}, function(err, report) { - if (err) { - console.log(err); - process.exit(1); - } - if(report.failed > 0){ - process.on('exit', function() { - process.exit(1); - }); - } -}); diff --git a/test/lib/pixelmatch.js b/test/lib/pixelmatch.js new file mode 100644 index 00000000..73706c90 --- /dev/null +++ b/test/lib/pixelmatch.js @@ -0,0 +1,156 @@ +'use strict'; + +function pixelmatch(img1, img2, output, width, height, options) { + + if (!options) options = {}; + + var threshold = options.threshold === undefined ? 0.1 : options.threshold; + + // maximum acceptable square distance between two colors; + // 35215 is the maximum possible value for the YIQ difference metric + var maxDelta = 35215 * threshold * threshold, + diff = 0; + + // compare each pixel of one image against the other one + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + + var pos = (y * width + x) * 4; + + // squared YUV distance between colors at this pixel position + var delta = colorDelta(img1, img2, pos, pos); + + // the color difference is above the threshold + if (delta > maxDelta) { + // check it's a real rendering difference or just anti-aliasing + if (!options.includeAA && (antialiased(img1, x, y, width, height, img2) || + antialiased(img2, x, y, width, height, img1))) { + // one of the pixels is anti-aliasing; draw as yellow and do not count as difference + if (output) drawPixel(output, pos, 255, 255, 0); + + } else { + // found substantial difference not caused by anti-aliasing; draw it as red + if (output) drawPixel(output, pos, 255, 0, 0); + diff++; + } + + } else if (output) { + // pixels are similar; draw background as grayscale image blended with white + var val = blend(grayPixel(img1, pos), 0.1); + drawPixel(output, pos, val, val, val); + } + } + } + + // return the number of different pixels + return diff; +} + +// check if a pixel is likely a part of anti-aliasing; +// based on "Anti-aliased Pixel and Intensity Slope Detector" paper by V. Vysniauskas, 2009 + +function antialiased(img, x1, y1, width, height, img2) { + var x0 = Math.max(x1 - 1, 0), + y0 = Math.max(y1 - 1, 0), + x2 = Math.min(x1 + 1, width - 1), + y2 = Math.min(y1 + 1, height - 1), + pos = (y1 * width + x1) * 4, + zeroes = 0, + positives = 0, + negatives = 0, + min = 0, + max = 0, + minX, minY, maxX, maxY; + + // go through 8 adjacent pixels + for (var x = x0; x <= x2; x++) { + for (var y = y0; y <= y2; y++) { + if (x === x1 && y === y1) continue; + + // brightness delta between the center pixel and adjacent one + var delta = colorDelta(img, img, pos, (y * width + x) * 4, true); + + // count the number of equal, darker and brighter adjacent pixels + if (delta === 0) zeroes++; + else if (delta < 0) negatives++; + else if (delta > 0) positives++; + + // if found more than 2 equal siblings, it's definitely not anti-aliasing + if (zeroes > 2) return false; + + if (!img2) continue; + + // remember the darkest pixel + if (delta < min) { + min = delta; + minX = x; + minY = y; + } + // remember the brightest pixel + if (delta > max) { + max = delta; + maxX = x; + maxY = y; + } + } + } + + if (!img2) return true; + + // if there are no both darker and brighter pixels among siblings, it's not anti-aliasing + if (negatives === 0 || positives === 0) return false; + + // if either the darkest or the brightest pixel has more than 2 equal siblings in both images + // (definitely not anti-aliased), this pixel is anti-aliased + return (!antialiased(img, minX, minY, width, height) && !antialiased(img2, minX, minY, width, height)) || + (!antialiased(img, maxX, maxY, width, height) && !antialiased(img2, maxX, maxY, width, height)); +} + +// calculate color difference according to the paper "Measuring perceived color difference +// using YIQ NTSC transmission color space in mobile applications" by Y. Kotsarenko and F. Ramos + +function colorDelta(img1, img2, k, m, yOnly) { + var a1 = img1[k + 3] / 255, + a2 = img2[m + 3] / 255, + + r1 = blend(img1[k + 0], a1), + g1 = blend(img1[k + 1], a1), + b1 = blend(img1[k + 2], a1), + + r2 = blend(img2[m + 0], a2), + g2 = blend(img2[m + 1], a2), + b2 = blend(img2[m + 2], a2), + + y = rgb2y(r1, g1, b1) - rgb2y(r2, g2, b2); + + if (yOnly) return y; // brightness difference only + + var i = rgb2i(r1, g1, b1) - rgb2i(r2, g2, b2), + q = rgb2q(r1, g1, b1) - rgb2q(r2, g2, b2); + + return 0.5053 * y * y + 0.299 * i * i + 0.1957 * q * q; +} + +function rgb2y(r, g, b) { return r * 0.29889531 + g * 0.58662247 + b * 0.11448223; } +function rgb2i(r, g, b) { return r * 0.59597799 - g * 0.27417610 - b * 0.32180189; } +function rgb2q(r, g, b) { return r * 0.21147017 - g * 0.52261711 + b * 0.31114694; } + +// blend semi-transparent color with white +function blend(c, a) { + return 255 + (c - 255) * a; +} + +function drawPixel(output, pos, r, g, b) { + output[pos + 0] = r; + output[pos + 1] = g; + output[pos + 2] = b; + output[pos + 3] = 255; +} + +function grayPixel(img, i) { + var a = img[i + 3] / 255, + r = blend(img[i + 0], a), + g = blend(img[i + 1], a), + b = blend(img[i + 2], a); + return rgb2y(r, g, b); +} diff --git a/test/visual/assets/svg_linear_1.svg b/test/visual/assets/svg_linear_1.svg new file mode 100644 index 00000000..a05f7482 --- /dev/null +++ b/test/visual/assets/svg_linear_1.svg @@ -0,0 +1,13 @@ + + + + Created with Fabric.js 1.0.12 + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_linear_2.svg b/test/visual/assets/svg_linear_2.svg new file mode 100644 index 00000000..593255da --- /dev/null +++ b/test/visual/assets/svg_linear_2.svg @@ -0,0 +1,11 @@ + + + + Created with Fabric.js 1.0.12 + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_linear_3.svg b/test/visual/assets/svg_linear_3.svg new file mode 100644 index 00000000..909e3a62 --- /dev/null +++ b/test/visual/assets/svg_linear_3.svg @@ -0,0 +1,11 @@ + + + + Created with Fabric.js 1.0.12 + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_linear_4.svg b/test/visual/assets/svg_linear_4.svg new file mode 100644 index 00000000..5f5c263c --- /dev/null +++ b/test/visual/assets/svg_linear_4.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_linear_5.svg b/test/visual/assets/svg_linear_5.svg new file mode 100644 index 00000000..cf6adc40 --- /dev/null +++ b/test/visual/assets/svg_linear_5.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_linear_6.svg b/test/visual/assets/svg_linear_6.svg new file mode 100644 index 00000000..59ba6af7 --- /dev/null +++ b/test/visual/assets/svg_linear_6.svg @@ -0,0 +1,13 @@ + + + + Created with Fabric.js 1.0.12 + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_linear_7.svg b/test/visual/assets/svg_linear_7.svg new file mode 100644 index 00000000..e54be1f9 --- /dev/null +++ b/test/visual/assets/svg_linear_7.svg @@ -0,0 +1,13 @@ + + + + Created with Fabric.js 1.0.12 + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_linear_8.svg b/test/visual/assets/svg_linear_8.svg new file mode 100644 index 00000000..fe21f47f --- /dev/null +++ b/test/visual/assets/svg_linear_8.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_1.svg b/test/visual/assets/svg_radial_1.svg new file mode 100644 index 00000000..0d9990d5 --- /dev/null +++ b/test/visual/assets/svg_radial_1.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_10.svg b/test/visual/assets/svg_radial_10.svg new file mode 100644 index 00000000..479e6c04 --- /dev/null +++ b/test/visual/assets/svg_radial_10.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_11.svg b/test/visual/assets/svg_radial_11.svg new file mode 100644 index 00000000..08d92f6f --- /dev/null +++ b/test/visual/assets/svg_radial_11.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_12.svg b/test/visual/assets/svg_radial_12.svg new file mode 100644 index 00000000..9f6db29f --- /dev/null +++ b/test/visual/assets/svg_radial_12.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_13.svg b/test/visual/assets/svg_radial_13.svg new file mode 100644 index 00000000..86d16a78 --- /dev/null +++ b/test/visual/assets/svg_radial_13.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_2.svg b/test/visual/assets/svg_radial_2.svg new file mode 100644 index 00000000..07169461 --- /dev/null +++ b/test/visual/assets/svg_radial_2.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_3.svg b/test/visual/assets/svg_radial_3.svg new file mode 100644 index 00000000..e08ae361 --- /dev/null +++ b/test/visual/assets/svg_radial_3.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_4.svg b/test/visual/assets/svg_radial_4.svg new file mode 100644 index 00000000..880b24e2 --- /dev/null +++ b/test/visual/assets/svg_radial_4.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_5.svg b/test/visual/assets/svg_radial_5.svg new file mode 100644 index 00000000..1d00f815 --- /dev/null +++ b/test/visual/assets/svg_radial_5.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_6.svg b/test/visual/assets/svg_radial_6.svg new file mode 100644 index 00000000..5de412b5 --- /dev/null +++ b/test/visual/assets/svg_radial_6.svg @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_8.svg b/test/visual/assets/svg_radial_8.svg new file mode 100644 index 00000000..89b43388 --- /dev/null +++ b/test/visual/assets/svg_radial_8.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_radial_9.svg b/test/visual/assets/svg_radial_9.svg new file mode 100644 index 00000000..5220c20e --- /dev/null +++ b/test/visual/assets/svg_radial_9.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/visual/assets/svg_stroke_1.svg b/test/visual/assets/svg_stroke_1.svg index d8dfd763..97a17fd5 100644 --- a/test/visual/assets/svg_stroke_1.svg +++ b/test/visual/assets/svg_stroke_1.svg @@ -7,9 +7,11 @@ Example stroke01 - stroke-width + + - \ No newline at end of file + diff --git a/test/visual/assets/svg_stroke_3.svg b/test/visual/assets/svg_stroke_3.svg index d93a6d49..5537c4e7 100644 --- a/test/visual/assets/svg_stroke_3.svg +++ b/test/visual/assets/svg_stroke_3.svg @@ -7,9 +7,9 @@ Example stroke5 - stroke-dasharray - - - - + + + + - \ No newline at end of file + diff --git a/test/visual/golden/svg_linear_1.png b/test/visual/golden/svg_linear_1.png new file mode 100644 index 00000000..118d004a Binary files /dev/null and b/test/visual/golden/svg_linear_1.png differ diff --git a/test/visual/golden/svg_linear_2.png b/test/visual/golden/svg_linear_2.png new file mode 100644 index 00000000..beb9b8ff Binary files /dev/null and b/test/visual/golden/svg_linear_2.png differ diff --git a/test/visual/golden/svg_linear_3.png b/test/visual/golden/svg_linear_3.png new file mode 100644 index 00000000..9744d7b4 Binary files /dev/null and b/test/visual/golden/svg_linear_3.png differ diff --git a/test/visual/golden/svg_linear_4.png b/test/visual/golden/svg_linear_4.png new file mode 100644 index 00000000..c734f5cf Binary files /dev/null and b/test/visual/golden/svg_linear_4.png differ diff --git a/test/visual/golden/svg_linear_5.png b/test/visual/golden/svg_linear_5.png new file mode 100644 index 00000000..3eee3277 Binary files /dev/null and b/test/visual/golden/svg_linear_5.png differ diff --git a/test/visual/golden/svg_linear_6.png b/test/visual/golden/svg_linear_6.png new file mode 100644 index 00000000..7cb1d7b2 Binary files /dev/null and b/test/visual/golden/svg_linear_6.png differ diff --git a/test/visual/golden/svg_linear_7.png b/test/visual/golden/svg_linear_7.png new file mode 100644 index 00000000..f39c29b4 Binary files /dev/null and b/test/visual/golden/svg_linear_7.png differ diff --git a/test/visual/golden/svg_linear_8.png b/test/visual/golden/svg_linear_8.png new file mode 100644 index 00000000..8f6aec88 Binary files /dev/null and b/test/visual/golden/svg_linear_8.png differ diff --git a/test/visual/golden/svg_radial_1.png b/test/visual/golden/svg_radial_1.png new file mode 100644 index 00000000..609060bc Binary files /dev/null and b/test/visual/golden/svg_radial_1.png differ diff --git a/test/visual/golden/svg_radial_10.png b/test/visual/golden/svg_radial_10.png new file mode 100644 index 00000000..aadda46d Binary files /dev/null and b/test/visual/golden/svg_radial_10.png differ diff --git a/test/visual/golden/svg_radial_11.png b/test/visual/golden/svg_radial_11.png new file mode 100644 index 00000000..9c781d69 Binary files /dev/null and b/test/visual/golden/svg_radial_11.png differ diff --git a/test/visual/golden/svg_radial_12.png b/test/visual/golden/svg_radial_12.png new file mode 100644 index 00000000..70ede6a1 Binary files /dev/null and b/test/visual/golden/svg_radial_12.png differ diff --git a/test/visual/golden/svg_radial_13.png b/test/visual/golden/svg_radial_13.png new file mode 100644 index 00000000..b9f96fda Binary files /dev/null and b/test/visual/golden/svg_radial_13.png differ diff --git a/test/visual/golden/svg_radial_2.png b/test/visual/golden/svg_radial_2.png new file mode 100644 index 00000000..a512d646 Binary files /dev/null and b/test/visual/golden/svg_radial_2.png differ diff --git a/test/visual/golden/svg_radial_3.png b/test/visual/golden/svg_radial_3.png new file mode 100644 index 00000000..329a4bf7 Binary files /dev/null and b/test/visual/golden/svg_radial_3.png differ diff --git a/test/visual/golden/svg_radial_4.png b/test/visual/golden/svg_radial_4.png new file mode 100644 index 00000000..44713fa3 Binary files /dev/null and b/test/visual/golden/svg_radial_4.png differ diff --git a/test/visual/golden/svg_radial_5.png b/test/visual/golden/svg_radial_5.png new file mode 100644 index 00000000..16b2447e Binary files /dev/null and b/test/visual/golden/svg_radial_5.png differ diff --git a/test/visual/golden/svg_radial_6.png b/test/visual/golden/svg_radial_6.png new file mode 100644 index 00000000..edc8fce9 Binary files /dev/null and b/test/visual/golden/svg_radial_6.png differ diff --git a/test/visual/golden/svg_radial_8.png b/test/visual/golden/svg_radial_8.png new file mode 100644 index 00000000..678e351d Binary files /dev/null and b/test/visual/golden/svg_radial_8.png differ diff --git a/test/visual/golden/svg_radial_9.png b/test/visual/golden/svg_radial_9.png new file mode 100644 index 00000000..c426ad5c Binary files /dev/null and b/test/visual/golden/svg_radial_9.png differ diff --git a/test/visual/golden/svg_stroke_1.png b/test/visual/golden/svg_stroke_1.png index b39e1db4..a97f1244 100644 Binary files a/test/visual/golden/svg_stroke_1.png and b/test/visual/golden/svg_stroke_1.png differ diff --git a/test/visual/golden/svg_stroke_2.png b/test/visual/golden/svg_stroke_2.png index d0690218..5f8a8879 100644 Binary files a/test/visual/golden/svg_stroke_2.png and b/test/visual/golden/svg_stroke_2.png differ diff --git a/test/visual/golden/svg_stroke_3.png b/test/visual/golden/svg_stroke_3.png index 4fae19a1..8ac3cb6a 100644 Binary files a/test/visual/golden/svg_stroke_3.png and b/test/visual/golden/svg_stroke_3.png differ diff --git a/test/visual/golden/svg_stroke_4.png b/test/visual/golden/svg_stroke_4.png index e5d8d3ef..15393099 100644 Binary files a/test/visual/golden/svg_stroke_4.png and b/test/visual/golden/svg_stroke_4.png differ diff --git a/test/visual/golden/svg_stroke_5.png b/test/visual/golden/svg_stroke_5.png index cbb85cbc..baa8c82f 100644 Binary files a/test/visual/golden/svg_stroke_5.png and b/test/visual/golden/svg_stroke_5.png differ diff --git a/test/visual/golden/svg_stroke_6.png b/test/visual/golden/svg_stroke_6.png index fef0ef9d..9f363471 100644 Binary files a/test/visual/golden/svg_stroke_6.png and b/test/visual/golden/svg_stroke_6.png differ diff --git a/test/visual/golden/svg_stroke_7.png b/test/visual/golden/svg_stroke_7.png index a41acae8..a95a809a 100644 Binary files a/test/visual/golden/svg_stroke_7.png and b/test/visual/golden/svg_stroke_7.png differ diff --git a/test/visual/golden/svg_stroke_8.png b/test/visual/golden/svg_stroke_8.png index 55ec72ec..d1362615 100644 Binary files a/test/visual/golden/svg_stroke_8.png and b/test/visual/golden/svg_stroke_8.png differ diff --git a/test/visual/goldenMaker.html b/test/visual/goldenMaker.html new file mode 100644 index 00000000..c3df7fb0 --- /dev/null +++ b/test/visual/goldenMaker.html @@ -0,0 +1,46 @@ + + + +
+ + + diff --git a/test/visual/svg_import.js b/test/visual/svg_import.js index 4d18b21c..1cba8af3 100644 --- a/test/visual/svg_import.js +++ b/test/visual/svg_import.js @@ -1,10 +1,13 @@ -(function(global) { - var fs = global.fs; - var pixelmatch = global.pixelmatch; +(function() { + var _pixelMatch = pixelmatch; + if (fabric.isLikelyNode) { + var fs = global.fs; + _pixelMatch = global.pixelmatch; + } var fabricCanvas = this.canvas = new fabric.Canvas(null, {enableRetinaScaling: false, renderOnAddRemove: false}); var pixelmatchOptions = { includeAA: true, - threshold: 0.05, + threshold: 0.1 }; function getAbsolutePath(path) { @@ -17,19 +20,25 @@ return src; } - function getAsset(filename) { + function getAsset(filename, callback) { var finalName = '/assets/' + filename + '.svg'; if (fabric.isLikelyNode) { var path = (__dirname + finalName); - return fs.readFileSync(path, { encoding: 'utf8' }); - } else { - + return fs.readFile(path, { encoding: 'utf8' }, callback); + } + else { + var path = getAbsolutePath('test/visual' + finalName); + fabric.util.request(path, { + onComplete: function(xhr) { + callback(null, xhr.responseText); + } + }); } } function getGolden(filename) { var finalName = '/golden/' + filename + '.png'; - return fabric.isLikelyNode ? (__dirname + finalName) : getAbsolutePath(finalName); + return fabric.isLikelyNode ? (__dirname + finalName) : getAbsolutePath('test/visual' + finalName); } function getGoldenImage(filename, callback) { @@ -58,11 +67,13 @@ var goldenImageData = ctx.getImageData(0, 0, width, height).data; ctx.clearRect(0, 0, width, height); var outputImageData = ctx.getImageData(0, 0, width, height).data; - fabric.loadSVGFromString(getAsset(filename), function(objects) { - fabricCanvas.add.apply(fabricCanvas, objects); - fabricCanvas.renderAll(); - var fabricImageData = fabricCanvas.contextContainer.getImageData(0, 0, width, height).data; - callback(fabricImageData, goldenImageData, width, height, outputImageData); + getAsset(filename, function(err, string) { + fabric.loadSVGFromString(string, function(objects) { + fabricCanvas.add.apply(fabricCanvas, objects); + fabricCanvas.renderAll(); + var fabricImageData = fabricCanvas.contextContainer.getImageData(0, 0, width, height).data; + callback(fabricImageData, goldenImageData, width, height, outputImageData); + }); }); }); } @@ -75,24 +86,48 @@ }); [ - 'svg_stroke_1', - 'svg_stroke_2', - 'svg_stroke_3', - 'svg_stroke_4', - 'svg_stroke_5', - 'svg_stroke_6', - 'svg_stroke_7', - 'svg_stroke_8', - ].forEach(function(filename) { + ['svg_stroke_1', 0], + ['svg_stroke_2', 0], + ['svg_stroke_3', 0], + ['svg_stroke_4', 8], + ['svg_stroke_5', 4], + ['svg_stroke_6', 83], + ['svg_stroke_7', 0], + ['svg_stroke_8', 0], + ['svg_linear_1', 0], + ['svg_linear_2', 0], + ['svg_linear_3', 0], + ['svg_linear_4', 14], + ['svg_linear_5', 8], + ['svg_linear_6', 83], + ['svg_linear_7', 0], + ['svg_linear_8', 0], + ['svg_radial_1', 100], + ['svg_radial_2', 0], + ['svg_radial_3', 0], + ['svg_radial_4', 143], + ['svg_radial_5', 143], + ['svg_radial_6', 8], + ['svg_radial_8', 0], + ['svg_radial_9', 8], + ['svg_radial_10', 12], + ['svg_radial_11', 0], + ['svg_radial_12', 8], + ['svg_radial_13', 4], + ].forEach(function(filenameArray) { + var filename = filenameArray[0]; + var expectedPixels = filenameArray[1]; QUnit.test('Import test for file ' + filename, function(assert) { var done = assert.async(); loadAndPrepareCanvasFor(filename, function(imageDataCanvas, imageDataGolden, width, height, output) { var totalPixels = width * height; var percentage = 0.01; - var differentPixels = pixelmatch(imageDataCanvas, imageDataGolden, output, width, height, pixelmatchOptions); - assert.ok(differentPixels < totalPixels * percentage, 'Image ' + filename + ' has too many different pixels ' + differentPixels + ' representing ' + differentPixels / totalPixels * 100 + '%'); + var differentPixels = _pixelMatch(imageDataCanvas, imageDataGolden, output, width, height, pixelmatchOptions); + var percDiff = differentPixels / totalPixels * 100; + assert.ok(differentPixels < totalPixels * percentage, 'Image ' + filename + ' has too many different pixels ' + differentPixels + ' representing ' + percDiff + '%'); done(); + console.log('Different pixels for', filename, ':', differentPixels, '/', totalPixels, 'expected:', expectedPixels, ' diff:', percDiff.toFixed(3), '%'); }); }); }); -})(global); +})(); diff --git a/testem-visual.json b/testem-visual.json new file mode 100644 index 00000000..a971ca9c --- /dev/null +++ b/testem-visual.json @@ -0,0 +1,34 @@ +{ + "framework": "qunit", + "serve_files": [ + "dist/fabric.js", + "test/lib/pixelmatch.js", + "test/visual/*.js" + ], + "routes": { + "/fixtures": "test/fixtures" + }, + "test_page": "tests.mustache?hidepassed&hideskipped&timeout=60000", + "browser_args": { + "Chrome": [ "--headless", "--disable-gpu", "--remote-debugging-port=9222" ], + "Firefox": [ "--headless" ] + }, + "launch_in_dev": [ + "Chrome", + "Node", + "Firefox" + ], + "launch_in_ci": [ + "Chrome", + "Node", + "Firefox" + ], + "launchers": { + "Node": { + "command": "npm run test:visual", + "protocol": "tap" + } + }, + "timeout": 540, + "parallel": 4 +} diff --git a/tests.mustache b/tests.mustache index dcd2a700..3de2dfc7 100644 --- a/tests.mustache +++ b/tests.mustache @@ -1,7 +1,7 @@ -Test'em +Unit Tests {{#serve_files}}{{/serve_files}}