Skip to content

Commit

Permalink
add a way to save only reference screenshots (#27)
Browse files Browse the repository at this point in the history
- without checking for already existing screenshots
- without diffing against previous
- overwrite always
  • Loading branch information
zinserjan authored Nov 9, 2016
1 parent afeaf9f commit 95106e3
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ number between 0 and 100 that defines the degree of mismatch to consider two ima

For an example of generating screenshot filesnames dependent on the current test name, have a look at the sample code of [Configuration](#configuration).

#### VisualRegressionCompare.SaveScreenshot
This method is a stripped variant of `VisualRegressionCompare.LocalCompare` to capture only screenshots. This is quite useful when you just want to create reference screenshots and overwrite the previous one without diffing.

You can pass the following options to it's constructor as object:

* **screenshotName** `Function` <br>
pass in a function that returns the filename for the current screenshot. Function receives a *context* object as first parameter with all relevant information about the command.

## Usage
wdio-visual-regression-service enhances an WebdriverIO instance with the following commands:
* `browser.checkViewport([{options}]);`
Expand Down
1 change: 1 addition & 0 deletions src/compare.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as LocalCompare } from './methods/LocalCompare';
export { default as SaveScreenshot } from './methods/SaveScreenshot';
22 changes: 22 additions & 0 deletions src/methods/SaveScreenshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import fs from 'fs-promise';
import BaseCompare from './BaseCompare';
import debug from 'debug';

const log = debug('wdio-visual-regression-service:SaveScreenshot');

export default class SaveScreenshot extends BaseCompare {

constructor(options = {}) {
super();
this.getScreenshotFile = options.screenshotName;
}

async afterScreenshot(context, base64Screenshot) {
const screenshotPath = this.getScreenshotFile(context);

log(`create screenshot file at ${screenshotPath}`);
await fs.outputFile(screenshotPath, base64Screenshot, 'base64');
return this.createResultReport(0, true, true);
}

}
159 changes: 159 additions & 0 deletions test/unit/methods/SaveScreenshot.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import path from 'path';
import { assert } from 'chai';
import { stub } from 'sinon';
import fs from 'fs-promise';

import BaseCompare from '../../../src/methods/BaseCompare';
import SaveScreenshot from '../../../src/methods/SaveScreenshot';

const dirTmp = path.join(process.cwd(), '.tmp');
const dirFixture = path.join(__dirname, '../../fixture/');


async function readAsBase64(file) {
// read binary data
const content = await fs.readFile(file);
// convert binary data to base64 encoded string
return new Buffer(content).toString('base64');
}


function pause(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

describe('SaveScreenshot', function () {
beforeEach(async function () {
await fs.remove(dirTmp);
});

after(async function () {
await fs.remove(dirTmp);
});

it('creates a instance of BaseCompare', async function () {
const saveScreenshot = new SaveScreenshot();
assert.instanceOf(saveScreenshot, BaseCompare, 'SaveScreenshot should extend BaseCompare');
});

context('afterScreenshot', function () {
beforeEach(async function() {
this.referencFile = path.join(dirTmp, 'reference.png');
this.getReferenceFile = stub().returns(this.referencFile);

this.saveScreenshot = new SaveScreenshot({
screenshotName: this.getReferenceFile,
});

this.resultIdentical = {
misMatchPercentage: 0,
isWithinMisMatchTolerance: true,
isSameDimensions: true,
isExactSameImage: true
};
});

it('creates a reference file for the first run', async function () {
const context = {};
const base64Screenshot = await readAsBase64(path.join(dirFixture, 'image/100x100.png'));

const results = await this.saveScreenshot.afterScreenshot(context, base64Screenshot);

// check reference getter
assert.strictEqual(this.getReferenceFile.callCount, 1, 'Reference getter should be called once');
assert.isTrue(this.getReferenceFile.calledWithExactly(context), 'Reference getter should receive context as arg');

// check image results
assert.deepEqual(results, this.resultIdentical, 'Result should be reported');

// check if reference image was created
const existsReference = await fs.exists(this.referencFile);
assert.isTrue(existsReference, 'Reference screenshot should exist');

});

it('updates the reference image when changes are in tolerance', async function () {
const context = {};
const base64Screenshot = await readAsBase64(path.join(dirFixture, 'image/100x100.png'));

// 1st run -> create reference
const resultFirst = await this.saveScreenshot.afterScreenshot(context, base64Screenshot);

// check reference getter
assert.strictEqual(this.getReferenceFile.callCount, 1, 'Reference getter should be called once');
assert.isTrue(this.getReferenceFile.calledWithExactly(context), 'Reference getter should receive context as arg');

// check image results
assert.deepEqual(resultFirst, this.resultIdentical, 'Result should be reported');

// check if reference was created
const existsReference = await fs.exists(this.referencFile);
assert.isTrue(existsReference, 'Captured screenshot should exist');

// check last modified
const statsFirst = await fs.stat(this.referencFile);
assert.isAbove(statsFirst.mtime.getTime(), 0);

// wait to get a different last modified time
await pause(100);

// 2nd run --> update reference image
const resultSecond = await this.saveScreenshot.afterScreenshot(context, base64Screenshot);

// check reference getter
assert.strictEqual(this.getReferenceFile.callCount, 2, 'Reference getter should be called once');
assert.isTrue(this.getReferenceFile.alwaysCalledWithExactly(context), 'Reference getter should receive context as arg');

// check if image is reported as same
assert.deepEqual(resultSecond, this.resultIdentical, 'Result should be reported');

// check if reference was updated
const statsSecond = await fs.stat(this.referencFile);
assert.isAbove(statsSecond.mtime.getTime(), statsFirst.mtime.getTime(), 'File should be modified');
});

it('updates the reference image when changes are not in tolerance', async function () {
const context = {};
const base64ScreenshotReference = await readAsBase64(path.join(dirFixture, 'image/100x100.png'));
const base64ScreenshotNew = await readAsBase64(path.join(dirFixture, 'image/100x100-rotated.png'));

// 1st run -> create reference
const resultFirst = await this.saveScreenshot.afterScreenshot(context, base64ScreenshotReference);

// check reference getter
assert.strictEqual(this.getReferenceFile.callCount, 1, 'Reference getter should be called once');
assert.isTrue(this.getReferenceFile.calledWithExactly(context), 'Reference getter should receive context as arg');

// check image results
assert.deepEqual(resultFirst, this.resultIdentical, 'Result should be reported');

// check if reference was created
const existsReference = await fs.exists(this.referencFile);
assert.isTrue(existsReference, 'Captured screenshot should exist');

// check last modified
const statsFirst = await fs.stat(this.referencFile);
assert.isAbove(statsFirst.mtime.getTime(), 0);

// wait to get a different last modified time
await pause(100);

// 2nd run --> update refernece with diff image
const resultSecond = await this.saveScreenshot.afterScreenshot(context, base64ScreenshotNew);

// check reference getter
assert.strictEqual(this.getReferenceFile.callCount, 2, 'Reference getter should be called once');
assert.isTrue(this.getReferenceFile.alwaysCalledWithExactly(context), 'Reference getter should receive context as arg');

// check if image is reported as same (we don't care about the results here, as we are just overwriting all reference screenshots)
assert.deepEqual(resultSecond, this.resultIdentical, 'Result should be reported');

// check if reference was updated
const statsSecond = await fs.stat(this.referencFile);
assert.isAbove(statsSecond.mtime.getTime(), statsFirst.mtime.getTime(), 'File should be modified');
});

});
});

0 comments on commit 95106e3

Please sign in to comment.