summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Eipert <leipert@gitlab.com>2018-10-30 12:46:44 +0100
committerLukas Eipert <leipert@gitlab.com>2019-01-21 20:48:55 +0100
commit91df6d9ef496bdab9fa3658b8dea131fb0a71c8c (patch)
tree2271ad0d4ad9e693b0c0728ed15b7edb2e8497ad
parentd56b76a52dbb978982c3dedba333523e908b37db (diff)
downloadgitlab-ce-91df6d9ef496bdab9fa3658b8dea131fb0a71c8c.tar.gz
Make favicon tests more fault resistent
It seems like every new version of Chrome renders the favicon canvas differently. This reduces the problems with it by creating a more fault tolerant check, which compares the color values in the pixels and is okay if they are within a certain threshold.
-rw-r--r--package.json1
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js40
-rw-r--r--spec/javascripts/matchers.js39
-rw-r--r--yarn.lock12
4 files changed, 82 insertions, 10 deletions
diff --git a/package.json b/package.json
index 1fd7e53d62c..21431b210cd 100644
--- a/package.json
+++ b/package.json
@@ -161,6 +161,7 @@
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.0-beta.0",
"nodemon": "^1.18.4",
+ "pixelmatch": "^4.0.2",
"prettier": "1.15.3",
"vue-jest": "^3.0.2",
"webpack-dev-server": "^3.1.14",
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index 0dc7e93539a..121c4040212 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -3,6 +3,25 @@ import * as commonUtils from '~/lib/utils/common_utils';
import MockAdapter from 'axios-mock-adapter';
import { faviconDataUrl, overlayDataUrl, faviconWithOverlayDataUrl } from './mock_data';
+const PIXEL_TOLERANCE = 0.2;
+
+/**
+ * Loads a data URL as the src of an
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image|Image}
+ * and resolves to that Image once loaded.
+ *
+ * @param url
+ * @returns {Promise}
+ */
+const urlToImage = url =>
+ new Promise(resolve => {
+ const img = new Image();
+ img.onload = function() {
+ resolve(img);
+ };
+ img.src = url;
+ });
+
describe('common_utils', () => {
describe('parseUrl', () => {
it('returns an anchor tag with url', () => {
@@ -513,8 +532,9 @@ describe('common_utils', () => {
it('should return the favicon with the overlay', done => {
commonUtils
.createOverlayIcon(faviconDataUrl, overlayDataUrl)
- .then(url => {
- expect(url).toEqual(faviconWithOverlayDataUrl);
+ .then(url => Promise.all([urlToImage(url), urlToImage(faviconWithOverlayDataUrl)]))
+ .then(([actual, expected]) => {
+ expect(actual).toImageDiffEqual(expected, PIXEL_TOLERANCE);
done();
})
.catch(done.fail);
@@ -536,10 +556,10 @@ describe('common_utils', () => {
it('should set page favicon to provided favicon overlay', done => {
commonUtils
.setFaviconOverlay(overlayDataUrl)
- .then(() => {
- expect(document.getElementById('favicon').getAttribute('href')).toEqual(
- faviconWithOverlayDataUrl,
- );
+ .then(() => document.getElementById('favicon').getAttribute('href'))
+ .then(url => Promise.all([urlToImage(url), urlToImage(faviconWithOverlayDataUrl)]))
+ .then(([actual, expected]) => {
+ expect(actual).toImageDiffEqual(expected, PIXEL_TOLERANCE);
done();
})
.catch(done.fail);
@@ -582,10 +602,10 @@ describe('common_utils', () => {
commonUtils
.setCiStatusFavicon(BUILD_URL)
- .then(() => {
- const favicon = document.getElementById('favicon');
-
- expect(favicon.getAttribute('href')).toEqual(faviconWithOverlayDataUrl);
+ .then(() => document.getElementById('favicon').getAttribute('href'))
+ .then(url => Promise.all([urlToImage(url), urlToImage(faviconWithOverlayDataUrl)]))
+ .then(([actual, expected]) => {
+ expect(actual).toImageDiffEqual(expected, PIXEL_TOLERANCE);
done();
})
.catch(done.fail);
diff --git a/spec/javascripts/matchers.js b/spec/javascripts/matchers.js
index 0d465510fd3..406527b08a3 100644
--- a/spec/javascripts/matchers.js
+++ b/spec/javascripts/matchers.js
@@ -1,3 +1,5 @@
+import pixelmatch from 'pixelmatch';
+
export default {
toContainText: () => ({
compare(vm, text) {
@@ -54,4 +56,41 @@ export default {
return result;
},
}),
+ toImageDiffEqual: () => {
+ const getImageData = img => {
+ const canvas = document.createElement('canvas');
+ canvas.width = img.width;
+ canvas.height = img.height;
+ canvas.getContext('2d').drawImage(img, 0, 0);
+ return canvas.getContext('2d').getImageData(0, 0, img.width, img.height).data;
+ };
+
+ return {
+ compare(actual, expected, threshold = 0.1) {
+ if (actual.height !== expected.height || actual.width !== expected.width) {
+ return {
+ pass: false,
+ message: `Expected image dimensions (h x w) of ${expected.height}x${expected.width}.
+ Received an image with ${actual.height}x${actual.width}`,
+ };
+ }
+
+ const { width, height } = actual;
+ const differentPixels = pixelmatch(
+ getImageData(actual),
+ getImageData(expected),
+ null,
+ width,
+ height,
+ { threshold },
+ );
+
+ return {
+ pass: differentPixels < 20,
+ message: `${differentPixels} pixels differ more than ${threshold *
+ 100} percent between input and output.`,
+ };
+ },
+ };
+ },
};
diff --git a/yarn.lock b/yarn.lock
index 7b3144fca16..1486f6f8642 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7735,6 +7735,13 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+pixelmatch@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854"
+ integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=
+ dependencies:
+ pngjs "^3.0.0"
+
pkg-dir@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
@@ -7766,6 +7773,11 @@ pn@^1.1.0:
resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==
+pngjs@^3.0.0:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.3.tgz#85173703bde3edac8998757b96e5821d0966a21b"
+ integrity sha512-1n3Z4p3IOxArEs1VRXnZ/RXdfEniAUS9jb68g58FIXMNkPJeZd+Qh4Uq7/e0LVxAQGos1eIUrqrt4FpjdnEd+Q==
+
pofile@^1:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"