From 5cf43bb0cabf37f4fb21cb80b5f98903a8ba74e0 Mon Sep 17 00:00:00 2001 From: y-kurami Date: Mon, 20 Nov 2017 21:43:37 +0900 Subject: [PATCH 1/5] update dependencies --- package.json | 1 + yarn.lock | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6228f805..f64f21ef 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ }, "dependencies": { "glob": "^7.1.2", + "reg-cli": "0.10.1", "tslint-eslint-rules": "^4.1.1" }, "workspaces": [ diff --git a/yarn.lock b/yarn.lock index 67826521..9e584147 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6964,12 +6964,12 @@ redux@^3.4.0: loose-envify "^1.1.0" symbol-observable "^1.0.3" -reg-cli@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/reg-cli/-/reg-cli-0.9.0.tgz#bfa13fa24fca175a24039c231b676f3593e49a34" +reg-cli@0.10.1, reg-cli@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/reg-cli/-/reg-cli-0.10.1.tgz#109bc4447939529c06eb8ed01d2d0a27153938e7" dependencies: bluebird "^3.5.0" - chalk "^2.0.0" + chalk "^2.1.0" cli-spinner "^0.2.6" cross-spawn "^5.1.0" glob "^7.1.2" @@ -6979,6 +6979,7 @@ reg-cli@^0.9.0: md5-file "^3.1.1" meow "^3.7.0" mustache "^2.3.0" + x-img-diff-js latest regenerate@^1.2.1: version "1.3.3" @@ -8945,6 +8946,10 @@ wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" +x-img-diff-js@latest: + version "0.1.2" + resolved "https://registry.yarnpkg.com/x-img-diff-js/-/x-img-diff-js-0.1.2.tgz#ce33cd55c6b6d3843005a6bda146a47e134943a9" + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" From 154b23c5c914b92bec711525b59d127f1c49599b Mon Sep 17 00:00:00 2001 From: y-kurami Date: Mon, 20 Nov 2017 21:44:03 +0900 Subject: [PATCH 2/5] pass ximgdiff option to reg-cli --- README.md | 13 +++++++ packages/reg-suit-cli/src/commands/prepare.ts | 4 +- packages/reg-suit-core/package.json | 2 +- packages/reg-suit-core/src/processor.ts | 39 +++++++++++++------ packages/reg-suit-interface/src/core.ts | 5 +++ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 95363017..a504db1b 100644 --- a/README.md +++ b/README.md @@ -105,12 +105,17 @@ The `core` section contains reg-suit core setting and the `plugins` section cont actualDir: string; workingDir?: string; // default ".reg" threshold?: number; // default 0 + ximgdiff?: { + invocationType: "none" | "client"; // default "client" + }; } ``` - `actualDir` - *Required* - A directory which contains image files you want to test. - `workingDir` - *Optional* - A directory used by reg-suit puts temporary files. Ordinarily this dir is in listed at `.gitignore`. - `threshold` - *Optional* - Pixel matching threshold. It should be in ranges from `0` to `1`. +- `ximgdiffConfig` - *Optional* - An option to display more detailed difference information to report html. +- `ximgdiffConfig.invocationType` - If set `"cli"`, reg-suit runs x-img-diff-js and detects differences (CLI). If set `"client"`, x-img-diff-js be invoked only with browsers. See [smart differences detection](#smart-difference-detection) section. ### `plugins` Entries of `plugins` section are described as key-value pairs. Each key should be plugin name. If you want configurable value, see README.md under the each plugin package(e.g. [packages/reg-publish-s3-plugin/README.md](https://github.com/reg-viz/reg-suit/tree/master/packages/reg-publish-s3-plugin/README.md)). @@ -137,6 +142,14 @@ reg-suit run # } ``` +### Smart difference detection +If you turn `core.ximgdiff` option on in `regconfig.json`, reg-suit outputs a report with x-img-diff-js. + +[x-img-diff-js](https://reg-viz.github.io/x-img-diff-js) is a difference detection engine which calculates more structural information than naive pixel based comparison result. +reg-suit use this to display which parts of testing image were inserted or moved. + +If `invocationType` is set to `"client"`, x-img-diff-js works on your web browser (It uses Web Assembly and Web Workers, so you need "modern" browser). + ## Run with CI service A working demonstration is [here](https://github.com/reg-viz/reg-simple-demo). diff --git a/packages/reg-suit-cli/src/commands/prepare.ts b/packages/reg-suit-cli/src/commands/prepare.ts index 74d06aaf..4e4f14f1 100644 --- a/packages/reg-suit-cli/src/commands/prepare.ts +++ b/packages/reg-suit-cli/src/commands/prepare.ts @@ -23,7 +23,9 @@ function prepareCore(core: RegSuitCore) { return q; })).then((conf: any) => { // inquirer input returns string, but threshold should be type as number, so cast it. - return { ...conf, threshold: +conf.threshold } as CoreConfig; + return { ...conf, threshold: +conf.threshold, ximgdiff: { + invocationType: "client", + } } as CoreConfig; }) ; } diff --git a/packages/reg-suit-core/package.json b/packages/reg-suit-core/package.json index f2c1c051..e6d8099b 100644 --- a/packages/reg-suit-core/package.json +++ b/packages/reg-suit-core/package.json @@ -20,7 +20,7 @@ "license": "MIT", "dependencies": { "cpx": "^1.5.0", - "reg-cli": "^0.9.0", + "reg-cli": "^0.10.0", "reg-suit-util": "^0.5.9", "rimraf": "^2.6.1" }, diff --git a/packages/reg-suit-core/src/processor.ts b/packages/reg-suit-core/src/processor.ts index 7514cc48..f2115631 100644 --- a/packages/reg-suit-core/src/processor.ts +++ b/packages/reg-suit-core/src/processor.ts @@ -11,6 +11,7 @@ import { ComparisonResult, } from "reg-suit-interface"; import { fsUtil } from "reg-suit-util"; +import { EventEmitter } from "events"; const compare = require("reg-cli"); const rimraf = require("rimraf"); @@ -102,9 +103,10 @@ export class RegProcessor { const { actualDir, expectedDir, diffDir } = this._directoryInfo.workingDirs; const json = path.join(this._directoryInfo.workingDirs.base, "out.json"); const report = path.join(this._directoryInfo.workingDirs.base, "index.html"); + const ximgdiffConf = this._config.ximgdiff || { invocationType: "cli" }; rimraf.sync(actualDir); cpx.copySync(`${this._directoryInfo.userDirs.actualDir}/**/*.{png,jpg,jpeg,tiff,bmp,gif}`, actualDir); - return (compare({ + const emitter = compare({ actualDir, expectedDir, diffDir, @@ -114,17 +116,32 @@ export class RegProcessor { ignoreChange: true, urlPrefix: "", threshold: this._config.threshold, - }) as Promise) - .then(result => { - this._logger.verbose("Comparison result:", result); - return { ...ctx, comparisonResult: result }; - }) - .catch(reason => { - // re-throw notifiers error because it's fatal. - this._logger.error("An error occurs during compare images:"); - if (reason) this._logger.error(reason); - return Promise.reject(reason); + enableCliAdditionalDetection: ximgdiffConf.invocationType === "cli", + enableClientAdditionalDetection: ximgdiffConf.invocationType !== "none", + }) as EventEmitter; + emitter.on("compare", (compareItem: { type: string, path: string }) => { + this._logger.verbose(`${this._logger.colors.red(compareItem.type)}: ${this._logger.colors.magenta(compareItem.path)}`); }); + const comparisonResult = new Promise((resolve, reject) => { + emitter.once("complete", (result: ComparisonResult) => resolve(result)); + emitter.once("error", (reason: any) => reject(reason)); + }); + return comparisonResult + .then(result => { + this._logger.info("Comparison Complete"); + this._logger.info(this._logger.colors.red(" Changed items: " + result.failedItems.length)); + this._logger.info(this._logger.colors.cyan(" New items: " + result.newItems.length)); + this._logger.info(this._logger.colors.redBright(" Deleted items: " + result.deletedItems.length)); + this._logger.info(this._logger.colors.green(" Passed items: " + result.passedItems.length)); + this._logger.verbose("Comparison details:", result); + return { ...ctx, comparisonResult: result }; + }) + .catch(reason => { + // re-throw notifiers error because it's fatal. + this._logger.error("An error occurs during compare images:"); + if (reason) this._logger.error(reason); + return Promise.reject(reason); + }); } getActualKey(ctx: StepResultAfterComparison): Promise { diff --git a/packages/reg-suit-interface/src/core.ts b/packages/reg-suit-interface/src/core.ts index f1328699..2eda7f13 100644 --- a/packages/reg-suit-interface/src/core.ts +++ b/packages/reg-suit-interface/src/core.ts @@ -1,7 +1,12 @@ +export type AdditionalDetectionInvocationType = "none" | "cli" | "client"; + export interface CoreConfig { actualDir: string; workingDir: string; threshold?: number; + ximgdiff?: { + invocationType: AdditionalDetectionInvocationType; + }; } export interface WorkingDirectoryInfo { From 6afc99c92d517b705ce7391117356130079319d1 Mon Sep 17 00:00:00 2001 From: y-kurami Date: Mon, 20 Nov 2017 19:32:39 +0900 Subject: [PATCH 3/5] add .js and .wasm file to publish encode gzip with upload/download --- .../src/s3-publisher-plugin.ts | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/packages/reg-publish-s3-plugin/src/s3-publisher-plugin.ts b/packages/reg-publish-s3-plugin/src/s3-publisher-plugin.ts index cf8e88af..2a060735 100644 --- a/packages/reg-publish-s3-plugin/src/s3-publisher-plugin.ts +++ b/packages/reg-publish-s3-plugin/src/s3-publisher-plugin.ts @@ -1,5 +1,6 @@ import * as fs from "fs"; import * as path from "path"; +import * as zlib from "zlib"; import { S3, config as awsConfig } from "aws-sdk"; import * as glob from "glob"; import * as _ from "lodash"; @@ -25,7 +26,7 @@ export interface FileItem { mimeType: string; } -const DEFAULT_PATTERN = "**/*.{html,png,json,jpeg,jpg,tiff,bmp,gif}"; +const DEFAULT_PATTERN = "**/*.{html,js,wasm,png,json,jpeg,jpg,tiff,bmp,gif}"; const CONCURRENCY_SIZE = 50; export class S3PublisherPlugin implements PublisherPlugin { @@ -184,18 +185,22 @@ export class S3PublisherPlugin implements PublisherPlugin { private _publishItem(key: string, item: FileItem): Promise { return new Promise((resolve, reject) => { - fs.readFile(item.absPath, (err, data) => { + fs.readFile(item.absPath, (err, content) => { if (err) return reject(err); - this._s3client.putObject({ - Bucket: this._pluginConfig.bucketName, - Key: `${key}/${item.path}`, - Body: data, - ContentType: item.mimeType, - ACL: "public-read", - }, (err, x) => { + zlib.gzip(content, (err, data) => { if (err) return reject(err); - this._logger.verbose(`Uploaded from ${item.absPath} to ${key}/${item.path}`,); - return resolve(item); + this._s3client.putObject({ + Bucket: this._pluginConfig.bucketName, + Key: `${key}/${item.path}`, + Body: data, + ContentType: item.mimeType, + ContentEncoding: "gzip", + ACL: "public-read", + }, (err, x) => { + if (err) return reject(err); + this._logger.verbose(`Uploaded from ${item.absPath} to ${key}/${item.path}`,); + return resolve(item); + }); }); }); }); @@ -212,14 +217,26 @@ export class S3PublisherPlugin implements PublisherPlugin { return reject(err); } mkdirp.sync(path.dirname(item.absPath)); - fs.writeFile(item.absPath, x.Body, (err) => { - if (err) { - return reject(err); - } - this._logger.verbose(`Downloaded from ${s3Key} to ${item.absPath}`); - resolve(item); + this._gunzipIfNeed(x, (err, content) => { + fs.writeFile(item.absPath, content, (err) => { + if (err) { + return reject(err); + } + this._logger.verbose(`Downloaded from ${s3Key} to ${item.absPath}`); + resolve(item); + }); }); }); }); } + + private _gunzipIfNeed(output: S3.GetObjectOutput, cb: (err: any, data: Buffer) => any) { + if (output.ContentEncoding === "gzip") { + zlib.gunzip(output.Body as Buffer, (err, content) => { + cb(err, content); + }); + } else { + cb(null, output.Body as Buffer); + } + } } From 398f354fe118e5b6069f01f9e7b7669e67b642b5 Mon Sep 17 00:00:00 2001 From: y-kurami Date: Tue, 21 Nov 2017 13:35:32 +0900 Subject: [PATCH 4/5] fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a504db1b..b51ec19b 100644 --- a/README.md +++ b/README.md @@ -114,8 +114,8 @@ The `core` section contains reg-suit core setting and the `plugins` section cont - `actualDir` - *Required* - A directory which contains image files you want to test. - `workingDir` - *Optional* - A directory used by reg-suit puts temporary files. Ordinarily this dir is in listed at `.gitignore`. - `threshold` - *Optional* - Pixel matching threshold. It should be in ranges from `0` to `1`. -- `ximgdiffConfig` - *Optional* - An option to display more detailed difference information to report html. -- `ximgdiffConfig.invocationType` - If set `"cli"`, reg-suit runs x-img-diff-js and detects differences (CLI). If set `"client"`, x-img-diff-js be invoked only with browsers. See [smart differences detection](#smart-difference-detection) section. +- `ximgdiff` - *Optional* - An option to display more detailed difference information to report html. +- `ximgdiff.invocationType` - If set `"cli"`, reg-suit runs x-img-diff-js and detects differences (CLI). If set `"client"`, x-img-diff-js be invoked only with browsers. See [smart differences detection](#smart-difference-detection) section. ### `plugins` Entries of `plugins` section are described as key-value pairs. Each key should be plugin name. If you want configurable value, see README.md under the each plugin package(e.g. [packages/reg-publish-s3-plugin/README.md](https://github.com/reg-viz/reg-suit/tree/master/packages/reg-publish-s3-plugin/README.md)). From a78e2a636f4e5072af77095dd9388307544fa5e5 Mon Sep 17 00:00:00 2001 From: y-kurami Date: Tue, 21 Nov 2017 13:54:51 +0900 Subject: [PATCH 5/5] update reg-cli version --- package.json | 1 - packages/reg-suit-core/package.json | 2 +- yarn.lock | 14 +++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index f64f21ef..6228f805 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ }, "dependencies": { "glob": "^7.1.2", - "reg-cli": "0.10.1", "tslint-eslint-rules": "^4.1.1" }, "workspaces": [ diff --git a/packages/reg-suit-core/package.json b/packages/reg-suit-core/package.json index e6d8099b..d08640f3 100644 --- a/packages/reg-suit-core/package.json +++ b/packages/reg-suit-core/package.json @@ -20,7 +20,7 @@ "license": "MIT", "dependencies": { "cpx": "^1.5.0", - "reg-cli": "^0.10.0", + "reg-cli": "^0.10.5", "reg-suit-util": "^0.5.9", "rimraf": "^2.6.1" }, diff --git a/yarn.lock b/yarn.lock index 9e584147..d08b6eec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6964,9 +6964,9 @@ redux@^3.4.0: loose-envify "^1.1.0" symbol-observable "^1.0.3" -reg-cli@0.10.1, reg-cli@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/reg-cli/-/reg-cli-0.10.1.tgz#109bc4447939529c06eb8ed01d2d0a27153938e7" +reg-cli@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/reg-cli/-/reg-cli-0.10.5.tgz#a77f83154a4b7de96088b5f462caebe92c3a96ab" dependencies: bluebird "^3.5.0" chalk "^2.1.0" @@ -6979,7 +6979,7 @@ reg-cli@0.10.1, reg-cli@^0.10.0: md5-file "^3.1.1" meow "^3.7.0" mustache "^2.3.0" - x-img-diff-js latest + x-img-diff-js "^0.1.4" regenerate@^1.2.1: version "1.3.3" @@ -8946,9 +8946,9 @@ wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" -x-img-diff-js@latest: - version "0.1.2" - resolved "https://registry.yarnpkg.com/x-img-diff-js/-/x-img-diff-js-0.1.2.tgz#ce33cd55c6b6d3843005a6bda146a47e134943a9" +x-img-diff-js@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/x-img-diff-js/-/x-img-diff-js-0.1.4.tgz#d956bd098d95c8d11788ce35a399cf199e6e428c" xdg-basedir@^3.0.0: version "3.0.0"