From 259e56bb9e6dec9739f8ee93536a38ccb363dd42 Mon Sep 17 00:00:00 2001 From: Raphael Zimmermann Date: Thu, 4 May 2023 07:41:09 +0200 Subject: [PATCH] Add simple test for compare The tests were initially super slow, as the PNG.sync.write took up to 20 seconds. This seems to be related to jest [1][2]. I therefore added Math to the sandboxInjectedGlobals to speed things up. [1] https://github.com/pngjs/pngjs/issues/96 [2] https://github.com/jestjs/jest/issues/5163#issuecomment-457925591 --- pixelpact/.dockerignore | 1 + pixelpact/package-lock.json | 31 ++++++++++++++++++------- pixelpact/package.json | 8 ++++++- pixelpact/src/compare.js | 8 ++++--- pixelpact/src/compare.test.js | 17 ++++++++++++++ pixelpact/testdata/simple-actual.png | Bin 0 -> 13453 bytes pixelpact/testdata/simple-diff.png | Bin 0 -> 10892 bytes pixelpact/testdata/simple-expected.png | Bin 0 -> 13680 bytes 8 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 pixelpact/.dockerignore create mode 100644 pixelpact/src/compare.test.js create mode 100644 pixelpact/testdata/simple-actual.png create mode 100644 pixelpact/testdata/simple-diff.png create mode 100644 pixelpact/testdata/simple-expected.png diff --git a/pixelpact/.dockerignore b/pixelpact/.dockerignore new file mode 100644 index 0000000..830f581 --- /dev/null +++ b/pixelpact/.dockerignore @@ -0,0 +1 @@ +testdata \ No newline at end of file diff --git a/pixelpact/package-lock.json b/pixelpact/package-lock.json index c2b2657..b902760 100644 --- a/pixelpact/package-lock.json +++ b/pixelpact/package-lock.json @@ -14,7 +14,7 @@ "fastify": "^4.6.0", "pixelmatch": "^5.3.0", "playwright": "^1.26.1", - "pngjs": "^6.0.0" + "pngjs": "^7.0.0" }, "devDependencies": { "jest": "^29.5.0", @@ -3652,6 +3652,14 @@ "pixelmatch": "bin/pixelmatch" } }, + "node_modules/pixelmatch/node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "engines": { + "node": ">=12.13.0" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -3691,11 +3699,11 @@ } }, "node_modules/pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", "engines": { - "node": ">=12.13.0" + "node": ">=14.19.0" } }, "node_modules/prettier": { @@ -7291,6 +7299,13 @@ "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", "requires": { "pngjs": "^6.0.0" + }, + "dependencies": { + "pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==" + } } }, "pkg-dir": { @@ -7318,9 +7333,9 @@ } }, "pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==" }, "prettier": { "version": "2.8.2", diff --git a/pixelpact/package.json b/pixelpact/package.json index 9050355..6478532 100644 --- a/pixelpact/package.json +++ b/pixelpact/package.json @@ -16,11 +16,17 @@ "fastify": "^4.6.0", "pixelmatch": "^5.3.0", "playwright": "^1.26.1", - "pngjs": "^6.0.0" + "pngjs": "^7.0.0" }, "devDependencies": { "jest": "^29.5.0", "prettier": "2.8.2", "supervisor": "^0.12.0" + }, + "jest": { + "sandboxInjectedGlobals": [ + "Math" + ], + "testEnvironment": "node" } } diff --git a/pixelpact/src/compare.js b/pixelpact/src/compare.js index 9c86202..de5abc9 100644 --- a/pixelpact/src/compare.js +++ b/pixelpact/src/compare.js @@ -5,19 +5,21 @@ export async function compare(expected, actual, options = { threshold: 0.01 }) { const expectedPng = PNG.sync.read(expected); const actualPng = PNG.sync.read(actual); const { width, height } = expectedPng; - const diff = new PNG({ width, height }); + const diffPng = new PNG({ width, height }); const numDiffPixels = pixelmatch( expectedPng.data, actualPng.data, - diff.data, + diffPng.data, width, height, options ); + const diff = PNG.sync.write(diffPng); + return { numDiffPixels: numDiffPixels, expected: expected, actual: actual, - diff: PNG.sync.write(diff), + diff: diff, }; } diff --git a/pixelpact/src/compare.test.js b/pixelpact/src/compare.test.js new file mode 100644 index 0000000..58b5a0b --- /dev/null +++ b/pixelpact/src/compare.test.js @@ -0,0 +1,17 @@ +import fs from "fs/promises"; +import { compare } from "./compare.js"; + +describe("compare", () => { + it("returns the number of pixels that differ", async () => { + let expected = await fs.readFile("testdata/simple-expected.png"); + let actual = await fs.readFile("testdata/simple-actual.png"); + let expectedDiff = await fs.readFile("testdata/simple-diff.png"); + + let result = await compare(expected, actual); + + expect(result.numDiffPixels).toBe(152); + expect(result.expected).toStrictEqual(expected); + expect(result.actual).toStrictEqual(actual); + expect(result.diff).toStrictEqual(expectedDiff); + }); +}); diff --git a/pixelpact/testdata/simple-actual.png b/pixelpact/testdata/simple-actual.png new file mode 100644 index 0000000000000000000000000000000000000000..73114e325949ab91ce61920cc7f2a53635c7cbc9 GIT binary patch literal 13453 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 literal 0 HcmV?d00001 diff --git a/pixelpact/testdata/simple-diff.png b/pixelpact/testdata/simple-diff.png new file mode 100644 index 0000000000000000000000000000000000000000..da2cbd05c579c5326b7ed7fdbda43f70c66ac892 GIT binary patch literal 10892 zcmeHN|4$QV7_UR8k*JxA11c*n*GOVAlon-h9XQ8Yhz{K(!7&08Dn%GzXso-*fQ%5P zw(G7$9hQR;7pEei6^56fV5YOx?kXA(Xa^=M+z%8nZRXZd?Vh)H_$RpF?tZzq?_HlS zpXc*=-=}YSWLKtY#d7g-kw~;6BR%b7k!WeHNVHhA>{XZ%{gYNF5^dO>k@jBJ7mGaC z!*yAz)k_9GCHjtjIhQ}yzVC|i_p-bB3F|g7N4~ifvlx9vB&rSeA#><@JBz!EirZe{ zMq9(z@KZTw`N7?7OSn<(8yonk?p=$x(GT?t&s5E1YMB)4no*3(Ids9=u@}IlT!+Bl5V`mXQU3z1h#c5SB5upH_-}>OwEg2HJJi_f~Ro9_YWV86li2WA;qj8Z&t<)tqiH$iOSd%Y`^wlkJ#RR*%d3i_#kL%ctWs{$ zOR-?2f3wmQszCQ}69D6$o5{5k?l>%4EAba}$P=-A{YSQRi|<>q9iA4kMbc7=jw0?T zzU|xM1uw(NzCz`-J<~gsEooUN+8huWM4A=sRs#BTgBqo@lW)+a; zG$b)(t)t9uat;{|G^=N(zeE=Yh3zEUQ6N=kl8gZfmWYUg0`K3Cs9*#0 zGCosRoA*P^mM*IVvLzZwR@tc>k4FO8_#5E{86b)8Kzx$|-V&If6{FX^o$=m#%_*n*0ed-&gGZ3OqWI;Z5FRM9TaN2iJ#;+(yzjy~cBIaAcLY zjnun5z%}H(1Z1CJI@m(oX;w*Q6k^(uDT6>l>mnF2NO4#Uc55Z{C{gY%#9K?GGwfT!HhbIp{f_Oc71-al0Sj1F?2m{&0fH})l0t} z3kd>C7j#1@ z0*`ne2om9d5S9_15W)({10n1p91y}z%M(IqB6uK#MvDVNXd-w*2u%bBgwRCrgb_0`j-OHia<%pLF!H T3-?3+p~?6lGp%#mXJ7vd*<*y^ literal 0 HcmV?d00001 diff --git a/pixelpact/testdata/simple-expected.png b/pixelpact/testdata/simple-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..df5cac09882ba5c37a82ad56af00a738a258943e GIT binary patch literal 13680 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 Gm;V9K1(G8G literal 0 HcmV?d00001