-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from puneet0191/master
PMM-3410 Moving the component
- Loading branch information
Showing
4 changed files
with
382 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# Bower dependency directory (https://bower.io/) | ||
bower_components | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (https://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules/ | ||
jspm_packages/ | ||
|
||
# TypeScript v1 declaration files | ||
typings/ | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# Yarn Integrity file | ||
.yarn-integrity | ||
|
||
# dotenv environment variables file | ||
.env | ||
|
||
# next.js build output | ||
.next |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# codeceptjs-resemblehelper | ||
Helper for resemble.js, used for Image comparison in Tests with WebdriverIO | ||
|
||
codeceptjs-resemblehelper is [CodeceptJS](https://codecept.io/) helper which can be used to compare screenshots and make the tests fail/pass based on the tolerance allowed | ||
|
||
If two screenshot comparisons have difference greater then the tolerance provided, the test will fail. | ||
|
||
NPM package: https://www.npmjs.com/package/codeceptjs-resemblehelper | ||
|
||
To install the package, just run `npm install codeceptjs-resemblehelper` | ||
|
||
### Configuration | ||
|
||
This helper should be added in codecept.json/codecept.conf.js | ||
|
||
Example: | ||
|
||
```json | ||
{ | ||
"helpers": { | ||
"ResembleHelper" : { | ||
"require": "codeceptjs-resemblehelper", | ||
"screenshotFolder" : "./tests/output/", | ||
"baseFolder": "./tests/screenshots/base/", | ||
"diffFolder": "./tests/screenshots/diff/" | ||
} | ||
} | ||
} | ||
``` | ||
To use the Helper, users must provide the three parameters: | ||
`screenshotFolder` : This will always have the same value as `output` in Codecept configuration, this is the folder where webdriverIO | ||
saves a screenshot when using `I.saveScreenshot` method | ||
|
||
`baseFolder`: 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, | ||
Please remember to create empty folder if you don't have one already | ||
|
||
Usage, these are major functions that help in visual testing | ||
|
||
First one is the `verifyMisMatchPercentage` which basically takes several parameters including tolerance and PrepareBase | ||
```js | ||
/** | ||
* Mis Match Percentage Verification | ||
* @param baseImage Name of the Base Image (Base Image path is taken from Configuration) | ||
* @param screenShotImage Name of the screenshot Image (Screenshot Image Path is taken from Configuration) | ||
* @param diffImageName Name of the Diff Image which will be saved after comparison (Diff Image path is taken from Configuration) | ||
* @param tolerance Tolerance Percentage, default value 10 | ||
* @param prepareBase True | False, depending on the requirement if the base images are missing | ||
* @param selector CSS|XPath|id, If provided locator will be used to fetch Bounding Box of the element and only that element is compared on two images | ||
* @param options Resemble JS Options, read more here: https://github.com/rsmbl/Resemble.js | ||
* @returns {Promise<void>} | ||
*/ | ||
async verifyMisMatchPercentage(baseImage, screenShotImage, diffImageName, tolerance = 10, prepareBase = false, selector, options){ | ||
``` | ||
Second one is the `PrepareBase` which basically prepares all the base images in case they are not available | ||
```js | ||
/** | ||
* Function to prepare Base Images from Screenshots | ||
* | ||
* @param baseImage Name of the Base Image (Base Image path is taken from Configuration) | ||
* @param screenShotImage Name of the screenshot Image (Screenshot Image Path is taken from Configuration) | ||
*/ | ||
prepareBaseImage(baseImage, screenShotImage) {} | ||
``` | ||
Third function is to fetch the boundingBox of an element using selector, this boundingBox is then provided to resemble | ||
so that only that element is compared on the images. | ||
```js | ||
/** | ||
* Function to fetch Bounding box for an element, fetched using selector | ||
* | ||
* @param selector CSS|XPath|ID locators | ||
* @returns {Promise<{boundingBox: {left: *, top: *, right: *, bottom: *}}>} | ||
*/ | ||
async getBoundingBox(selector){ | ||
``` | ||
Users can make use of the boundingBox feature by providing a selector to `verifyMisMatchPercentage` function, it will internally | ||
check if a locator is provided, fetch it's bounding-box and compare only that element on both the images. | ||
Finally to use the helper in your test, you can write something like this: | ||
``` | ||
Feature('to verify monitoried Remote Db instances'); | ||
|
||
Scenario('Open the System Overview Dashboard', async (I, adminPage, loginPage) => { | ||
adminPage.navigateToDashboard("OS", "System Overview"); | ||
adminPage.applyTimer("1m"); | ||
adminPage.viewMetric("CPU Usage"); | ||
I.saveScreenshot("System_Overview_CPU_Usage.png"); | ||
}); | ||
|
||
Scenario('Compare CPU Usage Images', async (I) => { | ||
|
||
// passing TRUE to let the helper know to prepare base images | ||
I.verifyMisMatchPercentage("System_Overview_CPU_Usage.png", "System_Overview_CPU_Usage.png", "DiffImage_SystemOverview_CPU_USAGE_Dashboard", 10, true); | ||
|
||
// passing a selector, to only compare that element on both the images now | ||
I.verifyMisMatchPercentage("System_Overview_CPU_Usage.png", "System_Overview_CPU_Usage.png", "DiffImage_SystemOverview_CPU_USAGE_Panel", 10, false, "//div[@class='panel-container']"); | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
'use strict'; | ||
|
||
// use any assertion library you like | ||
const resemble = require("resemblejs"); | ||
const fs = require('fs'); | ||
let assert = require('assert'); | ||
const mkdirp = require('mkdirp'); | ||
const getDirName = require('path').dirname; | ||
/** | ||
* Resemble.js helper class for CodeceptJS, this allows screen comparison | ||
* @author Puneet Kala | ||
*/ | ||
class ResembleHelper extends Helper { | ||
|
||
constructor(config) { | ||
super(config); | ||
} | ||
|
||
/** | ||
* | ||
* @param image1 | ||
* @param image2 | ||
* @param diffImage | ||
* @param tolerance | ||
* @param options | ||
* @returns {Promise<any | never>} | ||
*/ | ||
async _compareImages (image1, image2, diffImage, tolerance, options) { | ||
image1 = this.config.baseFolder + image1; | ||
image2 = this.config.screenshotFolder + image2; | ||
|
||
return new Promise((resolve, reject) => { | ||
if (options !== undefined) | ||
{ | ||
resemble.outputSettings({ | ||
boundingBox: options.boundingBox | ||
}); | ||
} | ||
resemble.compare(image1, image2, options, (err, data) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(data); | ||
if (data.misMatchPercentage >= tolerance) { | ||
mkdirp(getDirName(this.config.diffFolder + diffImage), function (err) { | ||
if (err) return cb(err); | ||
}); | ||
fs.writeFile(this.config.diffFolder + diffImage + '.png', data.getBuffer(), (err, data) => { | ||
if (err) { | ||
throw new Error(this.err); | ||
} | ||
}); | ||
} | ||
} | ||
}); | ||
}).catch((error) => { | ||
console.log('caught', error.message); | ||
}); | ||
} | ||
|
||
/** | ||
* | ||
* @param image1 | ||
* @param image2 | ||
* @param diffImage | ||
* @param tolerance | ||
* @param options | ||
* @returns {Promise<*>} | ||
*/ | ||
async _fetchMisMatchPercentage (image1, image2, diffImage, tolerance, options) { | ||
var result = this._compareImages(image1, image2, diffImage, tolerance, options); | ||
var data = await Promise.resolve(result); | ||
return data.misMatchPercentage; | ||
} | ||
|
||
/** | ||
* Mis Match Percentage Verification | ||
* @param baseImage Name of the Base Image (Base Image path is taken from Configuration) | ||
* @param screenShotImage Name of the screenshot Image (Screenshot Image Path is taken from Configuration) | ||
* @param diffImageName Name of the Diff Image which will be saved after comparison (Diff Image path is taken from Configuration) | ||
* @param tolerance Tolerance Percentage, default value 10 | ||
* @param prepareBase True | False, depending on the requirement if the base images are missing | ||
* @param selector If set, passed selector will be used to fetch Bouding Box and compared on two images | ||
* @param options Resemble JS Options, read more here: https://github.com/rsmbl/Resemble.js | ||
* @returns {Promise<void>} | ||
*/ | ||
async verifyMisMatchPercentage(baseImage, screenShotImage, diffImageName, tolerance = 10, prepareBase = false, selector, options){ | ||
if (prepareBase) | ||
{ | ||
await this.prepareBaseImage(baseImage, screenShotImage); | ||
} | ||
|
||
if (selector !== undefined) | ||
{ | ||
if (options !== undefined) | ||
{ | ||
options.boundingBox = await this.getBoundingBox(selector); | ||
} | ||
else | ||
{ | ||
var options = {}; | ||
options.boundingBox = await this.getBoundingBox(selector); | ||
} | ||
} | ||
|
||
var misMatch = await this._fetchMisMatchPercentage(baseImage, screenShotImage, diffImageName, tolerance, options); | ||
console.log("MisMatch Percentage Calculated is " + misMatch); | ||
assert.ok(misMatch < tolerance, "MissMatch Percentage " + misMatch); | ||
} | ||
|
||
/** | ||
* Function to prepare Base Images from Screenshots | ||
* | ||
* @param baseImage Name of the Base Image (Base Image path is taken from Configuration) | ||
* @param screenShotImage Name of the screenshot Image (Screenshot Image Path is taken from Configuration) | ||
*/ | ||
async prepareBaseImage(baseImage, screenShotImage) { | ||
var configuration = this.config; | ||
|
||
await this._createDir(configuration.baseFolder + baseImage); | ||
|
||
fs.access(configuration.screenshotFolder + screenShotImage, fs.constants.F_OK | fs.constants.W_OK, (err) => { | ||
if (err) { | ||
console.error( | ||
`${configuration.screenshotFolder + screenShotImage} ${err.code === 'ENOENT' ? 'does not exist' : 'is read-only'}`); | ||
} | ||
}); | ||
|
||
fs.access(configuration.baseFolder, fs.constants.F_OK | fs.constants.W_OK, (err) => { | ||
if (err) { | ||
console.error( | ||
`${configuration.baseFolder} ${err.code === 'ENOENT' ? 'does not exist' : 'is read-only'}`); | ||
} | ||
}); | ||
|
||
fs.copyFileSync(configuration.screenshotFolder + screenShotImage, configuration.baseFolder + baseImage); | ||
} | ||
|
||
/** | ||
* Function to create Directory | ||
* @param directory | ||
* @returns {Promise<void>} | ||
* @private | ||
*/ | ||
async _createDir (directory) { | ||
mkdirp.sync(getDirName(directory)); | ||
} | ||
|
||
/** | ||
* Function to fetch Bounding box for an element, fetched using selector | ||
* | ||
* @param selector CSS|XPath|ID selector | ||
* @returns {Promise<{boundingBox: {left: *, top: *, right: *, bottom: *}}>} | ||
*/ | ||
async getBoundingBox(selector){ | ||
const browser = this._getBrowser(); | ||
|
||
var ele = await browser.element(selector) | ||
.then((res) => { | ||
return res; | ||
}) | ||
.catch((err) => { | ||
// Catch the error because webdriver.io throws if the element could not be found | ||
// Source: https://github.com/webdriverio/webdriverio/blob/master/lib/protocol/element.js | ||
return null; | ||
}); | ||
var location = await browser.getLocation(selector); | ||
var size = await browser.getElementSize(selector); | ||
var bottom = size.height + location.y; | ||
var right = size.width + location.x; | ||
var boundingBox = { | ||
left: location.x, | ||
top: location.y, | ||
right: right, | ||
bottom: bottom | ||
}; | ||
|
||
return boundingBox; | ||
} | ||
|
||
_getBrowser() { | ||
if (this.helpers['WebDriver']) { | ||
return this.helpers['WebDriver'].browser; | ||
} | ||
if (this.helpers['Appium']) { | ||
return this.helpers['Appium'].browser; | ||
} | ||
if (this.helpers['WebDriverIO']) { | ||
return this.helpers['WebDriverIO'].browser; | ||
} | ||
throw new Error('No matching helper found. Supported helpers: WebDriver/Appium/WebDriverIO'); | ||
} | ||
} | ||
|
||
module.exports = ResembleHelper; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "codeceptjs-resemblehelper", | ||
"version": "1.2.1", | ||
"description": "Resemble Js helper for CodeceptJS, with WebdriverIO", | ||
"repository": { | ||
"type": "git", | ||
"url": "[email protected]:Percona-Lab/codeceptjs-resemblehelper.git" | ||
}, | ||
"dependencies": { | ||
"assert": "^1.4.1", | ||
"canvas": "^2.2.0", | ||
"mz": "^2.7.0", | ||
"resemblejs": "^3.0.0", | ||
"mkdirp": "^0.5.1", | ||
"path": "^0.12.7" | ||
}, | ||
"keywords": [ | ||
"codeceptJS", | ||
"codeceptjs", | ||
"resemblejs", | ||
"codeceptjs-resemble" | ||
], | ||
"author": "Puneet Kala <[email protected]>", | ||
"license": "MIT" | ||
} |