Fix bug
This commit is contained in:
parent
38d5cb9ed0
commit
c5ae2b607a
|
@ -1,2 +1,4 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
examples
|
||||||
run.sh
|
run.sh
|
||||||
|
screenshot*
|
||||||
|
|
58
index.js
58
index.js
|
@ -3,10 +3,43 @@
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const process = require('process');
|
const process = require('process');
|
||||||
const puppeteer = require('puppeteer');
|
const puppeteer = require('puppeteer');
|
||||||
|
const quality = require('./quality.js');
|
||||||
|
|
||||||
// Size of the rendering of the web page
|
// Size of the rendering of the web page
|
||||||
const size = { width: 1280, height: 720 };
|
const size = { width: 1280, height: 720 };
|
||||||
|
|
||||||
|
// Logging helper
|
||||||
|
function write(stream, chunk, encoding='utf8') {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const errListener = (err) => {
|
||||||
|
stream.removeListener('error', errListener);
|
||||||
|
reject(err);
|
||||||
|
};
|
||||||
|
stream.addListener('error', errListener);
|
||||||
|
const callback = () => {
|
||||||
|
stream.removeListener('error', errListener);
|
||||||
|
resolve(undefined);
|
||||||
|
};
|
||||||
|
stream.write(chunk, encoding, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function print(data) {
|
||||||
|
await write(process.stdout, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function eprint(data) {
|
||||||
|
await write(process.stderr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function println(data) {
|
||||||
|
await write(process.stdout, data + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function eprintln(data) {
|
||||||
|
await write(process.stderr, data + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
|
||||||
if (process.argv[2] === undefined) {
|
if (process.argv[2] === undefined) {
|
||||||
|
@ -57,9 +90,17 @@ async function main() {
|
||||||
let file2 = await fs.readFile(__dirname + '/' + 'screenshot2.png');
|
let file2 = await fs.readFile(__dirname + '/' + 'screenshot2.png');
|
||||||
let filesAreSame = file1.map((x, i) => x === file2[i]).reduce((a, b) => a && b, true);
|
let filesAreSame = file1.map((x, i) => x === file2[i]).reduce((a, b) => a && b, true);
|
||||||
|
|
||||||
// Crash if they're different
|
|
||||||
if (!filesAreSame) {
|
if (!filesAreSame) {
|
||||||
throw new Error("Page edit changed the layout");
|
// Check psnr
|
||||||
|
let psnr = await quality.psnr(__dirname + '/' + 'screenshot1.png', __dirname + '/' + 'screenshot2.png');
|
||||||
|
|
||||||
|
// Crash if they're different
|
||||||
|
if (psnr > 70) {
|
||||||
|
eprintln("\x1b[33mWarning: " + process.argv[2] + " produced slight diff: psnr = " + psnr + '\x1b[0m');
|
||||||
|
} else {
|
||||||
|
await eprintln("\x1b[31mError: age edit changed the layout: psnr = " + psnr + '\x1b[0m');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyse the root and output the result
|
// Analyse the root and output the result
|
||||||
|
@ -82,14 +123,19 @@ async function addSpan(element) {
|
||||||
for (let elt of elts) {
|
for (let elt of elts) {
|
||||||
let value = await elt.evaluate(el => el.textContent, element);
|
let value = await elt.evaluate(el => el.textContent, element);
|
||||||
if (value !== "") {
|
if (value !== "") {
|
||||||
await elt.evaluate(el => {
|
let html = await elt.evaluate(el => {
|
||||||
if (el.innerHTML.indexOf('<li>') === -1) {
|
if (el.innerHTML.indexOf('<li>') === -1 && el.innerHTML.indexOf('<p>') === -1) {
|
||||||
|
let tmp = el.innerHTML;
|
||||||
el.innerHTML = '<span class="sized-span">' + el.innerHTML + '</span>';
|
el.innerHTML = '<span class="sized-span">' + el.innerHTML + '</span>';
|
||||||
return true;
|
return [tmp, el.innerHTML];
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (html !== null) {
|
||||||
|
await eprintln("\x1b[36mReplaced " + JSON.stringify(html[0]) + " by " + JSON.stringify(html[1]) + '\x1b[0m');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"pngjs": "^7.0.0",
|
||||||
"puppeteer": "^19.7.1"
|
"puppeteer": "^19.7.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -48,9 +49,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "18.13.0",
|
"version": "18.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz",
|
||||||
"integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==",
|
"integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/yauzl": {
|
"node_modules/@types/yauzl": {
|
||||||
|
@ -540,6 +541,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||||
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="
|
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/pngjs": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/progress": {
|
"node_modules/progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"pngjs": "^7.0.0",
|
||||||
"puppeteer": "^19.7.1"
|
"puppeteer": "^19.7.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
const { PNG } = require('pngjs');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// Fixed from https://www.npmjs.com/package/png-quality
|
||||||
|
|
||||||
|
async function loadPngFile(pathOrBuffer) {
|
||||||
|
// Load buffer of path
|
||||||
|
if (!(pathOrBuffer instanceof Buffer)) {
|
||||||
|
pathOrBuffer = await new Promise((resolve, reject) => {
|
||||||
|
fs.readFile(pathOrBuffer, (err, data) => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(data)
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load PNG from buffer
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
const png = new PNG()
|
||||||
|
png.parse(pathOrBuffer, err => {
|
||||||
|
if (err) return reject(err)
|
||||||
|
resolve(png)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mse(png1, png2) {
|
||||||
|
const pngs = [png1, png2];
|
||||||
|
for (let i in pngs) {
|
||||||
|
if (!(pngs[i] instanceof PNG)) pngs[i] = await loadPngFile(pngs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pngs[0].width !== pngs[1].width || pngs[0].height !== pngs[1].height) {
|
||||||
|
throw new Error('Width or height does not equal')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pngs[0].data.length !== pngs[1].data.length) {
|
||||||
|
throw new Error('Data buffer length does not equal')
|
||||||
|
}
|
||||||
|
|
||||||
|
const square = (a) => a * a,
|
||||||
|
channelIndex = [0, 1, 2],
|
||||||
|
channelMax = 255 * 255,
|
||||||
|
area = pngs[0].width * pngs[1].height
|
||||||
|
|
||||||
|
let mse = 0
|
||||||
|
for (let i = 0; i < pngs[0].data.length; i += 4) {
|
||||||
|
const rgbas = pngs.map(png => png.data.slice(i, i + 4))
|
||||||
|
const rgbs = rgbas.map(rgba => channelIndex.map(i => rgba[i] * rgba[3]))
|
||||||
|
channelIndex.forEach(i => mse += square(rgbs[0][i] - rgbs[1][i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return mse / 3.0 / (channelMax * channelMax) / area
|
||||||
|
}
|
||||||
|
|
||||||
|
async function psnr(png1, png2) {
|
||||||
|
const m = await mse(png1, png2)
|
||||||
|
return 10 * Math.log10(1 / m)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
loadPngFile,
|
||||||
|
mse,
|
||||||
|
psnr,
|
||||||
|
};
|
Loading…
Reference in New Issue