diff --git a/README.md b/README.md index 464d69a..f84b84e 100644 --- a/README.md +++ b/README.md @@ -113,18 +113,19 @@ Now let's talk about **how to test your application!**. ## Setting up After going through all the steps of the getting started section, you are able to configure robot-eyes to your needs. `robot-eyes.json` is the file that contains the general settings, which are valid for all tests. Here's a list of the available options: -| Property | Description | Default value -| ------------- |-------------| -------------| -| `baseURL` | Link to the main page of your application (shouldn't contain '/'). Example: https://github.com | null | -| `paths.testImages` | relative path where temporary test image files will be saved. Example './test_images/' | './images/test_images' | -| `paths.diffImages` | relative path where temporary diff image files will be saved. Example './diff_images/' | './images/diff_images' | -| `paths.referenceImages` | relative path where the baseline/reference images will be saved. Example './reference_images/' | './images/reference_images' | -| `viewports` | Array of objects containing the width and height that will be tested | `{width: 1920, height: 1080}` | -| `timeout` | Mocha timeout | 40000 | -| `headless` | Chrome browsing mode. Is important to know that, headless and headed generate different images. | true | -| `threshold` | Maximum percentage of different pixels for the test to pass | 0.01 | -| `waitForResourceTimeout` | Maximum time (in ms) to wait for baseURL to be available | 60000 | - +| Property | Description | Default value +| ------------- |-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `baseURL` | Link to the main page of your application (shouldn't contain '/'). Example: https://github.com | null | +| `paths.testImages` | relative path where temporary test image files will be saved. Example './test_images/' | './images/test_images' | +| `paths.diffImages` | relative path where temporary diff image files will be saved. Example './diff_images/' | './images/diff_images' | +| `paths.referenceImages` | relative path where the baseline/reference images will be saved. Example './reference_images/' | './images/reference_images' | +| `viewports` | Array of objects containing the width and height that will be tested | `{width: 1920, height: 1080}` | +| `timeout` | Mocha timeout | 40000 | +| `headless` | Chrome browsing mode. Is important to know that, headless and headed generate different images. | true | +| `threshold` | Maximum percentage of different pixels for the test to pass | 0.01 | +| `waitForResourceTimeout` | Maximum time (in ms) to wait for baseURL to be available | 60000 | +| `resembleOptions`| Config options for [Resemble.js](https://github.com/rsmbl/Resemble.js). This object is passed directly to Resemble's `compareImages` function. You can set the parameters it will use to compare the images, for instance, change the default `ignore: "nothing"` to `ignore: "antialiasing"` to make it more tolerant to small differences. |
| + ### Example robot-eyes.json file ```javascript { diff --git a/compare/compareImages.js b/compare/compareImages.js index 8d8c52e..bd29699 100644 --- a/compare/compareImages.js +++ b/compare/compareImages.js @@ -12,21 +12,14 @@ const compareImages = (config, fileName, viewport) => { const result = await resembleCompare( referenceImage, testImage, - { - ignore: 'nothing', - scaleToSameSize: true, - output: { - largeImageThreshold: 0, - transparency: 0.3 - } - } + config.resembleOptions ) if (result.rawMisMatchPercentage > config.threshold) { await createFolder(`${config.paths.diffImages}/${fileName}`) const diffImagePath = getFilePath(config.paths.diffImages, fileName, viewport) fs.writeFileSync(diffImagePath, result.getBuffer()) - reject(new Error(`Images are not the same. See difference at ${diffImagePath}.`)) + reject(new Error(`Images are not the same (${result.rawMisMatchPercentage}%). See difference at ${diffImagePath}.`)) } else { resolve() } diff --git a/core/getConfig.js b/core/getConfig.js index 81e8347..61ebbe8 100644 --- a/core/getConfig.js +++ b/core/getConfig.js @@ -6,7 +6,7 @@ const getConfig = () => { const args = minimist(process.argv) const configFile = fs.readFileSync(process.cwd() + '/robot-eyes.json') const userConfig = JSON.parse(configFile) - const config = Object.assign({ + const config = mergeDeep({ baseURL: null, paths: { testImages: './images/test_images', @@ -22,7 +22,14 @@ const getConfig = () => { timeout: 40000, headless: true, threshold: 0.01, - waitForResourceTimeout: 60000 + waitForResourceTimeout: 60000, + resembleOptions: { + ignore: 'nothing', + output: { + largeImageThreshold: 0, + transparency: 0.3 + } + } }, userConfig) Object.keys(config.paths) .forEach(v => { @@ -36,4 +43,19 @@ const getConfig = () => { return config } +const mergeDeep = (obj1, obj2) => { + const result = {}; + Object.assign(result, obj1); + + for (const prop of Object.keys(obj2)) { + if (result.hasOwnProperty(prop) && typeof obj2[prop] === 'object' && !Array.isArray(obj2[prop])) { + result[prop] = mergeDeep(result[prop], obj2[prop]); + } else { + result[prop] = obj2[prop]; + } + } + + return result; +} + module.exports = getConfig diff --git a/core/tests/getConfig.spec.js b/core/tests/getConfig.spec.js index 5b1adf2..9ee45ea 100644 --- a/core/tests/getConfig.spec.js +++ b/core/tests/getConfig.spec.js @@ -137,6 +137,48 @@ describe('getConfig', function () { compareResolvedAndUnresolvedPath(config.paths.referenceImages, paths.referenceImages) }) + it('default resemble options', function () { + createEmptyConfigFile() + + const config = getConfig() + + expect(config.resembleOptions.ignore).to.eql('nothing') + expect(config.resembleOptions.output.largeImageThreshold).to.eql(0) + expect(config.resembleOptions.output.transparency).to.eql(0.3) + }) + + it('default resemble options should be overrided by config file', function () { + const resembleOptions = { + ignore: 'antialiasing', + output: { + largeImageThreshold: 1000, + transparency: 0.5 + } + } + createConfigFile({ resembleOptions }) + + const config = getConfig() + + expect(config.resembleOptions).to.eql(resembleOptions) + }) + + it('should override only the specified resemble options preserving defaults', function () { + const resembleOptions = { + output: { + transparency: 0.5, + errorType: "movement" + } + } + createConfigFile({ resembleOptions }) + + const config = getConfig() + + expect(config.resembleOptions.ignore).to.eql('nothing') + expect(config.resembleOptions.output.largeImageThreshold).to.eql(0) + expect(config.resembleOptions.output.transparency).to.eql(0.5) + expect(config.resembleOptions.output.errorType).to.eql("movement") + }) + const compareResolvedAndUnresolvedPath = (resolved, unresolved) => { expect(resolved).to.satisfy(path => path.endsWith(unresolved.replace('.', ''))) } diff --git a/integrationTests/robot-eyes.json b/integrationTests/robot-eyes.json index 0066ab2..7c5393c 100644 --- a/integrationTests/robot-eyes.json +++ b/integrationTests/robot-eyes.json @@ -13,5 +13,9 @@ "testImages": "./images/test", "diffImages": "./images/diff", "referenceImages": "./images/reference" + }, + "threshold": 0.02, + "resembleOptions": { + "ignore": ["antialiasing"] } }{
ignore: 'nothing',
output: {
largeImageThreshold: 0,
transparency: 0.3
}
}