-
-
Notifications
You must be signed in to change notification settings - Fork 91
/
helper.js
95 lines (87 loc) · 3.36 KB
/
helper.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
const ospath = require('path')
const fs = require('fs')
const childProcess = require('child_process')
const PNG = require('pngjs').PNG
const pixelmatch = require('pixelmatch')
function outputDir () {
return ospath.join(__dirname, 'output')
}
function outputFile (path) {
return ospath.join(outputDir(), path)
}
function computeImageDifferences (referenceBuffer, actualBuffer, diffFilename) {
const referenceImage = PNG.sync.read(referenceBuffer)
const actualImage = PNG.sync.read(actualBuffer)
const { width, height } = referenceImage
const diff = new PNG({ width, height })
const numDiffPixels = pixelmatch(referenceImage.data, actualImage.data, diff.data, width, height, { threshold: 0.1 })
fs.writeFileSync(diffFilename, PNG.sync.write(diff))
return numDiffPixels
}
function toVisuallyMatch (referenceFilename, actualPath) {
let referencePath
if (ospath.isAbsolute(referenceFilename)) {
referencePath = referenceFilename
} else {
referencePath = ospath.join(__dirname, 'reference', referenceFilename)
}
if (!fs.existsSync(actualPath)) {
return false
}
const imagesOutputDir = outputFile('visual-comparison-workdir')
if (!fs.existsSync(imagesOutputDir)) {
fs.mkdirSync(imagesOutputDir)
}
const actualBasename = ospath.basename(actualPath, '.pdf')
const outputBasename = ospath.join(imagesOutputDir, `${actualBasename}`)
childProcess.execFileSync('pdftocairo', ['-png', actualPath, `${outputBasename}-actual`])
childProcess.execFileSync('pdftocairo', ['-png', referencePath, `${outputBasename}-reference`])
let pixels = 0
const tmpFiles = [actualPath]
const currentFilenameRegexp = new RegExp(`${actualBasename}-(?:actual|reference)-([0-9]+).png`)
const files = fs.readdirSync(imagesOutputDir)
const indexes = new Set(files
.filter((name) => name.match(currentFilenameRegexp))
.map((name) => name.match(currentFilenameRegexp)[1]))
for (const idx of indexes) {
const referencePageFilename = `${outputBasename}-reference-${idx}.png`
const referencePageExists = fs.existsSync(referencePageFilename)
if (referencePageExists) {
tmpFiles.push(referencePageFilename)
}
const actualPageFilename = `${outputBasename}-actual-${idx}.png`
const actualPageExists = fs.existsSync(actualPageFilename)
if (actualPageExists) {
tmpFiles.push(actualPageFilename)
}
const referenceBuffer = fs.readFileSync(referencePageFilename)
const actualBuffer = fs.readFileSync(actualPageFilename)
if (referencePageExists && actualPageExists && referenceBuffer.compare(actualBuffer) === 0) {
continue
}
pixels += computeImageDifferences(referenceBuffer, actualBuffer, `${outputBasename}-diff-${idx}.png`)
}
if (pixels > 0) {
if (typeof process.env.DEBUG === 'undefined') {
tmpFiles.forEach((file) => fs.unlinkSync(file))
}
console.error(`expected ${actualPath} to be visually identical to ${referencePath}`)
return false
} else {
return true
}
}
module.exports = (chai) => {
chai.use(function (_chai, _) {
_chai.Assertion.addMethod('visuallyIdentical', function (reference) {
const obj = this._obj
this.assert(
toVisuallyMatch(reference, obj) === true
, 'expected #{obj} to be visually identical to #{reference}'
, 'expected #{obj} to not be visually identical to #{reference}'
, reference
, obj
)
})
})
}