From 99b684594c76ad4d2cc4d2c24804311d33d0f581 Mon Sep 17 00:00:00 2001 From: Puneet Kala Date: Sat, 16 May 2020 13:35:55 +0530 Subject: [PATCH] Prepare 1.9.1 release (#68) * Issue #60 - Prepare all baselines of test by setting parameter in config (#65) Co-authored-by: Jonatas Kirsch * Update Dependecies, Fix Fatal Error with mkdirp and Mac (#66) * Update Dependencies * Fix Error on Mac * Avoid failing the test for a given threshold but yet generating the difference image (#63) * Option bypassFailure allowing the user to avoid failing the test for a given threshold but yet generating the difference image * Renamed option to skipFailure Co-authored-by: Jonatas Kirsch * feat(testcafe): add the support for testcafe (#62) * passing through output settings to resemble.js (#59) Co-authored-by: JANK Michael * Issue 48 - Add custom assert message (#64) Co-authored-by: Jonatas Kirsch Co-authored-by: Jonatas Kirsch Co-authored-by: Jonatas Kirsch Co-authored-by: Guillaume Camus Co-authored-by: yankydoo Co-authored-by: JANK Michael --- README.md | 43 +++++++++++++++++++++++++++++------ index.js | 63 ++++++++++++++++++++++++++++++++++++---------------- package.json | 14 ++++++------ 3 files changed, 87 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index bc75a17..e7519f9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # codeceptjs-resemblehelper -Helper for resemble.js, used for image comparison in tests with WebdriverIO. +Helper for resemble.js, used for image comparison in tests with WebdriverIO or Puppeteer. codeceptjs-resemblehelper is a [CodeceptJS](https://codecept.io/) helper which can be used to compare screenshots and make the tests fail/pass based on the tolerance allowed. @@ -21,19 +21,25 @@ Example: "ResembleHelper" : { "require": "codeceptjs-resemblehelper", "baseFolder": "./tests/screenshots/base/", - "diffFolder": "./tests/screenshots/diff/" + "diffFolder": "./tests/screenshots/diff/", + "prepareBaseImage": true } } } ``` -To use the Helper, users must provide the two parameters: +To use the Helper, users may provide the parameters: -`baseFolder`: This is the folder for base images, which will be used with screenshot for comparison. +`baseFolder`: Mandatory. This is the folder for base images, which will be used with screenshot for comparison. -`diffFolder`: This will the folder where resemble would try to store the difference image, which can be viewed later. +`diffFolder`: Mandatory. This will the folder where resemble would try to store the difference image, which can be viewed later. -Usage, these are major functions that help in visual testing +`prepareBaseImage`: Optional. When `true` then the system replaces all of the baselines related to the test case(s) you ran. This is equivalent of setting the option `prepareBaseImage: true` in all verifications of the test file. + + +### Usage + +These are the major functions that help in visual testing: First one is the `seeVisualDiff` which basically takes two parameters 1) `baseImage` Name of the base image, this will be the image used for comparison with the screenshot image. It is mandatory to have the same image file names for base and screenshot image. @@ -102,7 +108,7 @@ Scenario('Compare CPU Usage Images', async (I) => { ### Ignored Box You can also exclude part of the image from comparison, by specifying the excluded area in pixels from the top left. Just declare an object and pass it in options as `ignoredBox`: -``` +```js const box = { left: 0, top: 10, @@ -115,6 +121,29 @@ I.seeVisualDiff("image.png", {prepareBaseImage: true, tolerance: 1, ignoredBox: After this, that specific mentioned part will be ignored while comparison. This works for `seeVisualDiff` and `seeVisualDiffForElement`. +### resemble.js Output Settings +You can set further output settings used by resemble.js. Declare an object specifying them and pass it in the options as `outputSettings`: + +```js +const outputSettings = { + ignoreAreasColoredWith: {r: 250, g: 250, b: 250, a: 0}, + // read more here: https://github.com/rsmbl/Resemble.js +}; +I.seeVisualDiff("image.png", {prepareBaseImage: true, tolerance: 1, outputSettings: outputSettings}); +``` + +Refer to the [resemble.js](https://github.com/rsmbl/Resemble.js) documentation for available output settings. + +### Skip Failure +You can avoid the test fails for a given threshold but yet generates the difference image. +Just declare an object and pass it in options as `skipFailure`: +``` +I.seeVisualDiff("image.png", {prepareBaseImage: true, tolerance: 1, skipFailure: true}); +``` +After this, the system generates the difference image but does not fail the test. +This works for `seeVisualDiff` and `seeVisualDiffForElement`. + + ### Allure Reporter Allure reports may also be generated directly from the tool. To do so, add diff --git a/index.js b/index.js index ecb5383..8e0e182 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,7 @@ class ResembleHelper extends Helper { this.baseFolder = this.resolvePath(config.baseFolder); this.diffFolder = this.resolvePath(config.diffFolder); this.screenshotFolder = global.output_dir + "/"; + this.prepareBaseImage = config.prepareBaseImage; } resolvePath(folderPath) { @@ -57,9 +58,13 @@ class ResembleHelper extends Helper { return new Promise((resolve, reject) => { + if (!options.outputSettings) { + options.outputSettings = {}; + } resemble.outputSettings({ boundingBox: options.boundingBox, - ignoredBox: options.ignoredBox + ignoredBox: options.ignoredBox, + ...options.outputSettings, }); this.debug("Tolerance Level Provided " + options.tolerance); @@ -76,9 +81,9 @@ class ResembleHelper extends Helper { } resolve(data); if (data.misMatchPercentage >= tolerance) { - mkdirp(getDirName(this.diffFolder + diffImage), function (error) { - if (error) return cb(error); - }); + if (!fs.existsSync(getDirName(this.diffFolder + diffImage))) { + fs.mkdirSync(getDirName(this.diffFolder + diffImage)); + } fs.writeFileSync(this.diffFolder + diffImage + '.png', data.getBuffer()); const diffImagePath = path.join(process.cwd(), this.diffFolder + diffImage + '.png'); this.debug("Diff Image File Saved to: " + diffImagePath); @@ -125,7 +130,14 @@ class ResembleHelper extends Helper { const el = els[0]; await el.saveScreenshot(this.screenshotFolder + name + '.png'); - } else throw new Error("Method only works with Puppeteer and WebDriver helpers."); + } else if (this.helpers['TestCafe']) { + await helper.waitForVisible(selector); + const els = await helper._locate(selector); + if (!await els.count) throw new Error(`Element ${selector} couldn't be located`); + const { t } = this.helpers['TestCafe']; + + await t.takeElementScreenshot(els, name); + } else throw new Error("Method only works with Puppeteer, WebDriver or TestCafe helpers."); } /** @@ -177,7 +189,7 @@ class ResembleHelper extends Helper { * @param region * @param bucketName * @param baseImage - * @param ifBaseImage - tells if the prepareBaseImage is true or false. If false, then it won't upload the baseImage. + * @param ifBaseImage - tells if the prepareBaseImage is true or false. If false, then it won't upload the baseImage. However, this parameter is not considered if the config file has a prepareBaseImage set to true. * @returns {Promise} */ @@ -296,32 +308,32 @@ class ResembleHelper extends Helper { options.tolerance = 0; } - const awsC = this.config.aws; + if (this.prepareBaseImage) { + options.prepareBaseImage = true; + } + const awsC = this.config.aws; if (awsC !== undefined && options.prepareBaseImage === false) { await this._download(awsC.accessKeyId, awsC.secretAccessKey, awsC.region, awsC.bucketName, baseImage); } - if (options.prepareBaseImage !== undefined && options.prepareBaseImage) { await this._prepareBaseImage(baseImage); } - if (selector) { options.boundingBox = await this._getBoundingBox(selector); } - const misMatch = await this._fetchMisMatchPercentage(baseImage, options); - this._addAttachment(baseImage, misMatch, options.tolerance); - this._addMochaContext(baseImage, misMatch, options.tolerance); - if (awsC !== undefined) { await this._upload(awsC.accessKeyId, awsC.secretAccessKey, awsC.region, awsC.bucketName, baseImage, options.prepareBaseImage) } - this.debug("MisMatch Percentage Calculated is " + misMatch); - assert(misMatch <= options.tolerance, "MissMatch Percentage " + misMatch); + this.debug("MisMatch Percentage Calculated is " + misMatch + " for baseline " + baseImage); + + if (options.skipFailure === false) { + assert(misMatch <= options.tolerance, "Screenshot does not match with the baseline " + baseImage + " when MissMatch Percentage is " + misMatch); + } } /** @@ -369,17 +381,24 @@ class ResembleHelper extends Helper { const helper = this._getHelper(); await helper.waitForVisible(selector); const els = await helper._locate(selector); - if (!els.length) throw new Error(`Element ${selector} couldn't be located`); - const el = els[0]; + + if (this.helpers['TestCafe']) { + if (await els.count != 1) throw new Error(`Element ${selector} couldn't be located or isn't unique on the page`); + } + else { + if (!els.length) throw new Error(`Element ${selector} couldn't be located`); + } let location, size; if (this.helpers['Puppeteer']) { + const el = els[0]; const box = await el.boundingBox(); size = location = box; } if (this.helpers['WebDriver'] || this.helpers['Appium']) { + const el = els[0]; location = await el.getLocation(); size = await el.getSize(); } @@ -388,6 +407,9 @@ class ResembleHelper extends Helper { location = await helper.browser.getLocation(selector); size = await helper.browser.getElementSize(selector); } + if (this.helpers['TestCafe']) { + return await els.boundingClientRect; + } if (!size) { throw new Error("Cannot get element size!"); @@ -421,9 +443,12 @@ class ResembleHelper extends Helper { if (this.helpers['WebDriverIO']) { return this.helpers['WebDriverIO']; } + if (this.helpers['TestCafe']) { + return this.helpers['TestCafe']; + } - throw new Error('No matching helper found. Supported helpers: WebDriver/Appium/Puppeteer'); + throw new Error('No matching helper found. Supported helpers: WebDriver/Appium/Puppeteer/TestCafe'); } } -module.exports = ResembleHelper; \ No newline at end of file +module.exports = ResembleHelper; diff --git a/package.json b/package.json index d203268..86daff0 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,20 @@ { "name": "codeceptjs-resemblehelper", - "version": "1.9.0", + "version": "1.9.1", "description": "Resemble Js helper for CodeceptJS, with Support for Webdriver, Puppeteer & Appium", "repository": { "type": "git", "url": "git@github.com:Percona-Lab/codeceptjs-resemblehelper.git" }, "dependencies": { - "assert": "^1.4.1", - "canvas": "^2.2.0", + "assert": "^1.5.0", + "canvas": "^2.6.1", "mz": "^2.7.0", - "resemblejs": "^3.0.0", - "mkdirp": "^0.5.1", + "resemblejs": "^3.2.4", + "mkdirp": "^1.0.4", "path": "^0.12.7", - "aws-sdk": "^2.476.0", - "image-size": "^0.7.4" + "aws-sdk": "^2.662.0", + "image-size": "^0.8.3" }, "devDependencies": { "allure-commandline": "^2.13.0",