siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
241 lines (188 loc) • 8.33 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
!function () {
var fs = require('fs')
var fse = require('fs-extra')
var path = require('path');
var child_process = require('child_process');
Role('Siesta.Launcher.Page.CanWorkWithImagesNodeJS', {
has : {
similarityThreshold : 0.85,
commandInstalledCache : Joose.I.Object
},
methods : {
fileExistsInPath : function (fileName) {
if (this.commandInstalledCache.hasOwnProperty(fileName)) return this.commandInstalledCache[ fileName ]
var envPath = process.env.PATH || ''
var envPaths = envPath.split(/:|;/)
var exists = false
Joose.A.each(envPaths, function (envPath) {
if (fs.existsSync(path.resolve(envPath, fileName))) {
exists = true
return false
}
})
return this.commandInstalledCache[ fileName ] = exists
},
// promised method
runImageMagickCommand : function (command, argv, acceptNonZeroExitCode) {
var me = this
var launcher = this.launcher
return new Promise(function (callback, errback) {
var fileName = command + (launcher.isWindows ? '.exe' : '')
if (!me.fileExistsInPath(fileName)) {
fileName = launcher.binDir + '/binary/imagemagick/' + launcher.getPlatformId() + '/' + fileName
}
child_process.execFile(
fileName,
argv,
{},
function (error, stdout, stderr) {
var output = "STDOUT:\n" + (stdout || '') + "\nSTDERR:\n" + (stderr || '')
var exitCode = error == null ? 0 : error.code
me.debug("IMGCK command: " + command + ', exitCode: ' + exitCode + ', args: ' + argv.join(' ') + ', output: ' + output)
if (error == null || acceptNonZeroExitCode)
callback({
exitCode : exitCode,
stdout : stdout,
stderr : stderr
})
else
errback({
exitCode : exitCode,
stdout : stdout,
stderr : stderr
})
}
)
})
},
// promised method
extentImage : function (fileName, width, height) {
// ssi - siesta screenshot image
var tempFileName = require('tmp').fileSync({ prefix : 'ssi' }).name
return this.runImageMagickCommand('convert', [
'-background', 'none',
'-gravity', 'NorthWest',
'-extent', width + 'x' + height,
fileName,
tempFileName
]).then(function () {
return tempFileName
})
},
// promised method
cropImage : function (fileName, x, y, width, height) {
// ssi - siesta screenshot image
var tempFileName = require('tmp').fileSync({ prefix : 'ssi' }).name
return this.runImageMagickCommand('convert', [
'-extract', width + 'x' + height + '+' + x + '+' + y,
fileName,
tempFileName
]).then(function () {
return tempFileName
})
},
// promised method
getPNGImageSize : function (fileName) {
var PNG = require('pngjs').PNG;
return new Promise(function (resolve, reject) {
var png = new PNG({})
png.on('metadata', function (metadata) {
resolve({
width : metadata.width,
height : metadata.height
})
})
png.on('error', function (error) {
reject(error)
})
fs.createReadStream(fileName).pipe(png)
})
// return this.runImageMagickCommand('identify', [
// fileName,
// '-format', '%w %h'
// ]).then(function (res) {
// var match = /(\d+) (\d+)/.exec(res.stdout)
//
// return {
// width : Number(match[ 1 ]),
// height : Number(match[ 2 ])
// }
// })
},
// promised method
equalizeImageSizes : function (fileName1, fileName2) {
var me = this
return Promise.all([ this.getPNGImageSize(fileName1), this.getPNGImageSize(fileName2) ]).then(function (results) {
var image1 = results[ 0 ]
var image2 = results[ 1 ]
if (image1 instanceof Error || image2 instanceof Error) throw new Error("Something went wrong")
var maxWidth = Math.max(image1.width, image2.width)
var maxHeight = Math.max(image1.height, image2.height)
if (
image1.width != maxWidth || image2.width != maxWidth
|| image1.height != maxHeight || image2.height != maxHeight
) {
return Promise.all([
me.extentImage(fileName1, maxWidth, maxHeight),
me.extentImage(fileName2, maxWidth, maxHeight)
]).then(function (results) {
return {
image1 : results[ 0 ],
image2 : results[ 1 ]
}
})
} else {
return {
image1 : fileName1,
image2 : fileName2
}
}
})
},
// promised method
compareImages : function (image1, image2, diffImage, options) {
var me = this
return this.equalizeImageSizes(image1, image2).then(function (files) {
options = Joose.O.extend(me.dispatcher.screenshotCompareConfig || {
fuzz : '5%',
metric : 'NCC',
compose : 'src-over',
'highlight-color' : '#e500f4'
}, options || {})
var argv = []
Joose.O.each(options, function (value, name) {
if (!/^\$/.test(name)) {
argv.push('-' + name)
argv.push(value)
}
})
argv.push(files.image1, files.image2, diffImage)
return me.runImageMagickCommand('compare', argv, true).then(function (res) {
res.similar = res.exitCode != 2 && Number(res.stderr) > (options.$similarityThreshold || me.similarityThreshold)
res.similarity = Number(res.stderr)
return res
})
})
},
// promised method
scaleImage : function (buffImage, scale) {
throw "Not implemented"
// var scaleTransform = java.awt.geom.AffineTransform.getScaleInstance(scale, scale)
//
// var scaleTransformOp = new java.awt.image.AffineTransformOp(scaleTransform, java.awt.image.AffineTransformOp.TYPE_BICUBIC)
//
// var newWidth = Math.ceil(buffImage.getWidth() * scale)
// var newHeight = Math.ceil(buffImage.getHeight() * scale)
//
// return scaleTransformOp.filter(buffImage, new java.awt.image.BufferedImage(newWidth, newHeight, buffImage.getType()))
}
}
// eof methods
})
}();